├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── docs └── Rain.png ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── client ├── java │ └── sh │ │ └── talonfloof │ │ └── enhancedweather │ │ ├── CloudChunk.java │ │ ├── CloudRenderManager.java │ │ ├── EWDebugHud.java │ │ ├── EnhancedWeatherClient.java │ │ ├── events │ │ └── TornadoClient.java │ │ ├── mixin │ │ └── client │ │ │ ├── BackgroundRendererMixin.java │ │ │ ├── CherryLeavesParticleMixin.java │ │ │ ├── MixinParticle.java │ │ │ ├── ParticleManagerMixin.java │ │ │ ├── WorldClientMixin.java │ │ │ └── WorldRendererMixin.java │ │ ├── network │ │ ├── ScreenOpenClient.java │ │ ├── SuppressAlert.java │ │ ├── UpdateConditionsClient.java │ │ └── UpdateEventClient.java │ │ ├── particle │ │ ├── HailParticle.java │ │ ├── RainParticle.java │ │ ├── SnowParticle.java │ │ └── TornadoParticle.java │ │ └── screen │ │ └── RadarScreen.java └── resources │ └── enhancedweather.client.mixins.json └── main ├── java └── sh │ └── talonfloof │ └── enhancedweather │ ├── EnhancedWeather.java │ ├── WindManager.java │ ├── api │ └── EnhancedWeatherAPI.java │ ├── block │ ├── BlockRegistry.java │ ├── RadarBlock.java │ └── RadarBlockEntity.java │ ├── commands │ └── SpawnTornadoCommand.java │ ├── config │ └── EnhancedWeatherConfigModel.java │ ├── events │ ├── Tornado.java │ └── WeatherEvent.java │ ├── mixin │ ├── FireBlockMixin.java │ ├── LightningEntityMixin.java │ ├── ServerWorldMixin.java │ └── WorldMixin.java │ ├── network │ ├── ScreenOpen.java │ ├── SuppressAlertServer.java │ ├── UpdateConditions.java │ └── UpdateEvent.java │ └── util │ ├── FastNoiseLite.java │ ├── ImageSampler.java │ └── MathUtil.java └── resources ├── assets ├── enhancedweather │ ├── blockstates │ │ └── radar.json │ ├── icon.png │ ├── lang │ │ └── en_us.json │ ├── models │ │ ├── block │ │ │ ├── radar.json │ │ │ └── radar_light.json │ │ └── item │ │ │ └── radar.json │ ├── particles │ │ ├── hail.json │ │ ├── rain.json │ │ ├── snow.json │ │ └── tornado.json │ ├── sounds.json │ ├── sounds │ │ └── radar_beep.ogg │ └── textures │ │ ├── block │ │ ├── radar.png │ │ ├── radar.png.mcmeta │ │ ├── radar_light.png │ │ └── radar_light.png.mcmeta │ │ ├── cloud │ │ └── cloud.png │ │ ├── gui │ │ ├── radar.png │ │ ├── radar_alert_light.png │ │ └── tornado_symbol.png │ │ ├── particle │ │ ├── hail.png │ │ ├── rain.png │ │ ├── snow1.png │ │ ├── snow2.png │ │ ├── snow3.png │ │ ├── snow4.png │ │ ├── tornado.png │ │ └── tornado2.png │ │ └── sky │ │ └── rainbow.png └── minecraft │ ├── sounds.json │ └── sounds │ └── ambient │ └── weather │ ├── rain1.ogg │ ├── rain2.ogg │ ├── rain3.ogg │ ├── rain4.ogg │ ├── thunder1.ogg │ ├── thunder2.ogg │ ├── thunder3.ogg │ ├── thunder4.ogg │ ├── thunder5.ogg │ └── thunder6.ogg ├── data ├── enhancedweather │ ├── clouds │ │ ├── large_details.png │ │ ├── main_shape.png │ │ ├── rain_density.png │ │ ├── rain_fronts.png │ │ ├── thunderstorms.png │ │ └── variation.png │ ├── loot_tables │ │ └── blocks │ │ │ └── radar.json │ └── recipes │ │ └── radar.json └── minecraft │ └── tags │ └── blocks │ └── mineable │ └── pickaxe.json ├── enhancedweather.accesswidener ├── enhancedweather.mixins.json └── fabric.mod.json /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # Automatically build the project and run any configured tests for every push 2 | # and submitted pull request. This can help catch issues that only occur on 3 | # certain platforms or Java versions, and provides a first line of defence 4 | # against bad commits. 5 | 6 | name: build 7 | on: [pull_request, push] 8 | 9 | jobs: 10 | build: 11 | strategy: 12 | matrix: 13 | # Use these Java versions 14 | java: [ 15 | 17, # Current Java LTS & minimum supported by Minecraft 16 | ] 17 | # and run on both Linux and Windows 18 | os: [ubuntu-22.04, windows-2022] 19 | runs-on: ${{ matrix.os }} 20 | steps: 21 | - name: checkout repository 22 | uses: actions/checkout@v3 23 | - name: validate gradle wrapper 24 | uses: gradle/wrapper-validation-action@v1 25 | - name: setup jdk ${{ matrix.java }} 26 | uses: actions/setup-java@v3 27 | with: 28 | java-version: ${{ matrix.java }} 29 | distribution: 'microsoft' 30 | - name: make gradle wrapper executable 31 | if: ${{ runner.os != 'Windows' }} 32 | run: chmod +x ./gradlew 33 | - name: build 34 | run: ./gradlew build 35 | - name: capture build artifacts 36 | if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS 37 | uses: actions/upload-artifact@v3 38 | with: 39 | name: Artifacts 40 | path: build/libs/ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | .gradle/ 4 | build/ 5 | out/ 6 | classes/ 7 | 8 | # eclipse 9 | 10 | *.launch 11 | 12 | # idea 13 | 14 | .idea/ 15 | *.iml 16 | *.ipr 17 | *.iws 18 | 19 | # vscode 20 | 21 | .settings/ 22 | .vscode/ 23 | bin/ 24 | .classpath 25 | .project 26 | 27 | # macos 28 | 29 | *.DS_Store 30 | 31 | # fabric 32 | 33 | run/ 34 | 35 | # java 36 | 37 | hs_err_*.log 38 | replay_*.log 39 | *.hprof 40 | *.jfr 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2023 TalonFox 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!IMPORTANT] 2 | > EnhancedWeather is discontinued, however a spirtiual successor, [Deluge](https://github.com/TalonFloof/Deluge) is currently in development and is planned to be released in the (not too distant) future. 3 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'fabric-loom' version '1.5-SNAPSHOT' 3 | id 'maven-publish' 4 | } 5 | 6 | version = project.mod_version 7 | group = project.maven_group 8 | 9 | base { 10 | archivesName = project.archives_base_name 11 | } 12 | 13 | repositories { 14 | // Add repositories to retrieve artifacts from in here. 15 | // You should only use this when depending on other mods because 16 | // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. 17 | // See https://docs.gradle.org/current/userguide/declaring_repositories.html 18 | // for more information about repositories. 19 | maven { url "https://maven.shedaniel.me/" } 20 | maven { url "https://maven.terraformersmc.com/" } 21 | maven { url 'https://maven.wispforest.io' } 22 | } 23 | 24 | loom { 25 | splitEnvironmentSourceSets() 26 | 27 | accessWidenerPath = file("src/main/resources/enhancedweather.accesswidener") 28 | 29 | mods { 30 | "enhancedweather" { 31 | sourceSet sourceSets.main 32 | sourceSet sourceSets.client 33 | } 34 | } 35 | 36 | } 37 | 38 | dependencies { 39 | // To change the versions see the gradle.properties file 40 | minecraft "com.mojang:minecraft:${project.minecraft_version}" 41 | mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" 42 | modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" 43 | 44 | // Fabric API. This is technically optional, but you probably want it anyway. 45 | modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" 46 | 47 | // Uncomment the following line to enable the deprecated Fabric API modules. 48 | // These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time. 49 | 50 | modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" 51 | 52 | implementation include("blue.endless:jankson:1.2.3") 53 | 54 | 55 | modImplementation "io.wispforest:owo-lib:${project.owo_version}" 56 | annotationProcessor "io.wispforest:owo-lib:${project.owo_version}" 57 | include "io.wispforest:owo-sentinel:${project.owo_version}" 58 | modImplementation("com.terraformersmc:modmenu:${project.modmenu_version}") { 59 | exclude(group: "net.fabricmc.fabric-api") 60 | } 61 | } 62 | 63 | processResources { 64 | inputs.property "version", project.version 65 | 66 | filesMatching("fabric.mod.json") { 67 | expand "version": project.version 68 | } 69 | } 70 | 71 | tasks.withType(JavaCompile).configureEach { 72 | it.options.release = 17 73 | } 74 | 75 | java { 76 | // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task 77 | // if it is present. 78 | // If you remove this line, sources will not be generated. 79 | withSourcesJar() 80 | 81 | sourceCompatibility = JavaVersion.VERSION_17 82 | targetCompatibility = JavaVersion.VERSION_17 83 | } 84 | 85 | jar { 86 | from("LICENSE") { 87 | rename { "${it}_${project.base.archivesName.get()}"} 88 | } 89 | } 90 | 91 | // configure the maven publication 92 | publishing { 93 | publications { 94 | mavenJava(MavenPublication) { 95 | from components.java 96 | } 97 | } 98 | 99 | // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. 100 | repositories { 101 | // Add repositories to publish to here. 102 | // Notice: This block does NOT have the same function as the block in the top level. 103 | // The repositories here will be used for publishing your artifact, not for 104 | // retrieving dependencies. 105 | } 106 | } -------------------------------------------------------------------------------- /docs/Rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/docs/Rain.png -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | org.gradle.parallel=true 4 | 5 | # Fabric Properties 6 | # check these on https://fabricmc.net/develop 7 | minecraft_version=1.20.4 8 | yarn_mappings=1.20.4+build.3 9 | loader_version=0.15.7 10 | 11 | # Mod Properties 12 | mod_version=1.1-Alpha2 13 | maven_group=sh.talonfloof.enhancedweather 14 | archives_base_name=enhancedweather 15 | 16 | # Dependencies 17 | fabric_version=0.96.4+1.20.4 18 | 19 | modmenu_version=9.0.0 20 | owo_version=0.12.5+1.20.3 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Use the maximum available, or set MAX_FD != -1 to use that value. 89 | MAX_FD=maximum 90 | 91 | warn () { 92 | echo "$*" 93 | } >&2 94 | 95 | die () { 96 | echo 97 | echo "$*" 98 | echo 99 | exit 1 100 | } >&2 101 | 102 | # OS specific support (must be 'true' or 'false'). 103 | cygwin=false 104 | msys=false 105 | darwin=false 106 | nonstop=false 107 | case "$( uname )" in #( 108 | CYGWIN* ) cygwin=true ;; #( 109 | Darwin* ) darwin=true ;; #( 110 | MSYS* | MINGW* ) msys=true ;; #( 111 | NONSTOP* ) nonstop=true ;; 112 | esac 113 | 114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 115 | 116 | 117 | # Determine the Java command to use to start the JVM. 118 | if [ -n "$JAVA_HOME" ] ; then 119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 120 | # IBM's JDK on AIX uses strange locations for the executables 121 | JAVACMD=$JAVA_HOME/jre/sh/java 122 | else 123 | JAVACMD=$JAVA_HOME/bin/java 124 | fi 125 | if [ ! -x "$JAVACMD" ] ; then 126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 127 | 128 | Please set the JAVA_HOME variable in your environment to match the 129 | location of your Java installation." 130 | fi 131 | else 132 | JAVACMD=java 133 | if ! command -v java >/dev/null 2>&1 134 | then 135 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 136 | 137 | Please set the JAVA_HOME variable in your environment to match the 138 | location of your Java installation." 139 | fi 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | 201 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 202 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 203 | 204 | # Collect all arguments for the java command; 205 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 206 | # shell script including quotes and variable substitutions, so put them in 207 | # double quotes to make sure that they get re-expanded; and 208 | # * put everything else in single quotes, so that it's not re-expanded. 209 | 210 | set -- \ 211 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 212 | -classpath "$CLASSPATH" \ 213 | org.gradle.wrapper.GradleWrapperMain \ 214 | "$@" 215 | 216 | # Stop when "xargs" is not available. 217 | if ! command -v xargs >/dev/null 2>&1 218 | then 219 | die "xargs is not available" 220 | fi 221 | 222 | # Use "xargs" to parse quoted args. 223 | # 224 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 225 | # 226 | # In Bash we could simply go: 227 | # 228 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 229 | # set -- "${ARGS[@]}" "$@" 230 | # 231 | # but POSIX shell has neither arrays nor command substitution, so instead we 232 | # post-process each arg (as a line of input to sed) to backslash-escape any 233 | # character that might be a shell metacharacter, then use eval to reverse 234 | # that process (while maintaining the separation between arguments), and wrap 235 | # the whole thing up as a single "set" statement. 236 | # 237 | # This will of course break if any of these variables contains a newline or 238 | # an unmatched quote. 239 | # 240 | 241 | eval "set -- $( 242 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 243 | xargs -n1 | 244 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 245 | tr '\n' ' ' 246 | )" '"$@"' 247 | 248 | exec "$JAVACMD" "$@" 249 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/CloudChunk.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather; 2 | 3 | import net.minecraft.client.gl.VertexBuffer; 4 | import net.minecraft.client.render.BufferBuilder; 5 | import net.minecraft.client.render.Tessellator; 6 | import net.minecraft.client.render.VertexFormat; 7 | import net.minecraft.client.render.VertexFormats; 8 | import net.minecraft.util.math.MathHelper; 9 | import net.minecraft.util.math.noise.PerlinNoiseSampler; 10 | import net.minecraft.util.math.random.Random; 11 | import sh.talonfloof.enhancedweather.api.EnhancedWeatherAPI; 12 | 13 | public class CloudChunk { 14 | private static final float[] RAIN_COLOR = new float[] { 66F / 255F, 74F / 255F, 74F / 255F }; 15 | private static final float[] DARK_COLOR = new float[] { 150F / 255F, 176F / 255F, 211F / 255F }; 16 | private static final Random RANDOM = Random.create(); 17 | private static final PerlinNoiseSampler NOISE = new PerlinNoiseSampler(Random.create()); 18 | 19 | private boolean needUpdate = true; 20 | private short[] data; 21 | public VertexBuffer buf = new VertexBuffer(VertexBuffer.Usage.STATIC); 22 | private int chunkX = Integer.MIN_VALUE; 23 | private int chunkZ = Integer.MIN_VALUE; 24 | public int posX; 25 | public int posZ; 26 | public CloudChunk() { 27 | data = new short[8192]; 28 | for(int i=0; i < 8192; i++) { 29 | data[i] = (short)0xF000; 30 | } 31 | } 32 | public void setRenderPosition(int chunkX, int chunkZ) { 33 | this.posX = chunkX << 5; 34 | this.posZ = chunkZ << 5; 35 | } 36 | public void setValue(int x, int y, int z, short val) { 37 | data[(x & 0xF) | ((y & 0x1F) << 4) | ((z & 0xF) << 9)] = val; 38 | } 39 | 40 | public void checkIfNeedUpdate(int x, int z) { 41 | needUpdate = chunkX != x || chunkZ != z; 42 | } 43 | public boolean needUpdate() { 44 | return needUpdate; 45 | } 46 | public void forceUpdate() { 47 | this.chunkX = Integer.MIN_VALUE; 48 | this.chunkZ = Integer.MIN_VALUE; 49 | needUpdate = true; 50 | } 51 | 52 | public void generateChunk(int oX, int oZ) { 53 | this.chunkX = oX; 54 | this.chunkZ = oZ; 55 | 56 | for(int i=0; i < 8192; i++) { 57 | byte x = (byte) (i & 15); 58 | byte y = (byte) ((i >> 4) & 31); 59 | byte z = (byte) (i >> 9); 60 | float rainFront = EnhancedWeatherAPI.sampleFront((oX*16)+x, (oZ*16)+z, 0.2); 61 | float density = EnhancedWeatherAPI.getCloudDensity(((oX*16)+x) << 1, y << 1, ((oZ*16)+z) << 1, rainFront); 62 | float coverage = EnhancedWeatherAPI.getCoverage(rainFront); 63 | if (density < coverage) { 64 | data[i] = (short)0xF000; 65 | } else { 66 | data[i] = (short) ((byte) (rainFront * 15) << 4); 67 | byte thunder = (byte)(EnhancedWeatherAPI.sampleThunderstorm(0, x, z, 0.1) * rainFront * 15); 68 | data[i] |= (short) (thunder << 8); 69 | } 70 | } 71 | for(int i=0; i < 8192; i++) { 72 | if (data[i] == (short)0xf000) continue; 73 | byte x = (byte) (i & 15); 74 | byte y = (byte) ((i >> 4) & 31); 75 | byte z = (byte) (i >> 9); 76 | byte light = 15; 77 | for (byte j = 1; j < 15; j++) { 78 | if (y + j > 31) break; 79 | int index2 = i + (j << 4); 80 | if (data[index2] != (short)0xf000) light--; 81 | } 82 | 83 | if (light > 0) { 84 | light = (byte) (light - NOISE.sample((float) (x * 0.3), (float)(y * 0.3), (float)(z * 0.3))); 85 | } 86 | data[i] |= light; 87 | } 88 | } 89 | 90 | public void tessellate() { 91 | BufferBuilder bufferBuilder = Tessellator.getInstance().getBuffer(); 92 | bufferBuilder.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR); 93 | for(int i=0; i < 8192; i++) { 94 | if(data[i] == (short)0xF000) continue; 95 | byte x = (byte) (i & 15); 96 | byte y = (byte) ((i >> 4) & 31); 97 | byte z = (byte) (i >> 9); 98 | boolean canDraw = x == 0 || x == 15 || y == 0 || y == 31 || z == 0 || z == 15; 99 | if (!canDraw) { 100 | canDraw = data[i + 1] == (short)0xF000 || data[i - 1] == (short)0xF000 || 101 | data[i + 16] == (short)0xF000 || data[i - 16] == (short)0xF000 || 102 | data[i + 512] == (short)0xF000 || data[i - 512] == (short)0xF000; 103 | } 104 | if (!canDraw) continue; 105 | RANDOM.setSeed(MathHelper.hashCode(x,y,z)); 106 | float deltaBrightness = ((data[i] & 15) + RANDOM.nextFloat()) / 15F; 107 | float deltaWetness = (((data[i] >> 4) & 15) + RANDOM.nextFloat()) / 15F; 108 | float deltaThunder = ((data[i] >> 8) & 15) / 15F; 109 | deltaBrightness *= (1 - deltaWetness) * 0.5F + 0.5F; 110 | deltaThunder = MathHelper.lerp(deltaThunder, 1F, 0.5F); 111 | float r = MathHelper.lerp(deltaWetness, RAIN_COLOR[0], DARK_COLOR[0]); 112 | float g = MathHelper.lerp(deltaWetness, RAIN_COLOR[1], DARK_COLOR[1]); 113 | float b = MathHelper.lerp(deltaWetness, RAIN_COLOR[2], DARK_COLOR[2]); 114 | r = MathHelper.clamp(MathHelper.lerp(deltaBrightness, r, 1F) * deltaThunder,0,1); 115 | g = MathHelper.clamp(MathHelper.lerp(deltaBrightness, g, 1F) * deltaThunder,0,1); 116 | b = MathHelper.clamp(MathHelper.lerp(deltaBrightness, b, 1F) * deltaThunder,0,1); 117 | CloudRenderManager.makeCloudBlock(bufferBuilder,x,y,z,r,g,b,data,i,chunkX,chunkZ); 118 | } 119 | buf.bind(); 120 | buf.upload(bufferBuilder.end()); 121 | VertexBuffer.unbind(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/CloudRenderManager.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.client.gl.ShaderProgram; 6 | import net.minecraft.client.gl.VertexBuffer; 7 | import net.minecraft.client.render.*; 8 | import net.minecraft.client.util.math.MatrixStack; 9 | import net.minecraft.util.Identifier; 10 | import net.minecraft.util.math.MathHelper; 11 | import net.minecraft.util.math.Vec2f; 12 | import net.minecraft.util.math.Vec3d; 13 | import org.joml.Matrix4f; 14 | import sh.talonfloof.enhancedweather.api.EnhancedWeatherAPI; 15 | import sh.talonfloof.enhancedweather.config.EnhancedWeatherConfig; 16 | import sh.talonfloof.enhancedweather.util.MathUtil; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import static sh.talonfloof.enhancedweather.EnhancedWeatherClient.windX; 22 | import static sh.talonfloof.enhancedweather.EnhancedWeatherClient.windZ; 23 | 24 | public class CloudRenderManager { 25 | private static final Identifier CLOUD = new Identifier("enhancedweather","textures/cloud/cloud.png"); 26 | private static int RADIUS = 0; 27 | private static int SIDE = 0; 28 | private static int CAPACITY = 0; 29 | private static CloudChunk[] chunks = new CloudChunk[CAPACITY]; 30 | private static Vec2f[] offsets; 31 | private static long lastTick = 0; 32 | public static double prevCloudX = 0; 33 | public static double prevCloudZ = 0; 34 | public static double cloudX = 0; 35 | public static double cloudZ = 0; 36 | private static Vec3d lastCloudColor = new Vec3d(1,1,1); 37 | 38 | private static int getIndex(int x, int y) { 39 | return (int)MathUtil.wrap(x, SIDE) * SIDE + (int)MathUtil.wrap(y, SIDE); 40 | } 41 | 42 | public static void forceUpdate() { 43 | if(RADIUS == EnhancedWeather.CONFIG.Client_CloudRadius()) { 44 | for (int i = 0; i < chunks.length; i++) { 45 | chunks[i].forceUpdate(); 46 | } 47 | } 48 | } 49 | 50 | public static boolean hasCloudBlock(int x, int y, int z) { 51 | float rainFront = EnhancedWeatherAPI.sampleFront(x, z, 0.2); 52 | float density = EnhancedWeatherAPI.getCloudDensity(x << 1, y << 1, z << 1, rainFront); 53 | float coverage = EnhancedWeatherAPI.getCoverage(rainFront); 54 | return !(density < coverage); 55 | } 56 | 57 | public static void render(MatrixStack matrices, Matrix4f projectionMatrix, float tickDelta, double cameraX, double cameraY, double cameraZ) { 58 | MinecraftClient client = MinecraftClient.getInstance(); 59 | if(RADIUS != EnhancedWeather.CONFIG.Client_CloudRadius()) { 60 | RADIUS = EnhancedWeather.CONFIG.Client_CloudRadius(); 61 | SIDE = RADIUS * 2 + 1; 62 | CAPACITY = SIDE * SIDE; 63 | chunks = new CloudChunk[CAPACITY]; 64 | for (int i = 0; i < chunks.length; i++) { 65 | chunks[i] = new CloudChunk(); 66 | } 67 | List offset = new ArrayList<>(CAPACITY); 68 | for (int x = -RADIUS; x <= RADIUS; x++) { 69 | for (int z = -RADIUS; z <= RADIUS; z++) { 70 | offset.add(new Vec2f(x, z)); 71 | } 72 | } 73 | offset.sort((v1, v2) -> { 74 | int d1 = (int)v1.x * (int)v1.x + (int)v1.y * (int)v1.y; 75 | int d2 = (int)v2.x * (int)v2.x + (int)v2.y * (int)v2.y; 76 | return Integer.compare(d1, d2); 77 | }); 78 | offsets = offset.toArray(Vec2f[]::new); 79 | } 80 | RenderSystem.disableCull(); 81 | RenderSystem.enableBlend(); 82 | RenderSystem.enableDepthTest(); 83 | RenderSystem.depthMask(true); 84 | RenderSystem.setShader(GameRenderer::getPositionTexColorNormalProgram); 85 | RenderSystem.setShaderTexture(0,CLOUD); 86 | //BackgroundRenderer.clearFog(); 87 | ShaderProgram shaderProgram = RenderSystem.getShader(); 88 | // Cloud Chunk Rendering 89 | double eX = cameraX; 90 | double eZ = cameraZ; 91 | int centerX = MathHelper.floor((cameraX)/32); 92 | int centerZ = MathHelper.floor((cameraZ)/32); 93 | int worldXOffset = (int)(cloudX/32); 94 | int worldZOffset = (int)(cloudZ/32); 95 | long currentTick = client.world.getTime(); 96 | if(lastTick != currentTick) { 97 | prevCloudX = cloudX; 98 | prevCloudZ = cloudZ; 99 | Vec2f normal = new Vec2f(windX,windZ).normalize(); 100 | cloudX += ((normal.x*Math.min(1.5,EnhancedWeatherClient.windSpeed/25F)) * 0.002) * 32; 101 | cloudZ += ((normal.y*Math.min(1.5,EnhancedWeatherClient.windSpeed/25F)) * 0.002) * 32; 102 | lastTick = currentTick; 103 | } 104 | eX -= MathHelper.lerp(tickDelta,prevCloudX,cloudX) % 32; 105 | eZ -= MathHelper.lerp(tickDelta,prevCloudZ,cloudZ) % 32; 106 | if(RADIUS == EnhancedWeather.CONFIG.Client_CloudRadius()) { 107 | boolean canUpdate = true; 108 | Vec3d curColor = client.world.getCloudsColor(tickDelta); 109 | for (Vec2f offset : offsets) { 110 | int cx = centerX + (int)offset.x; 111 | int cz = centerZ + (int)offset.y; 112 | int movedX = cx - worldXOffset; 113 | int movedZ = cz - worldZOffset; 114 | CloudChunk chunk = chunks[getIndex(movedX, movedZ)]; 115 | chunk.setRenderPosition(cx, cz); 116 | chunk.checkIfNeedUpdate(movedX, movedZ); 117 | if (canUpdate && chunk.needUpdate()) { 118 | chunk.generateChunk(movedX, movedZ); 119 | chunk.tessellate(); 120 | canUpdate = false; 121 | } 122 | if (!chunk.needUpdate()) { 123 | matrices.push(); 124 | matrices.translate(chunk.posX - eX, client.world.getDimensionEffects().getCloudsHeight() - cameraY, chunk.posZ - eZ); 125 | matrices.scale(2,2,2); 126 | chunk.buf.bind(); 127 | RenderSystem.setShaderColor((float)curColor.x,(float)curColor.y,(float)curColor.z,1.0F); 128 | chunk.buf.draw(matrices.peek().getPositionMatrix(), projectionMatrix, shaderProgram); 129 | RenderSystem.setShaderColor(1.0F,1.0F,1.0F,1.0F); 130 | VertexBuffer.unbind(); 131 | matrices.pop(); 132 | } 133 | } 134 | } 135 | RenderSystem.enableCull(); 136 | RenderSystem.disableBlend(); 137 | RenderSystem.defaultBlendFunc(); 138 | } 139 | 140 | public static void makeCloudBlock(BufferBuilder tessellator, int x, int y, int z, float r, float g, float b, short[] data, int index, int oX, int oZ) { 141 | if (!hasCloudBlock((oX*16)+x-1,y,(oZ*16)+z)) { 142 | tessellator.vertex(x, y, z).normal(-1,0,0).texture(0,0).color(r,g,b,1.0F).next(); 143 | tessellator.vertex(x, y + 1, z).normal(-1,0,0).texture(0,0).color(r,g,b,1.0F).next(); 144 | tessellator.vertex(x, y + 1, z + 1).normal(-1,0,0).texture(0,0).color(r,g,b,1.0F).next(); 145 | tessellator.vertex(x, y, z + 1).normal(-1,0,0).texture(0,0).color(r,g,b,1.0F).next(); 146 | } 147 | if (!hasCloudBlock((oX*16)+x+1,y,(oZ*16)+z)) { 148 | tessellator.vertex(x + 1, y, z).normal(1,0,0).texture(0,0).color(r,g,b,1.0F).next(); 149 | tessellator.vertex(x + 1, y + 1, z).normal(1,0,0).texture(0,0).color(r,g,b,1.0F).next(); 150 | tessellator.vertex(x + 1, y + 1, z + 1).normal(1,0,0).texture(0,0).color(r,g,b,1.0F).next(); 151 | tessellator.vertex(x + 1, y, z + 1).normal(1,0,0).texture(0,0).color(r,g,b,1.0F).next(); 152 | } 153 | 154 | if (y == 0 || data[index - 16] == (short)0xf000) { 155 | tessellator.vertex(x, y, z).normal(0,-1,0).texture(0,0).color(r,g,b,1.0F).next(); 156 | tessellator.vertex(x + 1, y, z).normal(0,-1,0).texture(0,0).color(r,g,b,1.0F).next(); 157 | tessellator.vertex(x + 1, y, z + 1).normal(0,-1,0).texture(0,0).color(r,g,b,1.0F).next(); 158 | tessellator.vertex(x, y, z + 1).normal(0,-1,0).texture(0,0).color(r,g,b,1.0F).next(); 159 | } 160 | if (y == 31 || data[index + 16] == (short)0xf000) { 161 | tessellator.vertex(x, y + 1, z).normal(0,1,0).texture(0,0).color(r,g,b,1.0F).next(); 162 | tessellator.vertex(x + 1, y + 1, z).normal(0,1,0).texture(0,0).color(r,g,b,1.0F).next(); 163 | tessellator.vertex(x + 1, y + 1, z + 1).normal(0,1,0).texture(0,0).color(r,g,b,1.0F).next(); 164 | tessellator.vertex(x, y + 1, z + 1).normal(0,1,0).texture(0,0).color(r,g,b,1.0F).next(); 165 | } 166 | 167 | if (!hasCloudBlock((oX*16)+x,y,(oZ*16)+z-1)) { 168 | tessellator.vertex(x, y, z).normal(0,0,-1).texture(0,0).color(r,g,b,1.0F).next(); 169 | tessellator.vertex(x, y + 1, z).normal(0,0,-1).texture(0,0).color(r,g,b,1.0F).next(); 170 | tessellator.vertex(x + 1, y + 1, z).normal(0,0,-1).texture(0,0).color(r,g,b,1.0F).next(); 171 | tessellator.vertex(x + 1, y, z).normal(0,0,-1).texture(0,0).color(r,g,b,1.0F).next(); 172 | } 173 | if (!hasCloudBlock((oX*16)+x,y,(oZ*16)+z+1)) { 174 | tessellator.vertex(x, y, z + 1).normal(0,0,1).texture(0,0).color(r,g,b,1.0F).next(); 175 | tessellator.vertex(x, y + 1, z + 1).normal(0,0,1).texture(0,0).color(r,g,b,1.0F).next(); 176 | tessellator.vertex(x + 1, y + 1, z + 1).normal(0,0,1).texture(0,0).color(r,g,b,1.0F).next(); 177 | tessellator.vertex(x + 1, y, z + 1).normal(0,0,1).texture(0,0).color(r,g,b,1.0F).next(); 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/EWDebugHud.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather; 2 | 3 | import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.client.gui.DrawContext; 6 | 7 | public class EWDebugHud implements HudRenderCallback { 8 | @Override 9 | public void onHudRender(DrawContext drawContext, float tickDelta) { 10 | drawContext.drawText(MinecraftClient.getInstance().textRenderer,Float.toString(MinecraftClient.getInstance().world.getSkyAngle(tickDelta)),0,0,0xffffffff,false); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/EnhancedWeatherClient.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather; 2 | 3 | import net.fabricmc.api.ClientModInitializer; 4 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; 5 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; 6 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 7 | import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry; 8 | import net.minecraft.util.math.BlockPos; 9 | import net.minecraft.util.math.MathHelper; 10 | import net.minecraft.util.math.random.Random; 11 | import net.minecraft.world.Heightmap; 12 | import net.minecraft.world.biome.Biome; 13 | import sh.talonfloof.enhancedweather.api.EnhancedWeatherAPI; 14 | import sh.talonfloof.enhancedweather.config.EnhancedWeatherConfig; 15 | import sh.talonfloof.enhancedweather.events.WeatherEvent; 16 | import sh.talonfloof.enhancedweather.network.*; 17 | import sh.talonfloof.enhancedweather.particle.HailParticle; 18 | import sh.talonfloof.enhancedweather.particle.SnowParticle; 19 | import sh.talonfloof.enhancedweather.particle.TornadoParticle; 20 | import sh.talonfloof.enhancedweather.particle.RainParticle; 21 | 22 | import java.util.HashMap; 23 | import java.util.UUID; 24 | 25 | import static sh.talonfloof.enhancedweather.EnhancedWeather.*; 26 | 27 | /* 28 | Weather Modifier Values: 29 | 0.3F-0.4F Cloud Transition 30 | 0.4F-0.5F Cloud 31 | 0.5F-0.6F Rain Transition 32 | 0.6F-0.7F Rain 33 | 0.8F- Thunder 34 | */ 35 | 36 | public class EnhancedWeatherClient implements ClientModInitializer { 37 | public static float rain = 0F; 38 | public static float cloud = 0F; 39 | public static int wetness = 0; 40 | public static boolean showRainbow = false; 41 | public static float rainDest = 0F; 42 | public static float cloudDest = 0F; 43 | public static float windX = 0F; 44 | public static float windZ = 0F; 45 | public static float windSpeed = 0F; 46 | public static HashMap clientEvents = new HashMap<>(); 47 | 48 | @Override 49 | public void onInitializeClient() { 50 | //HudRenderCallback.EVENT.register(new EWDebugHud()); 51 | ParticleFactoryRegistry.getInstance().register(EW_RAIN, RainParticle.DefaultFactory::new); 52 | ParticleFactoryRegistry.getInstance().register(EW_SNOW, SnowParticle.DefaultFactory::new); 53 | ParticleFactoryRegistry.getInstance().register(EW_HAIL, HailParticle.DefaultFactory::new); 54 | ParticleFactoryRegistry.getInstance().register(EW_TORNADO, TornadoParticle.DefaultFactory::new); 55 | ClientPlayNetworking.registerGlobalReceiver(UpdateConditions.PACKET_ID, UpdateConditionsClient::onReceive); 56 | ClientPlayNetworking.registerGlobalReceiver(ScreenOpen.PACKET_ID, ScreenOpenClient::onReceive); 57 | ClientPlayNetworking.registerGlobalReceiver(UpdateEvent.PACKET_ID, UpdateEventClient::onReceive); 58 | ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> { 59 | EnhancedWeather.LOGGER.info("Client has disconnected"); 60 | clientEvents.clear(); 61 | CloudRenderManager.cloudX = 0; 62 | CloudRenderManager.cloudZ = 0; 63 | cloudDest = 0; 64 | windX = 0; 65 | windZ = 0; 66 | windSpeed = 0; 67 | wetness = 0; 68 | cloud = 0; 69 | rain = 0; 70 | rainDest = 0; 71 | }); 72 | ClientTickEvents.START_WORLD_TICK.register((client) -> { 73 | for(UUID id : clientEvents.keySet()) { 74 | clientEvents.get(id).tickClient(); 75 | } 76 | if(rainDest > 0.90) { 77 | wetness = Math.min(wetness + 1,1000); 78 | if(wetness >= 1000) { 79 | showRainbow = true; 80 | } 81 | } else { 82 | wetness = Math.max(wetness - 1,0); 83 | if(wetness == 0) { 84 | showRainbow = false; 85 | } 86 | } 87 | if(rain > rainDest) { 88 | rain -= 0.005F; 89 | } else if(rain < rainDest) { 90 | rain += 0.005F; 91 | } 92 | if(rain > 1) { 93 | rain = 1; 94 | } 95 | if(rainDest == 0 && rain != 0F && Math.abs(rain-rainDest) < 0.2F) { 96 | rain = 0F; 97 | } 98 | if(cloud > cloudDest) { 99 | cloud -= 0.005F; 100 | } else if(cloud < cloudDest) { 101 | cloud += 0.005F; 102 | } 103 | if(cloudDest == 0 && cloud != 0F && Math.abs(cloud-cloudDest) < 0.2F) { 104 | cloud = 0F; 105 | } 106 | }); 107 | ClientTickEvents.END_CLIENT_TICK.register((client) -> { 108 | if(rain < 0.2F) 109 | return; 110 | if (client.isPaused() || client.world == null && client.getCameraEntity() == null) 111 | return; 112 | if(!EnhancedWeather.CONFIG.Misc_DimensionWhitelist().contains(client.world.getDimensionKey().getValue().toString())) 113 | return; 114 | if(client.player.getY() > client.world.getDimensionEffects().getCloudsHeight()) 115 | return; 116 | if(client.world.getBiome(client.player.getBlockPos()).value().getPrecipitation(client.player.getBlockPos()) == Biome.Precipitation.SNOW) { 117 | if(rain > 0) { 118 | for (int i = 0; i < 32; i++) { 119 | client.world.addParticle(EnhancedWeather.EW_SNOW, MathHelper.lerp(client.world.random.nextDouble(), client.player.getBlockX() - 64, client.player.getBlockX() + 64), client.player.getBlockY() + 50, MathHelper.lerp(client.world.random.nextDouble(), client.player.getBlockZ() - 64, client.player.getBlockZ() + 64), 0f, 0f, 0f); 120 | } 121 | } 122 | } else { 123 | int density = (int) ((rainDest == 1.0F ? 200 : 200) * rain); 124 | 125 | Random rand = Random.create(); 126 | 127 | for (int pass = 0; pass < density; pass++) { 128 | 129 | float theta = (float) (2 * Math.PI * rand.nextFloat()); 130 | float phi = (float) Math.acos(2 * rand.nextFloat() - 1); 131 | double x = 25 * MathHelper.sin(phi) * Math.cos(theta); 132 | double y = 25 * MathHelper.sin(phi) * Math.sin(theta); 133 | double z = 25 * MathHelper.cos(phi); 134 | 135 | var pos = new BlockPos.Mutable(); 136 | pos.set(x + client.player.getX(), y + client.player.getY(), z + client.player.getZ()); 137 | if (client.world.getTopY(Heightmap.Type.MOTION_BLOCKING, pos.getX(), pos.getZ()) > pos.getY()) 138 | continue; 139 | 140 | if(EnhancedWeather.CONFIG.Client_ParticleRain()) 141 | client.world.addParticle(EnhancedWeather.EW_RAIN, pos.getX() + rand.nextFloat(), pos.getY() + rand.nextFloat(), pos.getZ() + rand.nextFloat(), 0, 0, 0); 142 | if(windSpeed >= 50 && rainDest == 1F && pass < 5) { 143 | client.world.addParticle(EnhancedWeather.EW_HAIL, pos.getX() + rand.nextFloat(), pos.getY() + rand.nextFloat(), pos.getZ() + rand.nextFloat(), 0, 0, 0); 144 | } 145 | } 146 | } 147 | }); 148 | } 149 | } -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/events/TornadoClient.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.events; 2 | 3 | import net.minecraft.client.MinecraftClient; 4 | import net.minecraft.client.particle.Particle; 5 | import net.minecraft.util.math.MathHelper; 6 | import net.minecraft.util.math.Vec2f; 7 | import net.minecraft.util.math.Vec3d; 8 | import net.minecraft.util.math.random.Random; 9 | import net.minecraft.world.Heightmap; 10 | import sh.talonfloof.enhancedweather.EnhancedWeather; 11 | import sh.talonfloof.enhancedweather.EnhancedWeatherClient; 12 | import sh.talonfloof.enhancedweather.particle.TornadoParticle; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | import static sh.talonfloof.enhancedweather.EnhancedWeatherClient.windX; 18 | import static sh.talonfloof.enhancedweather.EnhancedWeatherClient.windZ; 19 | 20 | public class TornadoClient extends Tornado { 21 | public List funnelParticles = new ArrayList(); 22 | public Random rand = Random.create(); 23 | public TornadoClient(double x, double y, double z) { 24 | super(x, y, z, 0); 25 | } 26 | long ticks = 0; 27 | @Override 28 | public void tickClient() { 29 | Vec2f normal = new Vec2f(windX,windZ).normalize(); 30 | position = position.add(((normal.x*Math.min(1.5, EnhancedWeatherClient.windSpeed/25F)) * 0.002) * 32,0,((normal.y*Math.min(1.5,EnhancedWeatherClient.windSpeed/25F)) * 0.002) * 32); 31 | ticks++; 32 | if((ticks % 3) == 0) { 33 | assert MinecraftClient.getInstance().world != null; 34 | int currentY = MinecraftClient.getInstance().world.getTopY(Heightmap.Type.MOTION_BLOCKING, (int) position.x, (int) position.z); 35 | if (currentY == MinecraftClient.getInstance().world.getBottomY()) 36 | currentY = MinecraftClient.getInstance().world.getSeaLevel() + 1; 37 | int loopSize = 4; 38 | for (int i = 0; i < loopSize; i++) { 39 | if (funnelParticles.size() >= 600) { 40 | funnelParticles.get(0).markDead(); 41 | funnelParticles.remove(0); 42 | } 43 | if (funnelParticles.size() < 600) { 44 | Vec3d tryPos = new Vec3d(position.x + (rand.nextDouble() * 5D) - (rand.nextDouble() * 5D), currentY, position.z + (rand.nextDouble() * 5D) - (rand.nextDouble() * 5D)); 45 | TornadoParticle newParticle = (TornadoParticle) MinecraftClient.getInstance().particleManager.addParticle(EnhancedWeather.EW_TORNADO, tryPos.getX(), tryPos.getY(), tryPos.getZ(), 1F, 0.3F, 0.3F); 46 | assert newParticle != null; 47 | newParticle.setMaxAge(200); 48 | newParticle.setScale(200); 49 | funnelParticles.add(newParticle); 50 | } 51 | } 52 | for (int i = 0; i < funnelParticles.size(); i++) { 53 | TornadoParticle ent = (TornadoParticle)funnelParticles.get(i); 54 | if(ent.getY() > 196) { 55 | ent.markDead(); 56 | funnelParticles.remove(i); 57 | i -= 1; 58 | } 59 | } 60 | } 61 | for(Particle particle : funnelParticles) { 62 | TornadoParticle part = (TornadoParticle)particle; 63 | double a = position.x - part.getX(); 64 | double b = position.z - part.getZ(); 65 | part.yaw = -(float)Math.toDegrees((Math.atan2(b, a))) - 90; 66 | part.pitch = 30F; 67 | spinParticle(part); 68 | } 69 | } 70 | 71 | public void spinParticle(TornadoParticle ent) { 72 | int currentY = MinecraftClient.getInstance().world.getTopY(Heightmap.Type.MOTION_BLOCKING, (int) position.x, (int) position.z); 73 | if (currentY == MinecraftClient.getInstance().world.getBottomY()) 74 | currentY = MinecraftClient.getInstance().world.getSeaLevel() + 1; 75 | double d1 = ent.getX() - position.x; 76 | double d2 = ent.getZ() - position.z; 77 | Vec2f normalized = new Vec2f((float)d1,(float)d2).normalize(); 78 | float f = (float)Math.toDegrees(Math.atan2(normalized.y, normalized.x)); 79 | f -= 2; 80 | double curY = (ent.getY()-currentY)/(192-currentY); 81 | double radius = MathHelper.lerp(curY,5.0,50.0); 82 | double x = Math.cos(Math.toRadians(f))*radius; 83 | double z = Math.sin(Math.toRadians(f))*radius; 84 | ent.setPos(position.x+x,ent.getY(),position.z+z); 85 | ent.setVelocityY(2); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/mixin/client/BackgroundRendererMixin.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.mixin.client; 2 | 3 | import net.minecraft.client.MinecraftClient; 4 | import net.minecraft.client.render.BackgroundRenderer; 5 | import net.minecraft.client.render.Camera; 6 | import net.minecraft.client.render.CameraSubmersionType; 7 | import net.minecraft.world.dimension.DimensionTypes; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | @Mixin(BackgroundRenderer.class) 14 | public class BackgroundRendererMixin { 15 | /*@Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;getRainGradient(F)F")) 16 | private static float fogDarken(ClientWorld world, float delta) { 17 | return EnhancedWeatherClient.cloud; 18 | }*/ 19 | 20 | @Inject(method = "applyFog", at = @At(value = "RETURN")) 21 | private static void addWeatherFog(Camera camera, BackgroundRenderer.FogType fogType, float viewDistance, boolean thickFog, float tickDelta, CallbackInfo ci) { 22 | if (MinecraftClient.getInstance().world.getDimensionKey().equals(DimensionTypes.OVERWORLD)) { 23 | if (MinecraftClient.getInstance().gameRenderer.getCamera().getSubmersionType().equals(CameraSubmersionType.NONE)) { 24 | 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/mixin/client/CherryLeavesParticleMixin.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.mixin.client; 2 | 3 | import net.minecraft.client.particle.CherryLeavesParticle; 4 | import net.minecraft.client.particle.SpriteBillboardParticle; 5 | import net.minecraft.client.world.ClientWorld; 6 | import net.minecraft.world.dimension.DimensionTypes; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | import sh.talonfloof.enhancedweather.EnhancedWeatherClient; 12 | 13 | @Mixin(CherryLeavesParticle.class) 14 | public abstract class CherryLeavesParticleMixin extends SpriteBillboardParticle { 15 | 16 | protected CherryLeavesParticleMixin(ClientWorld clientWorld, double d, double e, double f) { 17 | super(clientWorld, d, e, f); 18 | } 19 | 20 | @Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/CherryLeavesParticle;move(DDD)V")) 21 | public void moveWithWind(CallbackInfo ci) { 22 | if (world.getDimensionKey().equals(DimensionTypes.OVERWORLD)) { 23 | ((CherryLeavesParticle) (Object) this).velocityX = EnhancedWeatherClient.windX / 4F; 24 | ((CherryLeavesParticle) (Object) this).velocityZ = EnhancedWeatherClient.windZ / 4F; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/mixin/client/MixinParticle.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.mixin.client; 2 | 3 | import net.minecraft.client.MinecraftClient; 4 | import net.minecraft.client.particle.Particle; 5 | import net.minecraft.client.world.ClientWorld; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.world.Heightmap; 8 | import net.minecraft.world.dimension.DimensionTypes; 9 | import org.spongepowered.asm.mixin.Final; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.Shadow; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | import sh.talonfloof.enhancedweather.EnhancedWeather; 16 | import sh.talonfloof.enhancedweather.EnhancedWeatherClient; 17 | 18 | @Mixin(Particle.class) 19 | public class MixinParticle { 20 | @Shadow 21 | @Final 22 | protected ClientWorld world; 23 | @Shadow 24 | protected boolean collidesWithWorld; 25 | @Shadow 26 | protected double prevPosX; 27 | @Shadow 28 | protected double prevPosY; 29 | @Shadow 30 | protected double prevPosZ; 31 | @Shadow 32 | protected double velocityX; 33 | @Shadow 34 | protected double velocityY; 35 | @Shadow 36 | protected double velocityZ; 37 | @Inject(at = @At("TAIL"), method = "tick") 38 | private void applyWind(CallbackInfo ci) { 39 | if(EnhancedWeather.CONFIG.Misc_DimensionWhitelist().contains(world.getDimensionKey().getValue().toString())) { 40 | if (collidesWithWorld) { 41 | if(world.getTopPosition(Heightmap.Type.MOTION_BLOCKING,new BlockPos((int)Math.floor(prevPosX),(int)Math.floor(prevPosY),(int)Math.floor(prevPosZ))).getY() <= prevPosY) { 42 | velocityX = EnhancedWeatherClient.windX/4F; 43 | velocityZ = EnhancedWeatherClient.windZ/4F; 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/mixin/client/ParticleManagerMixin.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.mixin.client; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import net.minecraft.client.particle.ParticleManager; 5 | import net.minecraft.client.render.Camera; 6 | import net.minecraft.client.render.LightmapTextureManager; 7 | import net.minecraft.client.render.VertexConsumerProvider; 8 | import net.minecraft.client.util.math.MatrixStack; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | @Mixin(ParticleManager.class) 15 | public class ParticleManagerMixin { 16 | @Inject(at = @At("HEAD"), method = "renderParticles(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider$Immediate;Lnet/minecraft/client/render/LightmapTextureManager;Lnet/minecraft/client/render/Camera;F)V") 17 | private void enableBackRender(MatrixStack matrices, VertexConsumerProvider.Immediate vertexConsumers, LightmapTextureManager lightmapTextureManager, Camera camera, float tickDelta, CallbackInfo ci) { 18 | RenderSystem.disableCull(); 19 | } 20 | @Inject(at = @At("TAIL"), method = "renderParticles(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider$Immediate;Lnet/minecraft/client/render/LightmapTextureManager;Lnet/minecraft/client/render/Camera;F)V") 21 | private void disableBackRender(MatrixStack matrices, VertexConsumerProvider.Immediate vertexConsumers, LightmapTextureManager lightmapTextureManager, Camera camera, float tickDelta, CallbackInfo ci) { 22 | RenderSystem.enableCull(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/mixin/client/WorldClientMixin.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.mixin.client; 2 | 3 | import net.fabricmc.api.EnvType; 4 | import net.fabricmc.api.Environment; 5 | import net.minecraft.client.MinecraftClient; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.util.math.MathHelper; 8 | import net.minecraft.world.Heightmap; 9 | import net.minecraft.world.World; 10 | import net.minecraft.world.biome.Biome; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 15 | import sh.talonfloof.enhancedweather.EnhancedWeather; 16 | import sh.talonfloof.enhancedweather.EnhancedWeatherClient; 17 | import sh.talonfloof.enhancedweather.api.EnhancedWeatherAPI; 18 | 19 | @Environment(EnvType.CLIENT) 20 | @Mixin(World.class) 21 | public class WorldClientMixin { 22 | @Inject(method="getRainGradient(F)F",at = @At("TAIL"), cancellable = true) 23 | public void getRainGradient(float delta, CallbackInfoReturnable cir) { 24 | if(MinecraftClient.getInstance().player != null) { 25 | if (MinecraftClient.getInstance().player.getY() > MinecraftClient.getInstance().world.getDimensionEffects().getCloudsHeight()) 26 | cir.setReturnValue(0F); 27 | else 28 | cir.setReturnValue(EnhancedWeatherClient.rain); 29 | } 30 | } 31 | 32 | @Inject(method="getThunderGradient(F)F",at = @At("TAIL"), cancellable = true) 33 | public void getThunderGradient(float delta, CallbackInfoReturnable cir) { 34 | if(MinecraftClient.getInstance().player != null) { 35 | if (MinecraftClient.getInstance().player.getY() > MinecraftClient.getInstance().world.getDimensionEffects().getCloudsHeight()) 36 | cir.setReturnValue(0F); 37 | else 38 | cir.setReturnValue(EnhancedWeatherClient.rainDest == 1F ? EnhancedWeatherClient.rain : 0F); 39 | } 40 | } 41 | @Inject(method = "hasRain(Lnet/minecraft/util/math/BlockPos;)Z", at = @At("RETURN"), cancellable = true) 42 | public void hasRain(BlockPos pos, CallbackInfoReturnable cir) { 43 | if (!EnhancedWeatherAPI.isRainingClient(((World)(Object)this),pos.getX() - MathHelper.floor(EnhancedWeather.cloudX), pos.getZ() - MathHelper.floor(EnhancedWeather.cloudZ))) { 44 | cir.setReturnValue(false); 45 | return; 46 | } 47 | if (!((World)(Object)this).isSkyVisible(pos)) { 48 | cir.setReturnValue(false); 49 | return; 50 | } 51 | if (((World)(Object)this).getTopPosition(Heightmap.Type.MOTION_BLOCKING, pos).getY() > pos.getY()) { 52 | cir.setReturnValue(false); 53 | return; 54 | } 55 | Biome biome = ((World)(Object)this).getBiome(pos).value(); 56 | cir.setReturnValue(biome.getPrecipitation(pos) == Biome.Precipitation.RAIN); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/mixin/client/WorldRendererMixin.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.mixin.client; 2 | 3 | import com.mojang.blaze3d.platform.GlStateManager; 4 | import com.mojang.blaze3d.systems.RenderSystem; 5 | import net.minecraft.client.MinecraftClient; 6 | import net.minecraft.client.particle.ParticleManager; 7 | import net.minecraft.client.render.*; 8 | import net.minecraft.client.util.math.MatrixStack; 9 | import net.minecraft.client.world.ClientWorld; 10 | import net.minecraft.particle.ParticleEffect; 11 | import net.minecraft.util.Identifier; 12 | import net.minecraft.util.math.MathHelper; 13 | import net.minecraft.util.math.random.Random; 14 | import org.joml.Matrix4f; 15 | import org.joml.Quaternionf; 16 | import org.spongepowered.asm.mixin.Mixin; 17 | import org.spongepowered.asm.mixin.Unique; 18 | import org.spongepowered.asm.mixin.injection.At; 19 | import org.spongepowered.asm.mixin.injection.Inject; 20 | import org.spongepowered.asm.mixin.injection.Redirect; 21 | import org.spongepowered.asm.mixin.injection.Slice; 22 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 23 | import sh.talonfloof.enhancedweather.CloudRenderManager; 24 | import sh.talonfloof.enhancedweather.EnhancedWeather; 25 | import sh.talonfloof.enhancedweather.config.EnhancedWeatherConfig; 26 | import sh.talonfloof.enhancedweather.EnhancedWeatherClient; 27 | 28 | @Mixin(WorldRenderer.class) 29 | public class WorldRendererMixin { 30 | @Unique 31 | private static VertexConsumerProvider.Immediate capturedImmediate; 32 | 33 | @Inject(method = "renderWeather(Lnet/minecraft/client/render/LightmapTextureManager;FDDD)V", at = @At("HEAD"), cancellable = true) 34 | public void rain(LightmapTextureManager manager, float tickDelta, double cameraX, double cameraY, double cameraZ, CallbackInfo ci) { 35 | if (EnhancedWeather.CONFIG.Client_ParticleRain()) { 36 | ci.cancel(); 37 | } 38 | } 39 | 40 | @Redirect(method = "tickRainSplashing(Lnet/minecraft/client/render/Camera;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;getRainGradient(F)F")) 41 | public float rainSound(ClientWorld instance, float v) { 42 | return MathHelper.clamp(EnhancedWeatherClient.rain, 0, 1); 43 | } 44 | 45 | @Redirect(method = "tickRainSplashing(Lnet/minecraft/client/render/Camera;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;addParticle(Lnet/minecraft/particle/ParticleEffect;DDDDDD)V")) 46 | public void tickRain(ClientWorld instance, ParticleEffect parameters, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { 47 | } 48 | 49 | @Inject(method = "renderClouds(Lnet/minecraft/client/util/math/MatrixStack;Lorg/joml/Matrix4f;FDDD)V", at = @At("HEAD"), cancellable = true) 50 | public void newCloudRender(MatrixStack matrices, Matrix4f projectionMatrix, float tickDelta, double cameraX, double cameraY, double cameraZ, CallbackInfo ci) { 51 | ClientWorld world = MinecraftClient.getInstance().world; 52 | if(EnhancedWeather.CONFIG.Misc_DimensionWhitelist().contains(world.getDimensionKey().getValue().toString())) { 53 | CloudRenderManager.render(matrices, projectionMatrix, tickDelta, cameraX, cameraY, cameraZ); 54 | ci.cancel(); 55 | } 56 | } 57 | 58 | @Inject(method = "renderSky(Lnet/minecraft/client/util/math/MatrixStack;Lorg/joml/Matrix4f;FLnet/minecraft/client/render/Camera;ZLjava/lang/Runnable;)V", slice = @Slice( 59 | from = @At( 60 | ordinal = 0, value = "INVOKE", 61 | target = "Lnet/minecraft/client/world/ClientWorld;getRainGradient(F)F" 62 | ) 63 | ), at = @At( 64 | shift = At.Shift.AFTER, 65 | ordinal = 0, 66 | value = "INVOKE", 67 | target = "Lnet/minecraft/client/util/math/MatrixStack;multiply(Lorg/joml/Quaternionf;)V" 68 | )) 69 | public void renderRainbow(MatrixStack matrices, Matrix4f projectionMatrix, float tickDelta, Camera camera, boolean thickFog, Runnable fogCallback, CallbackInfo ci) { 70 | if(!EnhancedWeatherClient.showRainbow || !EnhancedWeather.CONFIG.Client_ShowRainbow()) 71 | return; 72 | ClientWorld world = MinecraftClient.getInstance().world; 73 | if(!EnhancedWeather.CONFIG.Misc_DimensionWhitelist().contains(world.getDimensionKey().getValue().toString())) { 74 | return; 75 | } 76 | matrices.push(); 77 | Tessellator t = Tessellator.getInstance(); 78 | GlStateManager._blendFuncSeparate(770, 771, 1, 0); 79 | long time = world.getTimeOfDay() + 1000; 80 | int day = (int) (time / 24000L); 81 | Random rand = Random.create(day * 0xFF); 82 | float angle1 = rand.nextFloat() * 360F; 83 | float angle2 = rand.nextFloat() * 360F; 84 | float effCelAng1 = world.getSkyAngle(tickDelta); 85 | if (effCelAng1 >= 0.75F && effCelAng1 < 0.80F) { 86 | effCelAng1 = MathHelper.lerp((effCelAng1 - 0.75F) / 0.05F, 0F, 0.4F); 87 | } else if(effCelAng1 >= 0.20F && effCelAng1 < 0.25F) { 88 | effCelAng1 = MathHelper.lerp((effCelAng1 - 0.20F) / 0.05F, 0.4F, 0F); 89 | } else if(effCelAng1 >= 0.25F && effCelAng1 < 0.75F) { 90 | effCelAng1 = 0; 91 | } else { 92 | effCelAng1 = 0.4F; 93 | } 94 | float finalAlpha = EnhancedWeatherClient.showRainbow ? (effCelAng1*(Math.min(200,EnhancedWeatherClient.wetness)/200F)) : 0F; 95 | RenderSystem.setShaderColor(1F, 1F, 1F, finalAlpha - (world.getRainGradient(tickDelta)*effCelAng1)); 96 | matrices.multiply(new Quaternionf().rotateY((float)Math.toRadians(angle1))); 97 | matrices.multiply(new Quaternionf().rotateZ((float)Math.toRadians(angle2))); 98 | Matrix4f mat = matrices.peek().getPositionMatrix(); 99 | t.getBuffer().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE); 100 | for (int i = 0; i < 90; i++) { 101 | int j = i; 102 | if (i % 2 == 0) { 103 | j--; 104 | } 105 | 106 | float ang = j * (360F / 90F); 107 | float xp = (float) Math.cos(ang * Math.PI / 180F) * 10; 108 | float zp = (float) Math.sin(ang * Math.PI / 180F) * 10; 109 | 110 | float ut = ang * (1F / 360F); 111 | if (i % 2 == 0) { 112 | t.getBuffer().vertex(mat, xp, 2F, zp).texture(ut, 1F).next(); 113 | t.getBuffer().vertex(mat, xp, 0, zp).texture(ut, 0).next(); 114 | } else { 115 | t.getBuffer().vertex(mat, xp, 0, zp).texture(ut, 0).next(); 116 | t.getBuffer().vertex(mat, xp, 2F, zp).texture(ut, 1F).next(); 117 | } 118 | 119 | } 120 | RenderSystem.setShader(GameRenderer::getPositionTexProgram); 121 | RenderSystem.setShaderTexture(0, new Identifier("enhancedweather","textures/sky/rainbow.png")); 122 | t.draw(); 123 | matrices.pop(); 124 | RenderSystem.setShaderColor(1F, 1F, 1F, 1F - EnhancedWeatherClient.cloud); 125 | GlStateManager._blendFuncSeparate(770, 1, 1, 0); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/network/ScreenOpenClient.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.network; 2 | 3 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.client.network.ClientPlayNetworkHandler; 6 | import net.minecraft.network.PacketByteBuf; 7 | import net.minecraft.util.math.BlockPos; 8 | import sh.talonfloof.enhancedweather.screen.RadarScreen; 9 | 10 | public class ScreenOpenClient { 11 | public static void onReceive(MinecraftClient client, ClientPlayNetworkHandler clientPlayNetworkHandler, PacketByteBuf packetByteBuf, PacketSender packetSender) { 12 | BlockPos pos = packetByteBuf.readBlockPos(); 13 | client.send(() -> client.setScreen(new RadarScreen(pos))); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/network/SuppressAlert.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.network; 2 | 3 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 4 | import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; 5 | import net.minecraft.client.MinecraftClient; 6 | import net.minecraft.network.PacketByteBuf; 7 | import net.minecraft.util.Identifier; 8 | import net.minecraft.util.math.BlockPos; 9 | 10 | import static sh.talonfloof.enhancedweather.network.SuppressAlertServer.PACKET_ID; 11 | 12 | public class SuppressAlert { 13 | public static void send(BlockPos pos) { 14 | PacketByteBuf buf = PacketByteBufs.create(); 15 | buf.writeBlockPos(pos); 16 | ClientPlayNetworking.send(PACKET_ID,buf); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/network/UpdateConditionsClient.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.network; 2 | 3 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.client.network.ClientPlayNetworkHandler; 6 | import net.minecraft.network.PacketByteBuf; 7 | import net.minecraft.util.math.MathHelper; 8 | import sh.talonfloof.enhancedweather.CloudRenderManager; 9 | import sh.talonfloof.enhancedweather.api.EnhancedWeatherAPI; 10 | import sh.talonfloof.enhancedweather.EnhancedWeatherClient; 11 | 12 | 13 | public class UpdateConditionsClient { 14 | public static void onReceive(MinecraftClient client, ClientPlayNetworkHandler clientPlayNetworkHandler, PacketByteBuf packetByteBuf, PacketSender packetSender) { 15 | EnhancedWeatherClient.windX = packetByteBuf.readFloat(); 16 | EnhancedWeatherClient.windZ = packetByteBuf.readFloat(); 17 | EnhancedWeatherClient.windSpeed = packetByteBuf.readFloat(); 18 | CloudRenderManager.cloudX = packetByteBuf.readDouble(); 19 | CloudRenderManager.cloudZ = packetByteBuf.readDouble(); 20 | if(client.player != null) { 21 | float rain = Math.max(0, EnhancedWeatherAPI.sampleFrontClient(client.player.getBlockX() - MathHelper.floor(CloudRenderManager.cloudX), client.player.getBlockZ() - MathHelper.floor(CloudRenderManager.cloudZ),0.1)-0.2F)/0.8F; 22 | boolean thunder = EnhancedWeatherAPI.isThunderingClient(client.world, 0, client.player.getBlockX() - MathHelper.floor(CloudRenderManager.cloudX), client.player.getBlockZ() - MathHelper.floor(CloudRenderManager.cloudZ)); 23 | EnhancedWeatherClient.rainDest = thunder && rain >= 0.2F ? 1F : MathHelper.clamp(rain/0.2F,0F,0.99F); 24 | EnhancedWeatherClient.cloudDest = MathHelper.clamp(rain/0.2F,0,1); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/network/UpdateEventClient.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.network; 2 | 3 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 4 | import net.minecraft.client.MinecraftClient; 5 | import net.minecraft.client.network.ClientPlayNetworkHandler; 6 | import net.minecraft.nbt.NbtCompound; 7 | import net.minecraft.network.PacketByteBuf; 8 | import sh.talonfloof.enhancedweather.events.TornadoClient; 9 | import sh.talonfloof.enhancedweather.EnhancedWeatherClient; 10 | 11 | import java.util.UUID; 12 | 13 | public class UpdateEventClient { 14 | public static void onReceive(MinecraftClient client, ClientPlayNetworkHandler clientPlayNetworkHandler, PacketByteBuf packetByteBuf, PacketSender packetSender) { 15 | long lower = packetByteBuf.readLong(); 16 | long upper = packetByteBuf.readLong(); 17 | UUID id = new UUID(upper,lower); 18 | NbtCompound data = packetByteBuf.readNbt(); 19 | client.send(() -> { 20 | if(data == null) { 21 | EnhancedWeatherClient.clientEvents.remove(id); 22 | } else { 23 | if(EnhancedWeatherClient.clientEvents.containsKey(id)) { 24 | EnhancedWeatherClient.clientEvents.get(id).applyUpdate(data); 25 | } else { 26 | if(data.getString("id").equals("enhancedweather:tornado")) { 27 | TornadoClient t = new TornadoClient(0,0,0); 28 | t.applyUpdate(data); 29 | EnhancedWeatherClient.clientEvents.put(id,t); 30 | } 31 | } 32 | } 33 | }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/particle/HailParticle.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.particle; 2 | 3 | import net.fabricmc.api.EnvType; 4 | import net.fabricmc.api.Environment; 5 | import net.minecraft.client.particle.*; 6 | import net.minecraft.client.render.Camera; 7 | import net.minecraft.client.render.VertexConsumer; 8 | import net.minecraft.client.world.ClientWorld; 9 | import net.minecraft.entity.Entity; 10 | import net.minecraft.particle.DefaultParticleType; 11 | import net.minecraft.sound.SoundCategory; 12 | import net.minecraft.sound.SoundEvents; 13 | import net.minecraft.util.math.*; 14 | import net.minecraft.world.World; 15 | import org.jetbrains.annotations.Nullable; 16 | import org.joml.Quaternionf; 17 | import org.joml.Vector3f; 18 | import sh.talonfloof.enhancedweather.EnhancedWeatherClient; 19 | 20 | import java.util.List; 21 | 22 | public class HailParticle extends SpriteBillboardParticle { 23 | public float prevYaw = 0F; 24 | public float yaw = 0F; 25 | public float prevPitch = 0F; 26 | public float pitch = 0F; 27 | private boolean hasStopped = false; 28 | private boolean bounced = false; 29 | private boolean hasCollidedVerticallyDownwards = false; 30 | public int lastNonZeroBrightness = 0; 31 | public HailParticle(ClientWorld clientWorld, double x, double y, double z, double r, double g, double b, SpriteProvider provider) { 32 | super(clientWorld, x, y, z, r, g, b); 33 | this.yaw = clientWorld.random.nextInt(360) - 180F; 34 | this.collidesWithWorld = false; 35 | this.gravityStrength = 3.5F; 36 | this.maxAge = 70; 37 | this.velocityX = 0.0D; 38 | this.velocityY = -0.5D; 39 | this.velocityZ = 0.0D; 40 | this.velocityMultiplier = 1.0F; 41 | this.setSprite(provider); 42 | } 43 | @Override 44 | public ParticleTextureSheet getType() { 45 | return ParticleTextureSheet.PARTICLE_SHEET_TRANSLUCENT; 46 | } 47 | 48 | @Override 49 | public void move(double dx, double dy, double dz) { 50 | if (this.hasStopped) { 51 | return; 52 | } 53 | double d = dx; 54 | double e = dy; 55 | double f = dz; 56 | if ((dx != 0.0 || dy != 0.0 || dz != 0.0) && dx * dx + dy * dy + dz * dz < MathHelper.square(100.0)) { 57 | Vec3d vec3d = Entity.adjustMovementForCollisions(null, (Vec3d)new Vec3d(dx, dy, dz), (Box)this.getBoundingBox(), (World)this.world, List.of()); 58 | dx = vec3d.x; 59 | dy = vec3d.y; 60 | dz = vec3d.z; 61 | } 62 | if (dx != 0.0 || dy != 0.0 || dz != 0.0) { 63 | this.setBoundingBox(this.getBoundingBox().offset(dx, dy, dz)); 64 | this.repositionFromBoundingBox(); 65 | } 66 | if (Math.abs(e) >= (double)1.0E-5f && Math.abs(dy) < (double)1.0E-5f) { 67 | this.hasStopped = true; 68 | } 69 | this.onGround = e != dy && e < 0.0; 70 | this.hasCollidedVerticallyDownwards = e < y; 71 | if (d != dx) { 72 | this.velocityX = 0.0; 73 | } 74 | if (f != dz) { 75 | this.velocityZ = 0.0; 76 | } 77 | if (onGround && !bounced) { 78 | this.velocityY = -this.velocityY * 0.2F; 79 | this.onGround = false; 80 | bounced = true; 81 | world.playSoundAtBlockCenter(new BlockPos((int)this.x,(int)this.y,(int)this.z),SoundEvents.BLOCK_WOOD_BREAK, SoundCategory.WEATHER,0.2F,2F,false); 82 | } 83 | } 84 | 85 | @Override 86 | public void tick() { 87 | super.tick(); 88 | double speedXZ = Math.sqrt(velocityX * velocityX + velocityZ * velocityZ); 89 | double spinFastRateAdj = 10F * speedXZ * 10F; 90 | if(!onGround) { 91 | this.velocityX = EnhancedWeatherClient.windX / 4F; 92 | this.velocityZ = EnhancedWeatherClient.windZ / 4F; 93 | } 94 | this.prevPitch = this.pitch; 95 | this.prevYaw = this.yaw; 96 | if(!onGround) { 97 | this.pitch += (float) spinFastRateAdj; 98 | this.yaw += (float) -spinFastRateAdj; 99 | } 100 | if(onGround && bounced) { 101 | if(this.age < this.maxAge-20) { 102 | this.age = Math.max(this.age, this.maxAge - 20); 103 | } 104 | this.alpha = 1F-((this.age-(this.maxAge-20))/20.0F); 105 | } 106 | } 107 | 108 | @Override 109 | public void buildGeometry(VertexConsumer buffer, Camera camera, float tickDelta) { 110 | Vec3d vec3 = camera.getPos(); 111 | float f = (float)(MathHelper.lerp(tickDelta, this.prevPosX, this.x) - vec3.x); 112 | float f1 = (float)(MathHelper.lerp(tickDelta, this.prevPosY, this.y) - vec3.y); 113 | float f2 = (float)(MathHelper.lerp(tickDelta, this.prevPosZ, this.z) - vec3.z); 114 | Quaternionf quaternion = new Quaternionf(0, 0, 0, 1); 115 | quaternion.mul(RotationAxis.POSITIVE_Y.rotationDegrees(MathHelper.lerp(tickDelta, this.prevYaw, yaw))); 116 | quaternion.mul(RotationAxis.POSITIVE_X.rotationDegrees(MathHelper.lerp(tickDelta, this.prevPitch, pitch))); 117 | 118 | Vector3f[] avector3f = new Vector3f[]{ 119 | new Vector3f(-1.0F, -1.0F, 0.0F), 120 | new Vector3f(-1.0F, 1.0F, 0.0F), 121 | new Vector3f(1.0F, 1.0F, 0.0F), 122 | new Vector3f(1.0F, -1.0F, 0.0F)}; 123 | 124 | Vector3f[] avector3f2 = new Vector3f[]{ 125 | new Vector3f(0.0F, -1.0F, -1.0F), 126 | new Vector3f(0.0F, 1.0F, -1.0F), 127 | new Vector3f(0.0F, 1.0F, 1.0F), 128 | new Vector3f(0.0F, -1.0F, 1.0F)}; 129 | 130 | Vector3f[] avector3f3 = new Vector3f[]{ 131 | new Vector3f(-1.0F, 0.0F, -1.0F), 132 | new Vector3f(-1.0F, 0.0F, 1.0F), 133 | new Vector3f(1.0F, 0.0F, 1.0F), 134 | new Vector3f(1.0F, 0.0F, -1.0F)}; 135 | 136 | float f4 = this.getSize(tickDelta); 137 | 138 | for(int i = 0; i < 4; ++i) { 139 | Vector3f vector3f = avector3f[i]; 140 | vector3f.rotate(quaternion); 141 | vector3f.mul(f4); 142 | vector3f.add(f, f1, f2); 143 | } 144 | 145 | for(int i = 0; i < 4; ++i) { 146 | Vector3f vector3f = avector3f2[i]; 147 | vector3f.rotate(quaternion); 148 | vector3f.mul(f4); 149 | vector3f.add(f, f1, f2); 150 | } 151 | 152 | for(int i = 0; i < 4; ++i) { 153 | Vector3f vector3f = avector3f3[i]; 154 | vector3f.rotate(quaternion); 155 | vector3f.mul(f4); 156 | vector3f.add(f, f1, f2); 157 | } 158 | 159 | float f7 = this.getMinU(); 160 | float f8 = this.getMaxU(); 161 | float f5 = this.getMinV(); 162 | float f6 = this.getMaxV(); 163 | int j = this.getBrightness(tickDelta); 164 | if (j > 0) { 165 | lastNonZeroBrightness = j; 166 | } else { 167 | j = lastNonZeroBrightness; 168 | } 169 | buffer.vertex(avector3f[0].x(), avector3f[0].y(), avector3f[0].z()).texture(f8, f6).color(this.red, this.green, this.blue, this.alpha).light(j).next(); 170 | buffer.vertex(avector3f[1].x(), avector3f[1].y(), avector3f[1].z()).texture(f8, f5).color(this.red, this.green, this.blue, this.alpha).light(j).next(); 171 | buffer.vertex(avector3f[2].x(), avector3f[2].y(), avector3f[2].z()).texture(f7, f5).color(this.red, this.green, this.blue, this.alpha).light(j).next(); 172 | buffer.vertex(avector3f[3].x(), avector3f[3].y(), avector3f[3].z()).texture(f7, f6).color(this.red, this.green, this.blue, this.alpha).light(j).next(); 173 | 174 | buffer.vertex(avector3f2[0].x(), avector3f2[0].y(), avector3f2[0].z()).texture(f8, f6).color(this.red, this.green, this.blue, this.alpha).light(j).next(); 175 | buffer.vertex(avector3f2[1].x(), avector3f2[1].y(), avector3f2[1].z()).texture(f8, f5).color(this.red, this.green, this.blue, this.alpha).light(j).next(); 176 | buffer.vertex(avector3f2[2].x(), avector3f2[2].y(), avector3f2[2].z()).texture(f7, f5).color(this.red, this.green, this.blue, this.alpha).light(j).next(); 177 | buffer.vertex(avector3f2[3].x(), avector3f2[3].y(), avector3f2[3].z()).texture(f7, f6).color(this.red, this.green, this.blue, this.alpha).light(j).next(); 178 | 179 | buffer.vertex(avector3f3[0].x(), avector3f3[0].y(), avector3f3[0].z()).texture(f8, f6).color(this.red, this.green, this.blue, this.alpha).light(j).next(); 180 | buffer.vertex(avector3f3[1].x(), avector3f3[1].y(), avector3f3[1].z()).texture(f8, f5).color(this.red, this.green, this.blue, this.alpha).light(j).next(); 181 | buffer.vertex(avector3f3[2].x(), avector3f3[2].y(), avector3f3[2].z()).texture(f7, f5).color(this.red, this.green, this.blue, this.alpha).light(j).next(); 182 | buffer.vertex(avector3f3[3].x(), avector3f3[3].y(), avector3f3[3].z()).texture(f7, f6).color(this.red, this.green, this.blue, this.alpha).light(j).next(); 183 | } 184 | @Environment(EnvType.CLIENT) 185 | public record DefaultFactory(SpriteProvider provider) implements ParticleFactory { 186 | 187 | @Nullable 188 | @Override 189 | public Particle createParticle(DefaultParticleType parameters, ClientWorld world, double x, double y, double z, double r, double g, double b) { 190 | return new HailParticle(world, x, y, z, r, g, b, provider); 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/particle/RainParticle.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.particle; 2 | 3 | import net.fabricmc.api.EnvType; 4 | import net.fabricmc.api.Environment; 5 | import net.minecraft.client.MinecraftClient; 6 | import net.minecraft.client.particle.*; 7 | import net.minecraft.client.render.Camera; 8 | import net.minecraft.client.render.VertexConsumer; 9 | import net.minecraft.client.world.ClientWorld; 10 | import net.minecraft.particle.DefaultParticleType; 11 | import net.minecraft.particle.ParticleTypes; 12 | import net.minecraft.registry.tag.FluidTags; 13 | import net.minecraft.util.math.*; 14 | import org.jetbrains.annotations.Nullable; 15 | import org.joml.Quaternionf; 16 | import org.joml.Vector3f; 17 | import sh.talonfloof.enhancedweather.EnhancedWeatherClient; 18 | 19 | public class RainParticle extends SpriteBillboardParticle { 20 | public float prevYaw = 0F; 21 | public float yaw = 0F; 22 | public float prevPitch = 0F; 23 | public float pitch = 0F; 24 | public RainParticle(ClientWorld clientWorld, double x, double y, double z, double r, double g, double b, SpriteProvider provider) { 25 | super(clientWorld, x, y, z, r, g, b); 26 | this.velocityX = 0.0D; 27 | this.velocityY = -0.5D; 28 | this.velocityZ = 0.0D; 29 | this.gravityStrength = 1.8F; 30 | this.scale = 0.25F; 31 | this.maxAge = 20; 32 | this.setSprite(provider); 33 | BlockPos pos = new BlockPos((int)x,(int)y,(int)z); 34 | //int color = 0x43d5ee; 35 | int color = 0xffffff; 36 | this.setColor((float)ColorHelper.Argb.getRed(color)/255F,(float)ColorHelper.Argb.getGreen(color)/255F,(float)ColorHelper.Argb.getBlue(color)/255F); 37 | } 38 | 39 | @Override 40 | public void buildGeometry(VertexConsumer builder, Camera camera, float f) { 41 | internalBuildGeometry(builder,camera,f,0F); 42 | internalBuildGeometry(builder,camera,f,90F); 43 | internalBuildGeometry(builder,camera,f,180F); 44 | internalBuildGeometry(builder,camera,f,270F); 45 | } 46 | 47 | public void internalBuildGeometry(VertexConsumer builder, Camera camera, float f, float yaw) { 48 | Vec3d vec3 = camera.getPos(); 49 | float x = (float) (MathHelper.lerp(f, this.prevPosX, this.x) - vec3.x); 50 | float y = (float) (MathHelper.lerp(f, this.prevPosY, this.y) - vec3.y); 51 | float z = (float) (MathHelper.lerp(f, this.prevPosZ, this.z) - vec3.z); 52 | Quaternionf quaternion = new Quaternionf(0,0,0,1); 53 | double speed = velocityX * velocityX + velocityZ * velocityZ; 54 | prevYaw = this.yaw; 55 | prevPitch = pitch; 56 | this.yaw = -(float)Math.toDegrees(Math.atan2(velocityZ, velocityX))-90; 57 | this.pitch = Math.min(45, (float)(speed * 120)); 58 | quaternion.mul(RotationAxis.POSITIVE_Y.rotationDegrees(MathHelper.lerp(f, this.prevYaw, this.yaw))); 59 | quaternion.mul(RotationAxis.POSITIVE_X.rotationDegrees(MathHelper.lerp(f, prevPitch, pitch))); 60 | quaternion.mul(RotationAxis.POSITIVE_Y.rotationDegrees(yaw)); 61 | 62 | Vector3f[] vector3fs = 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)}; 63 | float k = this.getSize(f); 64 | 65 | for (int l = 0; l < 4; ++l) { 66 | Vector3f vector3f = vector3fs[l]; 67 | vector3f.rotate(quaternion); 68 | vector3f.mul(k); 69 | vector3f.add(x, y, z); 70 | } 71 | 72 | float l = this.getMinU(); 73 | float vector3f = this.getMaxU(); 74 | float m = this.getMinV(); 75 | float n = this.getMaxV(); 76 | int o = this.getBrightness(f); 77 | builder.vertex(vector3fs[0].x(), vector3fs[0].y(), vector3fs[0].z()).texture(vector3f, n).color(this.red, this.green, this.blue, this.alpha).light(o).next(); 78 | builder.vertex(vector3fs[1].x(), vector3fs[1].y(), vector3fs[1].z()).texture(vector3f, m).color(this.red, this.green, this.blue, this.alpha).light(o).next(); 79 | builder.vertex(vector3fs[2].x(), vector3fs[2].y(), vector3fs[2].z()).texture(l, m).color(this.red, this.green, this.blue, this.alpha).light(o).next(); 80 | builder.vertex(vector3fs[3].x(), vector3fs[3].y(), vector3fs[3].z()).texture(l, n).color(this.red, this.green, this.blue, this.alpha).light(o).next(); 81 | } 82 | 83 | public void tick() { 84 | this.velocityX = EnhancedWeatherClient.windX/2F; 85 | this.velocityZ = EnhancedWeatherClient.windZ/2F; 86 | super.tick(); 87 | MinecraftClient client = MinecraftClient.getInstance(); 88 | if (this.onGround || this.world.getBlockState(new BlockPos((int) this.x, (int)this.y, (int)this.z)).blocksMovement() || this.world.getFluidState(new BlockPos((int) this.x, (int) this.y, (int) this.z)).isIn(FluidTags.WATER) || this.world.getFluidState(new BlockPos((int) this.x, (int) this.y, (int) this.z)).isIn(FluidTags.LAVA)) { 89 | client.particleManager.addParticle(ParticleTypes.RAIN, this.x, this.y, this.z, 0, 0, 0); 90 | this.markDead(); 91 | } 92 | } 93 | 94 | @Override 95 | public ParticleTextureSheet getType() { 96 | return ParticleTextureSheet.PARTICLE_SHEET_TRANSLUCENT; 97 | } 98 | 99 | @Environment(EnvType.CLIENT) 100 | public record DefaultFactory(SpriteProvider provider) implements ParticleFactory { 101 | 102 | @Nullable 103 | @Override 104 | public Particle createParticle(DefaultParticleType parameters, ClientWorld world, double x, double y, double z, double r, double g, double b) { 105 | return new RainParticle(world, x, y, z, r, g, b, provider); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/particle/SnowParticle.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.particle; 2 | 3 | import net.fabricmc.api.EnvType; 4 | import net.fabricmc.api.Environment; 5 | import net.minecraft.client.MinecraftClient; 6 | import net.minecraft.client.particle.*; 7 | import net.minecraft.client.world.ClientWorld; 8 | import net.minecraft.particle.DefaultParticleType; 9 | import net.minecraft.registry.tag.FluidTags; 10 | import net.minecraft.util.math.BlockPos; 11 | import org.jetbrains.annotations.Nullable; 12 | import sh.talonfloof.enhancedweather.EnhancedWeatherClient; 13 | 14 | public class SnowParticle extends SpriteBillboardParticle { 15 | protected SnowParticle(ClientWorld clientWorld, double x, double y, double z, double r, double g, double b, SpriteProvider provider) { 16 | super(clientWorld, x, y, z, r, g, b); 17 | this.velocityX = 0.0D; 18 | this.velocityY = -1.0D; 19 | this.velocityZ = 0.0D; 20 | this.gravityStrength = 1.0F; 21 | this.scale = 0.25F; 22 | this.maxAge = 200; 23 | this.setSprite(provider); 24 | } 25 | 26 | public void tick() { 27 | this.velocityX = EnhancedWeatherClient.windX/2F; 28 | this.velocityZ = EnhancedWeatherClient.windZ/2F; 29 | super.tick(); 30 | MinecraftClient client = MinecraftClient.getInstance(); 31 | if (this.onGround || this.world.getBlockState(new BlockPos((int) this.x, (int)this.y, (int)this.z)).blocksMovement() || this.world.getFluidState(new BlockPos((int) this.x, (int) this.y, (int) this.z)).isIn(FluidTags.WATER) || this.world.getFluidState(new BlockPos((int) this.x, (int) this.y, (int) this.z)).isIn(FluidTags.LAVA)) { 32 | this.markDead(); 33 | } 34 | } 35 | 36 | @Override 37 | public ParticleTextureSheet getType() { 38 | return ParticleTextureSheet.PARTICLE_SHEET_TRANSLUCENT; 39 | } 40 | 41 | @Environment(EnvType.CLIENT) 42 | public record DefaultFactory(SpriteProvider provider) implements ParticleFactory { 43 | @Nullable 44 | @Override 45 | public Particle createParticle(DefaultParticleType parameters, ClientWorld world, double x, double y, double z, double r, double g, double b) { 46 | return new SnowParticle(world, x, y, z, r, g, b, provider); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/particle/TornadoParticle.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.particle; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import net.minecraft.client.particle.*; 5 | import net.minecraft.client.render.BufferBuilder; 6 | import net.minecraft.client.render.Camera; 7 | import net.minecraft.client.render.Tessellator; 8 | import net.minecraft.client.render.VertexConsumer; 9 | import net.minecraft.client.texture.TextureManager; 10 | import net.minecraft.client.world.ClientWorld; 11 | import net.minecraft.particle.DefaultParticleType; 12 | import net.minecraft.util.math.MathHelper; 13 | import net.minecraft.util.math.RotationAxis; 14 | import net.minecraft.util.math.Vec3d; 15 | import net.minecraft.util.math.random.Random; 16 | import org.joml.Quaternionf; 17 | import org.joml.Vector3f; 18 | 19 | public class TornadoParticle extends SpriteBillboardParticle { 20 | private static long nextID = 0; 21 | public long ID = 0; 22 | public float yaw = 0F; 23 | public float pitch = 0F; 24 | public boolean velocityDecay = false; 25 | protected static Random rand = Random.create(); 26 | 27 | public TornadoParticle(ClientWorld clientWorld, double x, double y, double z, double r, double g, double b, SpriteProvider provider) { 28 | super(clientWorld, x, y, z, r, g, b); 29 | ID = nextID; 30 | nextID += 1; 31 | this.setSprite(provider); 32 | this.setBoundingBoxSpacing(0.25F, 0.25F); 33 | this.scale = 200F*0.1F; 34 | this.collidesWithWorld = false; 35 | this.setMaxAge(300+rand.nextInt(100)); 36 | this.setColor((float)g,(float)g,(float)b); 37 | this.age = 0; 38 | this.setAlpha(1.0F); 39 | this.yaw = Math.round(Math.random()*360); 40 | this.pitch = -90+Math.round(Math.random()*50)-Math.round(Math.random()*50); 41 | } 42 | 43 | @Override 44 | public ParticleTextureSheet getType() { 45 | return ParticleTextureSheet.PARTICLE_SHEET_TRANSLUCENT; 46 | } 47 | 48 | @Override 49 | public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float tickDelta) { 50 | Vec3d vec3d = camera.getPos(); 51 | float f = (float)(MathHelper.lerp((double)tickDelta, this.prevPosX, this.x) - vec3d.getX()); 52 | float g = (float)(MathHelper.lerp((double)tickDelta, this.prevPosY, this.y) - vec3d.getY()); 53 | float h = (float)(MathHelper.lerp((double)tickDelta, this.prevPosZ, this.z) - vec3d.getZ()); 54 | Quaternionf quaternion; 55 | quaternion = new Quaternionf(0, 0, 0, 1); 56 | while (yaw >= 180.0F) 57 | { 58 | yaw -= 360.0F; 59 | } 60 | while (yaw <= -180.0F) 61 | { 62 | yaw += 360.0F; 63 | } 64 | quaternion.mul(RotationAxis.POSITIVE_Y.rotationDegrees(yaw)); 65 | quaternion.mul(RotationAxis.POSITIVE_X.rotationDegrees(pitch)); 66 | Vector3f[] vector3fs = 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)}; 67 | float i = this.getSize(tickDelta); 68 | 69 | for(int j = 0; j < 4; ++j) { 70 | Vector3f vector3f = vector3fs[j]; 71 | vector3f.rotate(quaternion); 72 | vector3f.mul(i); 73 | vector3f.add(f, g, h); 74 | } 75 | 76 | float l = this.getMinU(); 77 | float m = this.getMaxU(); 78 | float n = this.getMinV(); 79 | float o = this.getMaxV(); 80 | int p = this.getBrightness(tickDelta); 81 | vertexConsumer.vertex(vector3fs[0].x, vector3fs[0].y, vector3fs[0].z).texture(m, o).color(this.red, this.green, this.blue, this.alpha).light(p).next(); 82 | vertexConsumer.vertex(vector3fs[1].x, vector3fs[1].y, vector3fs[1].z).texture(m, n).color(this.red, this.green, this.blue, this.alpha).light(p).next(); 83 | vertexConsumer.vertex(vector3fs[2].x, vector3fs[2].y, vector3fs[2].z).texture(l, n).color(this.red, this.green, this.blue, this.alpha).light(p).next(); 84 | vertexConsumer.vertex(vector3fs[3].x, vector3fs[3].y, vector3fs[3].z).texture(l, o).color(this.red, this.green, this.blue, this.alpha).light(p).next(); 85 | } 86 | 87 | @Override 88 | public void tick() { 89 | super.tick(); 90 | this.velocityX = 0; 91 | this.velocityZ = 0; 92 | if(!velocityDecay) { 93 | this.velocityY /= 0.9800000190734863D; 94 | } 95 | if(this.age > this.maxAge - 50) { 96 | this.setAlpha((50 - (this.age - (this.maxAge - 50))) / 50F); 97 | } else { 98 | this.setAlpha(1.0F); 99 | } 100 | } 101 | 102 | public void setAge(int newAge) { 103 | this.age = newAge; 104 | } 105 | 106 | public void setVelocityX(double velX) { 107 | velocityX = velX; 108 | } 109 | 110 | public void setVelocityY(double velY) { 111 | velocityY = velY; 112 | } 113 | 114 | public void setVelocityZ(double velZ) { 115 | velocityZ = velZ; 116 | } 117 | 118 | public double getVelocityX() { 119 | return velocityX; 120 | } 121 | 122 | public double getVelocityY() { 123 | return velocityY; 124 | } 125 | 126 | public double getVelocityZ() { 127 | return velocityZ; 128 | } 129 | 130 | public double getX() { 131 | return x; 132 | } 133 | 134 | public double getY() { 135 | return y; 136 | } 137 | 138 | public double getZ() { 139 | return z; 140 | } 141 | public void setX(double x) { 142 | this.prevPosX = x; 143 | this.x = x; 144 | } 145 | public void setZ(double z) { 146 | this.prevPosZ = z; 147 | this.z = z; 148 | } 149 | 150 | public void addVelocity(double x, double y, double z) { 151 | this.velocityX += x; 152 | this.velocityY += y; 153 | this.velocityZ += z; 154 | } 155 | 156 | public void setScale(float s) { 157 | this.scale = s*0.15F; 158 | } 159 | 160 | public int getAge() { 161 | return age; 162 | } 163 | 164 | public record DefaultFactory(SpriteProvider provider) implements ParticleFactory { 165 | @Override 166 | public Particle createParticle(DefaultParticleType parameters, ClientWorld world, double x, double y, double z, double r, double g, double b) { 167 | return new TornadoParticle(world, x, y, z, r, g, b, provider); 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/client/java/sh/talonfloof/enhancedweather/screen/RadarScreen.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.screen; 2 | 3 | import net.minecraft.client.MinecraftClient; 4 | import net.minecraft.client.gui.DrawContext; 5 | import net.minecraft.client.gui.screen.Screen; 6 | import net.minecraft.sound.SoundCategory; 7 | import net.minecraft.sound.SoundEvent; 8 | import net.minecraft.sound.SoundEvents; 9 | import net.minecraft.text.Text; 10 | import net.minecraft.util.Identifier; 11 | import net.minecraft.util.math.BlockPos; 12 | import net.minecraft.util.math.MathHelper; 13 | import net.minecraft.util.math.Vec3d; 14 | import sh.talonfloof.enhancedweather.CloudRenderManager; 15 | import sh.talonfloof.enhancedweather.EnhancedWeatherClient; 16 | import sh.talonfloof.enhancedweather.api.EnhancedWeatherAPI; 17 | import sh.talonfloof.enhancedweather.events.WeatherEvent; 18 | import sh.talonfloof.enhancedweather.network.SuppressAlert; 19 | 20 | import java.util.UUID; 21 | import java.util.function.BiConsumer; 22 | 23 | import static sh.talonfloof.enhancedweather.block.RadarBlock.LIGHT; 24 | 25 | public class RadarScreen extends Screen { 26 | private BlockPos pos; 27 | private boolean alert = false; 28 | private boolean alertPressed = false; 29 | private static final Identifier TORNADO_SYMBOL = new Identifier("enhancedweather","textures/gui/tornado_symbol.png"); 30 | private static final Identifier RADAR_ALERT_LIGHT = new Identifier("enhancedweather","textures/gui/radar_alert_light.png"); 31 | private static final Identifier RADAR_BG = new Identifier("enhancedweather","textures/gui/radar.png"); 32 | public RadarScreen(BlockPos pos) { 33 | super(Text.literal("Radar Screen")); 34 | this.pos = pos; 35 | alert = MinecraftClient.getInstance().world.getBlockState(pos).get(LIGHT); 36 | } 37 | 38 | @Override 39 | public boolean shouldPause() { 40 | return false; 41 | } 42 | 43 | protected void castLine(int x1, int y1, int x2, int y2, BiConsumer func) { 44 | if(Math.abs(y2-y1) < Math.abs(x2-x1)) { 45 | if(x1 > x2) { 46 | lineCastLow(x2,y2,x1,y1,func); 47 | } else { 48 | lineCastLow(x1,y1,x2,y2,func); 49 | } 50 | } else { 51 | if(y1 > y2) { 52 | lineCastHigh(x2,y2,x1,y1,func); 53 | } else { 54 | lineCastHigh(x1,y1,x2,y2,func); 55 | } 56 | } 57 | } 58 | protected void lineCastLow(int x1, int y1, int x2, int y2, BiConsumer func) { 59 | var dx = x2 - x1; 60 | var dy = y2 - y1; 61 | var yi = 1; 62 | if(dy < 0) { 63 | yi = -1; 64 | dy = -dy; 65 | } 66 | var D = (2 * dy) - dx; 67 | var y = y1; 68 | for(int x=x1; x < x2; x++) { 69 | func.accept(x,y); 70 | if(D > 0) { 71 | y += yi; 72 | D += (2 * (dy - dx)); 73 | } else { 74 | D += 2*dy; 75 | } 76 | } 77 | } 78 | protected void lineCastHigh(int x1, int y1, int x2, int y2, BiConsumer func) { 79 | var dx = x2 - x1; 80 | var dy = y2 - y1; 81 | var xi = 1; 82 | if(dx < 0) { 83 | xi = -1; 84 | dx = -dx; 85 | } 86 | var D = (2 * dx) - dy; 87 | var x = x1; 88 | for(int y=y1; y < y2; y++) { 89 | func.accept(x,y); 90 | if(D > 0) { 91 | x += xi; 92 | D += (2 * (dx - dy)); 93 | } else { 94 | D += 2*dx; 95 | } 96 | } 97 | } 98 | 99 | @Override 100 | public boolean mouseClicked(double mouseX, double mouseY, int button) { 101 | double x = (this.width/2F)-((double) (128 * 2) /2)+(7*2); 102 | double y = (this.height/2F)-((double) (128 * 2) /2)+(113*2); 103 | if(mouseX >= x && mouseX <= x+16 && mouseY >= y && mouseY <= y+16) { 104 | alertPressed = true; 105 | MinecraftClient.getInstance().player.playSound(SoundEvents.UI_BUTTON_CLICK.value(), SoundCategory.MASTER, 0.25F, 2.0F); 106 | } 107 | return true; 108 | } 109 | 110 | @Override 111 | public boolean mouseReleased(double mouseX, double mouseY, int button) { 112 | double x = (this.width/2F)-((double) (128 * 2) /2)+(7*2); 113 | double y = (this.height/2F)-((double) (128 * 2) /2)+(113*2); 114 | if(mouseX >= x && mouseX <= x+16 && mouseY >= y && mouseY <= y+16 && alertPressed) { 115 | MinecraftClient.getInstance().player.playSound(SoundEvents.UI_BUTTON_CLICK.value(), SoundCategory.MASTER, 0.25F, 1.5F); 116 | SuppressAlert.send(pos); 117 | alert = false; 118 | } 119 | alertPressed = false; 120 | return true; 121 | } 122 | 123 | @Override 124 | public void render(DrawContext context, int mouseX, int mouseY, float delta) { 125 | MinecraftClient client = MinecraftClient.getInstance(); 126 | int chunkX = Math.floorDiv(pos.getX(),32); 127 | int chunkZ = Math.floorDiv(pos.getZ(),32); 128 | int[] rainColors = { 129 | 0x000000, 130 | 0x008C4D, 131 | 0x01A532, 132 | 0x00CF1C, 133 | 0x0FF114, 134 | 0x7FFE21, 135 | 0xFFF20E, 136 | }; 137 | int[] hailColors = { 138 | 0xFE7C00, 139 | 0xF93801, 140 | 0xDA061D, 141 | 0xDC009E, 142 | 0xFF00FE, 143 | }; 144 | int[] thunderColors = { 145 | 0xFFD300, 146 | 0xFFAB00, 147 | 0xFE7C00, 148 | 0xF93801, 149 | 0xDA061D, 150 | }; 151 | context.getMatrices().push(); 152 | context.getMatrices().translate(context.getScaledWindowWidth()/2F,context.getScaledWindowHeight()/2F,0); 153 | context.drawTexture(RADAR_BG,-((128*2)/2),-((128*2)/2),128*2,128*2,0,0,128,128,128,128); 154 | if(alert) 155 | context.drawTexture( RADAR_ALERT_LIGHT,-((128*2)/2)+(7*2),-((128*2)/2)+(113*2),16,16,0,0,8,8,8,8); 156 | if(alertPressed) 157 | context.fill(-((128*2)/2)+(7*2),-((128*2)/2)+(113*2),-((128*2)/2)+(7*2)+16,-((128*2)/2)+(113*2)+16,0x4f000000); 158 | context.getMatrices().translate(-5,-2,0); 159 | for(int x=-32; x < 32;x++) { 160 | for(int z=-32;z < 32;z++) { 161 | if(Math.pow(x,2)+Math.pow(z,2) < Math.pow(32,2)) { 162 | int finalX = ((chunkX * 32) + (x * 32)) - MathHelper.floor(CloudRenderManager.cloudX); 163 | int finalZ = ((chunkZ * 32) + (z * 32)) - MathHelper.floor(CloudRenderManager.cloudZ); 164 | int front = Math.round((Math.max(0, EnhancedWeatherAPI.sampleFrontClient(finalX, finalZ, 0.1) - 0.2F) / 0.8F) * 6); 165 | 166 | if (chunkX + x == chunkX && chunkZ + z == chunkZ) { 167 | context.fill(x * 3, z * 3, (x * 3) + 3, (z * 3) + 3, 0xffffffff); 168 | } else { 169 | if (EnhancedWeatherAPI.sampleFrontClient(finalX, finalZ, 0.1) >= 0.2F && EnhancedWeatherAPI.sampleThunderstorm(0, finalX, finalZ, 0.05) > 0.3) { 170 | front = Math.round((Math.max(0, EnhancedWeatherAPI.sampleThunderstorm(0, finalX, finalZ, 0.05) - 0.3F) / 0.7F) * 4); 171 | if (EnhancedWeatherClient.windSpeed >= 50F) { 172 | context.fill(x * 3, z * 3, (x * 3) + 3, (z * 3) + 3, hailColors[front] | 0xff000000); 173 | } else { 174 | context.fill(x * 3, z * 3, (x * 3) + 3, (z * 3) + 3, thunderColors[front] | 0xff000000); 175 | } 176 | } else { 177 | if(front > 0) { 178 | context.fill(x * 3, z * 3, (x * 3) + 3, (z * 3) + 3, rainColors[front] | 0xff000000); 179 | } 180 | } 181 | } 182 | } 183 | } 184 | } 185 | for(UUID id : EnhancedWeatherClient.clientEvents.keySet()) { 186 | WeatherEvent w = EnhancedWeatherClient.clientEvents.get(id); 187 | Vec3d ourPos = new Vec3d(pos.getX(),w.position.y,pos.getZ()); 188 | if(w.position.distanceTo(ourPos) < 1024) { 189 | context.drawTexture(TORNADO_SYMBOL,(int)((w.position.x-ourPos.x)/32)*3-8,(int)((w.position.z-ourPos.z)/32)*3-8,16,16,0,0,128,128,128,128); 190 | } 191 | } 192 | for(int x=-32; x < 32;x++) { 193 | for (int z = -32; z < 32; z++) { 194 | double v = Math.pow(x, 2) + Math.pow(z, 2); 195 | if ((v <= Math.pow(8, 2) && v >= Math.pow(7,2)) || (v <= Math.pow(16, 2) && v >= Math.pow(15,2)) || (v <= Math.pow(24, 2) && v >= Math.pow(23,2))) { 196 | context.fill(x * 3, z * 3, (x * 3) + 3, (z * 3) + 3, 0x80ffffff); 197 | } 198 | } 199 | } 200 | long ticks = client.world.getTime(); 201 | for(int i=0; i < 5; i++) { 202 | double angle = (((double)((ticks-i)+delta) % 360) / 360) * 360D; 203 | final float val = i/5F; 204 | castLine(0, 0, -(int)Math.round(Math.sin(Math.toRadians(angle)) * 32), (int)Math.round(Math.cos(Math.toRadians(angle)) * 32), (x, y) -> { 205 | context.fill(x * 3, y * 3, (x * 3) + 3, (y * 3) + 3, (MathHelper.lerp(val,255,0) << 24)| 0xFFFFFF); 206 | }); 207 | } 208 | double a = -Math.toDegrees(Math.atan2(EnhancedWeatherClient.windZ,EnhancedWeatherClient.windX))-90; 209 | int baseX = -((128*2)/2)+(16*2); 210 | int baseY = -((128*2)/2)+(16*2); 211 | for(int x=-12; x < 12;x++) { 212 | for (int z = -12; z < 12; z++) { 213 | if (Math.pow(x, 2) + Math.pow(z, 2) < Math.pow(12, 2)) { 214 | context.fill(baseX+(x * 2), baseY+(z * 2), baseX+((x * 2) + 2), baseY+((z * 2) + 2), 0xff121214); 215 | } 216 | } 217 | } 218 | castLine(0, 0, -(int)Math.round(Math.sin(Math.toRadians(a)) * 8), -(int)Math.round(Math.cos(Math.toRadians(a)) * 8), (x, y) -> { 219 | context.fill(baseX+(x * 3), baseY+(y * 3), baseX+((x * 3) + 3), baseY+((y * 3) + 3), 0xFFFFFFFF); 220 | }); 221 | String s = ((int)Math.floor(EnhancedWeatherClient.windSpeed))+" km/h"; 222 | context.drawText(this.textRenderer,s,baseX-(this.textRenderer.getWidth(s)/2),baseY+(12*2),0xffffffff,false); 223 | context.getMatrices().pop(); 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /src/client/resources/enhancedweather.client.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "sh.talonfloof.enhancedweather.mixin.client", 4 | "compatibilityLevel": "JAVA_17", 5 | "client": [ 6 | "BackgroundRendererMixin", 7 | "CherryLeavesParticleMixin", 8 | "MixinParticle", 9 | "ParticleManagerMixin", 10 | "WorldClientMixin", 11 | "WorldRendererMixin" 12 | ], 13 | "injectors": { 14 | "defaultRequire": 1 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/EnhancedWeather.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather; 2 | 3 | import blue.endless.jankson.Jankson; 4 | import blue.endless.jankson.JsonObject; 5 | import blue.endless.jankson.JsonPrimitive; 6 | import net.fabricmc.api.ModInitializer; 7 | 8 | import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; 9 | import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; 10 | import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents; 11 | import net.fabricmc.fabric.api.networking.v1.PlayerLookup; 12 | import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; 13 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 14 | import net.fabricmc.fabric.api.particle.v1.FabricParticleTypes; 15 | import net.minecraft.particle.DefaultParticleType; 16 | import net.minecraft.registry.Registries; 17 | import net.minecraft.registry.Registry; 18 | import net.minecraft.server.MinecraftServer; 19 | import net.minecraft.server.network.ServerPlayerEntity; 20 | import net.minecraft.util.Identifier; 21 | import net.minecraft.util.WorldSavePath; 22 | import net.minecraft.util.math.BlockPos; 23 | import net.minecraft.util.math.MathHelper; 24 | import net.minecraft.util.math.Vec3d; 25 | import net.minecraft.util.math.random.Random; 26 | import net.minecraft.world.dimension.DimensionTypes; 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | import sh.talonfloof.enhancedweather.api.EnhancedWeatherAPI; 30 | import sh.talonfloof.enhancedweather.block.BlockRegistry; 31 | import sh.talonfloof.enhancedweather.commands.SpawnTornadoCommand; 32 | import sh.talonfloof.enhancedweather.config.EnhancedWeatherConfig; 33 | import sh.talonfloof.enhancedweather.events.Tornado; 34 | import sh.talonfloof.enhancedweather.events.WeatherEvent; 35 | import sh.talonfloof.enhancedweather.network.SuppressAlertServer; 36 | import sh.talonfloof.enhancedweather.network.UpdateConditions; 37 | import sh.talonfloof.enhancedweather.network.UpdateEvent; 38 | 39 | import java.io.File; 40 | import java.io.FileWriter; 41 | import java.util.HashMap; 42 | import java.util.UUID; 43 | 44 | public class EnhancedWeather implements ModInitializer { 45 | // This logger is used to write text to the console and the log file. 46 | // It is considered best practice to use your mod id as the logger's name. 47 | // That way, it's clear which mod wrote info, warnings, and errors. 48 | public static final Logger LOGGER = LoggerFactory.getLogger("enhancedweather"); 49 | public static final int WEATHER_DATA_VERSION = 202402001; 50 | public static final EnhancedWeatherConfig CONFIG = EnhancedWeatherConfig.createAndLoad(); 51 | public static final DefaultParticleType EW_RAIN = FabricParticleTypes.simple(true); 52 | public static final DefaultParticleType EW_SNOW = FabricParticleTypes.simple(true); 53 | public static final DefaultParticleType EW_HAIL = FabricParticleTypes.simple(true); 54 | public static final DefaultParticleType EW_TORNADO = FabricParticleTypes.simple(true); 55 | public static long noiseTick = 0; 56 | public static double cloudX = 0; 57 | public static double cloudZ = 0; 58 | public static HashMap events = new HashMap<>(); 59 | 60 | public boolean load(MinecraftServer server) { 61 | new File(server.getSavePath(WorldSavePath.ROOT).toAbsolutePath() + "/enhancedweather/Clouds_DIM0.json5").delete(); 62 | File file = new File(server.getSavePath(WorldSavePath.ROOT).toAbsolutePath() + "/enhancedweather/Weather_DIM0.json5"); 63 | if(file.exists() && file.isFile()) { 64 | try { 65 | JsonObject jsonObject = Jankson.builder().build().load(file); 66 | if (jsonObject.getLong("DataFormat", 0L) != EnhancedWeather.WEATHER_DATA_VERSION) { 67 | return false; 68 | } 69 | cloudX = jsonObject.getDouble("cloudX",0); 70 | cloudZ = jsonObject.getDouble("cloudZ",0); 71 | WindManager.windAngle = jsonObject.getFloat("windAngle",0F); 72 | WindManager.windSpeed = jsonObject.getFloat("windSpeed",0F); 73 | WindManager.lowWindTimer = jsonObject.getInt("lowWindTimer",0); 74 | WindManager.highWindTimer = jsonObject.getInt("highWindTimer",0); 75 | JsonObject events = jsonObject.getObject("events"); 76 | for(String id : events.keySet()) { 77 | JsonObject eventData = events.getObject(id); 78 | if(eventData.get(String.class,"id").equals("enhancedweather:tornado")) { 79 | Tornado t = new Tornado(0,0,0,0); 80 | t.loadSaveData(eventData); 81 | EnhancedWeather.events.put(UUID.fromString(id),t); 82 | } 83 | } 84 | } catch (Exception e) { 85 | EnhancedWeather.LOGGER.error("Failed to load Weather Data"); 86 | EnhancedWeather.LOGGER.error("Reason: "+e.toString()); 87 | return false; 88 | } 89 | return true; 90 | } 91 | return false; 92 | } 93 | 94 | public static void save(MinecraftServer server) { 95 | JsonObject jsonObject = new JsonObject(); 96 | JsonObject eventObject = new JsonObject(); 97 | jsonObject.put("DataFormat",new JsonPrimitive(EnhancedWeather.WEATHER_DATA_VERSION)); 98 | jsonObject.put("cloudX",new JsonPrimitive(cloudX)); 99 | jsonObject.put("cloudZ",new JsonPrimitive(cloudZ)); 100 | jsonObject.put("windAngle",new JsonPrimitive(WindManager.windAngle)); 101 | jsonObject.put("windSpeed",new JsonPrimitive(WindManager.windSpeed)); 102 | jsonObject.put("lowWindTimer",new JsonPrimitive(WindManager.lowWindTimer)); 103 | jsonObject.put("highWindTimer",new JsonPrimitive(WindManager.highWindTimer)); 104 | for(UUID id : EnhancedWeather.events.keySet()) { 105 | WeatherEvent e = EnhancedWeather.events.get(id); 106 | eventObject.put(id.toString(),e.generateSaveData()); 107 | } 108 | jsonObject.put("events",eventObject); 109 | String data = jsonObject.toJson(true,true); 110 | File file = new File(server.getSavePath(WorldSavePath.ROOT).toAbsolutePath() + "/enhancedweather/Weather_DIM0.json5"); 111 | try { 112 | new File(file.getParent()).mkdir(); 113 | file.delete(); 114 | file.createNewFile(); 115 | FileWriter stream = new FileWriter(file); 116 | stream.write(data); 117 | stream.close(); 118 | } catch (Exception e) { 119 | EnhancedWeather.LOGGER.error("Failed to save Weather Data"); 120 | EnhancedWeather.LOGGER.error("Reason: "+e.toString()); 121 | } 122 | } 123 | 124 | @Override 125 | public void onInitialize() { 126 | Registry.register(Registries.PARTICLE_TYPE, new Identifier("enhancedweather", "rain"), EW_RAIN); 127 | Registry.register(Registries.PARTICLE_TYPE, new Identifier("enhancedweather", "snow"), EW_SNOW); 128 | Registry.register(Registries.PARTICLE_TYPE, new Identifier("enhancedweather", "hail"), EW_HAIL); 129 | Registry.register(Registries.PARTICLE_TYPE, new Identifier("enhancedweather", "tornado"), EW_TORNADO); 130 | ServerPlayNetworking.registerGlobalReceiver(SuppressAlertServer.PACKET_ID,SuppressAlertServer::onReceive); 131 | BlockRegistry.register(); 132 | SpawnTornadoCommand.register(); 133 | ServerWorldEvents.LOAD.register((server, world) -> { 134 | if(world.getDimensionKey().equals(DimensionTypes.OVERWORLD)) { 135 | events.clear(); 136 | if (!load(server)) { 137 | EnhancedWeather.LOGGER.info("No data was found, generating initial values"); 138 | WindManager.reset(); 139 | Random r = Random.create(); 140 | cloudX = r.nextBetween(-16777216, 16777216); 141 | cloudZ = r.nextBetween(-16777216, 16777216); 142 | EnhancedWeather.LOGGER.info("Starting cloud position will be: X={},Z={}", cloudX, cloudZ); 143 | } else { 144 | EnhancedWeather.LOGGER.info("Loaded Weather Data successfully"); 145 | } 146 | } 147 | }); 148 | ServerTickEvents.START_WORLD_TICK.register((world) -> { 149 | if(world.getDimensionKey().equals(DimensionTypes.OVERWORLD)) { 150 | if(events.size() < world.getServer().getCurrentPlayerCount()) { 151 | for (ServerPlayerEntity player : PlayerLookup.all(world.getServer())) { 152 | BlockPos pos = player.getBlockPos(); 153 | Random r = Random.create(); 154 | pos = pos.add(r.nextBetween(-1024, 1024), 0, r.nextBetween(-1024, 1024)); 155 | if (EnhancedWeatherAPI.isThundering(world, 0, pos.getX() - MathHelper.floor(cloudX), pos.getZ() - MathHelper.floor(cloudZ)) && WindManager.windSpeed >= CONFIG.Weather_TornadoMinimumWind()) { 156 | if(EnhancedWeather.CONFIG.Weather_TornadoSpawnChance() > 0) { 157 | if (r.nextInt(EnhancedWeather.CONFIG.Weather_TornadoSpawnChance()) == 0) { 158 | Tornado t = new Tornado(pos.getX(), 192, pos.getZ(), r.nextInt(3)); 159 | events.put(UUID.randomUUID(), t); 160 | } 161 | } 162 | } 163 | } 164 | } 165 | UUID[] ids = events.keySet().toArray(new UUID[0]); 166 | for(int i=0; i < ids.length; i++) { 167 | WeatherEvent e = events.get(ids[i]); 168 | if(e instanceof Tornado) { 169 | if(WindManager.windSpeed < EnhancedWeather.CONFIG.Weather_TornadoMinimumWind()) { 170 | for (ServerPlayerEntity player : PlayerLookup.all(world.getServer())) { 171 | UpdateEvent.send(world.getServer(),ids[i],null,player); 172 | } 173 | events.remove(ids[i]); 174 | } else { 175 | var col = PlayerLookup.around(world.getServer().getOverworld(), new Vec3d(e.position.x, 50, e.position.z), 1024.0D); 176 | if (col.isEmpty()) { 177 | if(!(!world.getServer().isDedicated() && world.getServer().getCurrentPlayerCount() == 0)) { 178 | for (ServerPlayerEntity player : PlayerLookup.all(world.getServer())) { 179 | UpdateEvent.send(world.getServer(), ids[i], null, player); 180 | } 181 | events.remove(ids[i]); 182 | } 183 | } else { 184 | ((Tornado) e).tickServer(); 185 | } 186 | } 187 | } 188 | } 189 | world.setRainGradient(0F); 190 | world.setThunderGradient(0F); 191 | noiseTick += 1; 192 | WindManager.tick(); 193 | float windX = (float)-Math.sin(Math.toRadians(WindManager.windAngle))*(WindManager.windSpeed/25F); 194 | float windZ = (float)Math.cos(Math.toRadians(WindManager.windAngle))*(WindManager.windSpeed/25F); 195 | float moveX = (float)-Math.sin(Math.toRadians(WindManager.windAngle))*Math.min(1.5F,WindManager.windSpeed/25F); 196 | float moveZ = (float)Math.cos(Math.toRadians(WindManager.windAngle))*Math.min(1.5F,WindManager.windSpeed/25F); 197 | cloudX += (moveX * 0.002) * 32; 198 | cloudZ += (moveZ * 0.002) * 32; 199 | if (noiseTick % 20 == 0) { 200 | for (ServerPlayerEntity player : PlayerLookup.all(world.getServer())) { 201 | UpdateConditions.send(world.getServer(), player, windX, windZ, cloudX, cloudZ); 202 | for(UUID id : events.keySet()) { 203 | UpdateEvent.send(world.getServer(),id,events.get(id).generateUpdate(),player); 204 | } 205 | } 206 | } 207 | } 208 | }); 209 | ServerLifecycleEvents.SERVER_STOPPING.register((server) -> { 210 | EnhancedWeather.LOGGER.info("Flushing data since server stop was triggered..."); 211 | save(server); 212 | }); 213 | } 214 | } -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/WindManager.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather; 2 | 3 | import net.minecraft.util.math.random.Random; 4 | import sh.talonfloof.enhancedweather.config.EnhancedWeatherConfig; 5 | 6 | public class WindManager { 7 | public static float windAngle = 0; 8 | public static float windSpeed = 0; 9 | public static float windSpeedChangeRate = 0.05F; 10 | public static int windSpeedRandChangeTimer = 0; 11 | public static int windSpeedRandChangeDelay = 10; 12 | public static int lowWindTimer = 0; 13 | public static int highWindTimer = 0; 14 | public static void reset() { 15 | Random rand = Random.create(); 16 | windAngle = rand.nextInt(360)-180; 17 | windSpeed = rand.nextInt(45); 18 | windSpeedRandChangeTimer = windSpeedRandChangeDelay; 19 | lowWindTimer = 0; 20 | highWindTimer = 0; 21 | } 22 | 23 | public static void tick() { 24 | Random rand = Random.create(); 25 | if (lowWindTimer <= 0) { 26 | if (windSpeedRandChangeTimer-- <= 0) { 27 | if (highWindTimer <= 0) 28 | windSpeed += (rand.nextDouble() * windSpeedChangeRate) - (windSpeedChangeRate / 2); 29 | else 30 | windSpeed += (rand.nextDouble() * windSpeedChangeRate); 31 | windSpeedRandChangeTimer = windSpeedRandChangeDelay; 32 | if (highWindTimer <= 0) 33 | if (rand.nextInt(EnhancedWeather.CONFIG.Wind_LowWindChance()) == 0) { 34 | lowWindTimer = EnhancedWeather.CONFIG.Wind_LowWindBaseTime() + rand.nextInt(EnhancedWeather.CONFIG.Wind_LowWindExtraTime()); 35 | EnhancedWeather.LOGGER.info("Low Wind for {} ticks", lowWindTimer); 36 | } else 37 | lowWindTimer = 0; 38 | if (highWindTimer <= 0) 39 | if (rand.nextInt(EnhancedWeather.CONFIG.Wind_HighWindChance()) == 0) { 40 | highWindTimer = EnhancedWeather.CONFIG.Wind_HighWindBaseTime() + rand.nextInt(EnhancedWeather.CONFIG.Wind_HighWindExtraTime()); 41 | EnhancedWeather.LOGGER.info("High Wind for {} ticks", highWindTimer); 42 | } 43 | } 44 | } else { 45 | lowWindTimer--; 46 | if(windSpeed > EnhancedWeather.CONFIG.Wind_LowWindThreshold()) { 47 | windSpeed -= 0.01F; 48 | } 49 | } 50 | if (highWindTimer > 0) { 51 | highWindTimer--; 52 | } 53 | windAngle += (rand.nextFloat()) - (rand.nextFloat()); 54 | if(windAngle < -180) 55 | windAngle += 360; 56 | if(windAngle > 180) 57 | windAngle -= 360; 58 | if (windSpeed < 0.00001F) 59 | windSpeed = 0.00001F; 60 | if (windSpeed > 100F) 61 | windSpeed = 100F; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/api/EnhancedWeatherAPI.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.api; 2 | 3 | import net.fabricmc.api.EnvType; 4 | import net.fabricmc.api.Environment; 5 | import net.minecraft.util.math.MathHelper; 6 | import net.minecraft.util.math.Vec2f; 7 | import net.minecraft.world.World; 8 | import sh.talonfloof.enhancedweather.EnhancedWeather; 9 | import sh.talonfloof.enhancedweather.config.EnhancedWeatherConfig; 10 | import sh.talonfloof.enhancedweather.util.ImageSampler; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class EnhancedWeatherAPI { 16 | private static final ImageSampler FRONT_SAMPLE = new ImageSampler("data/enhancedweather/clouds/rain_fronts.png"); 17 | private static final ImageSampler MAIN_SHAPE_SAMPLE = new ImageSampler("data/enhancedweather/clouds/main_shape.png"); 18 | private static final ImageSampler LARGE_DETAILS_SAMPLE = new ImageSampler("data/enhancedweather/clouds/large_details.png"); 19 | private static final ImageSampler VARIATION_SAMPLE = new ImageSampler("data/enhancedweather/clouds/variation.png"); 20 | private static final ImageSampler RAIN_DENSITY = new ImageSampler("data/enhancedweather/clouds/rain_density.png"); 21 | private static final ImageSampler THUNDERSTORMS = new ImageSampler("data/enhancedweather/clouds/thunderstorms.png"); 22 | private static final float[] CLOUD_SHAPE = new float[64]; 23 | private static final Vec2f[] OFFSETS; 24 | 25 | public static float sampleThunderstorm(float windSpeed, int x, int z, double scale) { 26 | return windSpeed >= 50F ? 1F : THUNDERSTORMS.sample(x * scale, z * scale); 27 | } 28 | 29 | public static boolean isRaining(World world, int x, int z) { 30 | float rainFront = sampleFront(x, z, 0.1); 31 | if (rainFront < 0.2F) return false; 32 | 33 | return true; 34 | } 35 | 36 | public static boolean isThundering(World world, float windSpeed, int x, int z) { 37 | return isRaining(world, x, z) && sampleThunderstorm(windSpeed, x, z, 0.05) > 0.3F; 38 | } 39 | 40 | public static boolean isRainingClient(World world, int x, int z) { 41 | float rainFront = sampleFrontClient(x, z, 0.1); 42 | if (rainFront < 0.2F) return false; 43 | 44 | return true; 45 | } 46 | 47 | public static boolean isThunderingClient(World world, float windSpeed, int x, int z) { 48 | return isRainingClient(world, x, z) && sampleThunderstorm(windSpeed, x, z, 0.05) > 0.3F; 49 | } 50 | 51 | public static float getCoverage(float rainFront) { 52 | return MathHelper.lerp(MathHelper.clamp(rainFront,0,1), 1.3F, 0.5F); 53 | } 54 | 55 | public static float getCloudDensity(int x, int y, int z, float rainFront) { 56 | 57 | 58 | float density = MAIN_SHAPE_SAMPLE.sample(x * 0.75F, z * 0.75F); 59 | density += LARGE_DETAILS_SAMPLE.sample(x * 2.5F, z * 2.5F); 60 | 61 | density -= VARIATION_SAMPLE.sample(y * 2.5F, x * 2.5F) * 0.05F; 62 | density -= VARIATION_SAMPLE.sample(z * 2.5F, y * 2.5F) * 0.05F; 63 | density -= VARIATION_SAMPLE.sample(z * 2.5F, x * 2.5F) * 0.05F; 64 | 65 | int value = (int) (MathHelper.hashCode(x, y, z) % 3); 66 | density -= value * 0.01F; 67 | 68 | float density1 = density - CLOUD_SHAPE[MathHelper.clamp(y << 1, 0, 63)]; 69 | float density2 = density + MAIN_SHAPE_SAMPLE.sample(x * 1.5F, z * 1.5F) - CLOUD_SHAPE[MathHelper.clamp(y, 0, 63)] * 3F; 70 | 71 | return MathHelper.lerp(rainFront, density1, density2); 72 | } 73 | 74 | public static float sampleFront(int x, int z, double scale) { 75 | float front = FRONT_SAMPLE.sample(x * scale, z * scale); 76 | if(EnhancedWeather.CONFIG.Weather_ReducedRainFronts()) { 77 | scale *= 0.7; 78 | front *= RAIN_DENSITY.sample(x * scale, z * scale); 79 | } 80 | return front; 81 | } 82 | 83 | @Environment(EnvType.CLIENT) 84 | public static float sampleFrontClient(int x, int z, double scale) { 85 | float front = FRONT_SAMPLE.sample(x * scale, z * scale); 86 | if(EnhancedWeather.CONFIG.Weather_ReducedRainFronts()) { 87 | scale *= 0.7; 88 | front *= RAIN_DENSITY.sample(x * scale, z * scale); 89 | } 90 | return front; 91 | } 92 | 93 | static { 94 | for (byte i = 0; i < 16; i++) { 95 | CLOUD_SHAPE[i] = (16 - i) / 16F; 96 | CLOUD_SHAPE[i] *= CLOUD_SHAPE[i]; 97 | } 98 | for (byte i = 16; i < 64; i++) { 99 | CLOUD_SHAPE[i] = (i - 16) / 48F; 100 | CLOUD_SHAPE[i] *= CLOUD_SHAPE[i]; 101 | } 102 | 103 | int radius = 6; 104 | int capacity = radius * 2 + 1; 105 | capacity *= capacity; 106 | 107 | List offsets = new ArrayList<>(capacity); 108 | for (int x = -radius; x <= radius; x++) { 109 | for (int z = -radius; z <= radius; z++) { 110 | if (x * x + z * z <= radius * radius) { 111 | offsets.add(new Vec2f(x, z)); 112 | } 113 | } 114 | } 115 | offsets.sort((v1, v2) -> { 116 | int d1 = (int)v1.x * (int)v1.x + (int)v1.y * (int)v1.y; 117 | int d2 = (int)v2.x * (int)v2.x + (int)v2.y * (int)v2.y; 118 | return Integer.compare(d1, d2); 119 | }); 120 | OFFSETS = offsets.toArray(Vec2f[]::new); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/block/BlockRegistry.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.block; 2 | 3 | import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents; 4 | import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; 5 | import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; 6 | import net.minecraft.block.Block; 7 | import net.minecraft.block.entity.BlockEntityType; 8 | import net.minecraft.item.BlockItem; 9 | import net.minecraft.item.Item; 10 | import net.minecraft.item.ItemGroups; 11 | import net.minecraft.registry.Registries; 12 | import net.minecraft.registry.Registry; 13 | import net.minecraft.sound.BlockSoundGroup; 14 | import net.minecraft.util.Identifier; 15 | 16 | public class BlockRegistry { 17 | public static final Block RADAR_BLOCK = new RadarBlock(FabricBlockSettings.create().requiresTool().strength(2.0f).sounds(BlockSoundGroup.NETHERITE)); 18 | public static final BlockItem RADAR_BLOCK_ITEM = new BlockItem(RADAR_BLOCK, new Item.Settings()); 19 | public static BlockEntityType RADAR_BLOCK_ENTITY; 20 | public static void register() { 21 | Registry.register(Registries.BLOCK, new Identifier("enhancedweather","radar"), RADAR_BLOCK); 22 | Registry.register(Registries.ITEM, new Identifier("enhancedweather","radar"), RADAR_BLOCK_ITEM); 23 | RADAR_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, "enhancedweather:radar", FabricBlockEntityTypeBuilder.create(RadarBlockEntity::new, RADAR_BLOCK).build(null)); 24 | ItemGroupEvents.modifyEntriesEvent(ItemGroups.FUNCTIONAL).register(content -> { 25 | content.add(RADAR_BLOCK_ITEM); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/block/RadarBlock.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.block; 2 | 3 | import com.mojang.serialization.MapCodec; 4 | import net.minecraft.block.*; 5 | import net.minecraft.block.entity.BlockEntity; 6 | import net.minecraft.block.entity.BlockEntityTicker; 7 | import net.minecraft.block.entity.BlockEntityType; 8 | import net.minecraft.entity.player.PlayerEntity; 9 | import net.minecraft.item.ItemPlacementContext; 10 | import net.minecraft.server.network.ServerPlayerEntity; 11 | import net.minecraft.state.StateManager; 12 | import net.minecraft.state.property.BooleanProperty; 13 | import net.minecraft.state.property.Properties; 14 | import net.minecraft.util.ActionResult; 15 | import net.minecraft.util.Hand; 16 | import net.minecraft.util.hit.BlockHitResult; 17 | import net.minecraft.util.math.BlockPos; 18 | import net.minecraft.util.math.Direction; 19 | import net.minecraft.world.World; 20 | import org.jetbrains.annotations.Nullable; 21 | import sh.talonfloof.enhancedweather.network.ScreenOpen; 22 | 23 | public class RadarBlock extends BlockWithEntity implements BlockEntityProvider { 24 | public static final MapCodec CODEC = createCodec(RadarBlock::new); 25 | public static final BooleanProperty LIGHT = BooleanProperty.of("light"); 26 | public RadarBlock(Settings settings) { 27 | super(settings); 28 | setDefaultState(this.stateManager.getDefaultState().with(LIGHT,false).with(Properties.HORIZONTAL_FACING, Direction.NORTH)); 29 | } 30 | 31 | @Override 32 | protected MapCodec getCodec() { 33 | return CODEC; 34 | } 35 | 36 | @Override 37 | public BlockRenderType getRenderType(BlockState state) { 38 | return BlockRenderType.MODEL; 39 | } 40 | 41 | @Override 42 | protected void appendProperties(StateManager.Builder stateManager) { 43 | stateManager.add(LIGHT); 44 | stateManager.add(Properties.HORIZONTAL_FACING); 45 | } 46 | 47 | @Override 48 | public BlockState getPlacementState(ItemPlacementContext ctx) { 49 | return (BlockState)this.getDefaultState().with(LIGHT,false).with(Properties.HORIZONTAL_FACING, ctx.getHorizontalPlayerFacing().getOpposite()); 50 | } 51 | 52 | @Override 53 | public ActionResult onUse(BlockState blockState, World world, BlockPos blockPos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) { 54 | if(!world.isClient()) { 55 | ScreenOpen.send((ServerPlayerEntity)player,blockPos); 56 | } 57 | return ActionResult.SUCCESS; 58 | } 59 | 60 | @Nullable 61 | @Override 62 | public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { 63 | return new RadarBlockEntity(pos, state.with(LIGHT,false)); 64 | } 65 | 66 | @Override 67 | public BlockEntityTicker getTicker(World world, BlockState state, BlockEntityType type) { 68 | return validateTicker(type, BlockRegistry.RADAR_BLOCK_ENTITY, RadarBlockEntity::tick); 69 | } 70 | } -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/block/RadarBlockEntity.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.block; 2 | 3 | import net.minecraft.block.BlockState; 4 | import net.minecraft.block.entity.BlockEntity; 5 | import net.minecraft.block.entity.BlockEntityType; 6 | import net.minecraft.sound.SoundCategory; 7 | import net.minecraft.sound.SoundEvent; 8 | import net.minecraft.util.Identifier; 9 | import net.minecraft.util.math.BlockPos; 10 | import net.minecraft.util.math.Vec3d; 11 | import net.minecraft.world.World; 12 | import sh.talonfloof.enhancedweather.EnhancedWeather; 13 | import sh.talonfloof.enhancedweather.events.WeatherEvent; 14 | 15 | import java.util.UUID; 16 | 17 | import static sh.talonfloof.enhancedweather.block.RadarBlock.LIGHT; 18 | 19 | public class RadarBlockEntity extends BlockEntity { 20 | public int count = 0; 21 | public RadarBlockEntity(BlockPos pos, BlockState state) { 22 | super(BlockRegistry.RADAR_BLOCK_ENTITY, pos, state); 23 | } 24 | public static void tick(World world, BlockPos pos, BlockState state, RadarBlockEntity blockEntity) { 25 | if(world.isClient()) 26 | return; 27 | int newCount = 0; 28 | for(UUID id : EnhancedWeather.events.keySet()) { 29 | WeatherEvent w = EnhancedWeather.events.get(id); 30 | Vec3d ourPos = new Vec3d(pos.getX(),w.position.y,pos.getZ()); 31 | if(w.position.distanceTo(ourPos) < 2048) { 32 | newCount++; 33 | } 34 | } 35 | if(newCount > blockEntity.count && !state.get(LIGHT)) { 36 | world.setBlockState(pos, blockEntity.getCachedState().with(LIGHT, true)); 37 | world.playSound(null, pos, SoundEvent.of(new Identifier("enhancedweather:radar.beep")), SoundCategory.BLOCKS,1F,1.0F); 38 | } 39 | blockEntity.count = newCount; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/commands/SpawnTornadoCommand.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.commands; 2 | 3 | import com.mojang.brigadier.arguments.FloatArgumentType; 4 | import com.mojang.brigadier.arguments.IntegerArgumentType; 5 | import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; 6 | import net.minecraft.server.command.CommandManager; 7 | import net.minecraft.server.command.ServerCommandSource; 8 | import sh.talonfloof.enhancedweather.EnhancedWeather; 9 | import sh.talonfloof.enhancedweather.events.Tornado; 10 | 11 | import java.util.UUID; 12 | 13 | public class SpawnTornadoCommand { // Example: /wxtornadoevent -42 785.75 500 - =D 14 | public static void register() { 15 | CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> { 16 | dispatcher.register(CommandManager.literal("wxtornadoevent") 17 | .then(CommandManager.argument("x", FloatArgumentType.floatArg()) 18 | .then(CommandManager.argument("z", FloatArgumentType.floatArg()) 19 | .then(CommandManager.argument("intensityMax", IntegerArgumentType.integer()) 20 | .executes(context -> execute(context.getSource(), 21 | FloatArgumentType.getFloat(context, "x"), 22 | FloatArgumentType.getFloat(context, "z"), 23 | IntegerArgumentType.getInteger(context, "intensityMax") 24 | )))))); 25 | }); 26 | } 27 | 28 | private static int execute(ServerCommandSource source, float x, float z, int intensityMax) { 29 | Tornado t = new Tornado(x,192,z,intensityMax); 30 | EnhancedWeather.events.put(UUID.randomUUID(),t); 31 | return 1; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/config/EnhancedWeatherConfigModel.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.config; 2 | 3 | import io.wispforest.owo.config.Option; 4 | import io.wispforest.owo.config.annotation.*; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | @Modmenu(modId = "enhancedweather") 10 | @Config(name = "enhancedweather", wrapperName="EnhancedWeatherConfig") 11 | public class EnhancedWeatherConfigModel { 12 | @SectionHeader("client") 13 | //@Comment("We recommended disabling this if you're using shaders\n(Default: true)") 14 | public boolean Client_ParticleRain = true; 15 | //@Comment("We recommended disabling this if you're using shaders\n(Default: true)") 16 | public boolean Client_ShowRainbow = true; 17 | //@Comment("Changes the radius of clouds that are rendered\n(Default: 9)") 18 | @RangeConstraint(min=6,max=16) 19 | public int Client_CloudRadius = 9; 20 | public boolean Client_ParticlesMoveWithWind = true; 21 | 22 | @SectionHeader("weather") 23 | @Sync(value=Option.SyncMode.OVERRIDE_CLIENT) 24 | //@Comment("Enabling this reduces the amount of rain fronts\n(Default: false)") 25 | public boolean Weather_ReducedRainFronts = false; 26 | 27 | //@Comment("The minimum wind speed that tornadoes can spawn and exist in\n(Default: 50)") 28 | @RangeConstraint(min=0,max=100) 29 | public int Weather_TornadoMinimumWind = 50; 30 | 31 | //@Comment("The chance (1 in [number]) of a tornado spawning in the right conditions\n(Default: 100)") 32 | public int Weather_TornadoSpawnChance = 100; 33 | 34 | @SectionHeader("wind") 35 | //@Comment("The chance (1 in [number]) of a low wind event occurring\n(Default: 4000)") 36 | public int Wind_LowWindChance = 20*200; 37 | 38 | //@Comment("The chance (1 in [number]) of a high wind event occurring\n(Default: 8000)") 39 | public int Wind_HighWindChance = 20*400; 40 | 41 | //@Comment("Base Time (in ticks) that a low wind event will last\n(Default: 2400)") 42 | public int Wind_LowWindBaseTime = (20*60*2); 43 | 44 | //@Comment("Maximum extra time (in ticks) that a low wind event will last\n(Default: 12000)") 45 | public int Wind_LowWindExtraTime = 20*60*10; 46 | 47 | //@Comment("Base Time (in ticks) that a high wind event will last\n(Default: 2400)") 48 | public int Wind_HighWindBaseTime = (20*60*2); 49 | 50 | //@Comment("Maximum extra time (in ticks) that a high wind event will last\n(Default: 12000)") 51 | public int Wind_HighWindExtraTime = 20*60*10; 52 | 53 | //@Comment("The lowest wind speed that a low wind event will drop to\n(Default: 5)") 54 | @RangeConstraint(min=0,max=100) 55 | public int Wind_LowWindThreshold = 5; 56 | @SectionHeader("misc") 57 | public List Misc_DimensionWhitelist = new ArrayList<>(List.of("minecraft:overworld")); 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/events/Tornado.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.events; 2 | 3 | import blue.endless.jankson.JsonObject; 4 | import blue.endless.jankson.JsonPrimitive; 5 | import net.minecraft.nbt.NbtCompound; 6 | import sh.talonfloof.enhancedweather.WindManager; 7 | 8 | public class Tornado extends WeatherEvent { 9 | public int intensity = 0; 10 | public int intensityMax = 0; 11 | public int intensityProgress = 0; 12 | public Tornado(double x, double y, double z, int intensityMax) { 13 | super(x,y,z); 14 | } 15 | @Override 16 | public NbtCompound generateUpdate() { 17 | NbtCompound c = new NbtCompound(); 18 | c.putString("id","enhancedweather:tornado"); 19 | c.putDouble("x",position.x); 20 | c.putDouble("y",position.y); 21 | c.putDouble("z",position.z); 22 | c.putInt("intensity",intensity); 23 | c.putInt("intensityMax",intensityMax); 24 | return c; 25 | } 26 | @Override 27 | public JsonObject generateSaveData() { 28 | JsonObject c = new JsonObject(); 29 | c.put("id",new JsonPrimitive("enhancedweather:tornado")); 30 | c.put("x",new JsonPrimitive(position.x)); 31 | c.put("y",new JsonPrimitive(position.y)); 32 | c.put("z",new JsonPrimitive(position.z)); 33 | c.put("intensity",new JsonPrimitive(intensity)); 34 | c.put("intensityMax",new JsonPrimitive(intensityMax)); 35 | c.put("intensityProgression",new JsonPrimitive(intensityProgress)); 36 | return c; 37 | } 38 | 39 | @Override 40 | public void loadSaveData(JsonObject data) { 41 | super.loadSaveData(data); 42 | } 43 | 44 | @Override 45 | public void tickServer() { 46 | float moveX = (float)-Math.sin(Math.toRadians(WindManager.windAngle))*Math.min(1.5F,WindManager.windSpeed/25F); 47 | float moveZ = (float)Math.cos(Math.toRadians(WindManager.windAngle))*Math.min(1.5F,WindManager.windSpeed/25F); 48 | position = position.add((moveX * 0.002) * 32,0,(moveZ * 0.002) * 32); 49 | intensityProgress += 1; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/events/WeatherEvent.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.events; 2 | 3 | import blue.endless.jankson.JsonObject; 4 | import net.minecraft.nbt.NbtCompound; 5 | import net.minecraft.util.math.Vec3d; 6 | 7 | public abstract class WeatherEvent { 8 | public Vec3d position; 9 | public WeatherEvent(double x, double y, double z) { 10 | position = new Vec3d(x,y,z); 11 | } 12 | public NbtCompound generateUpdate() { 13 | return new NbtCompound(); 14 | } 15 | public void applyUpdate(NbtCompound nbt) { 16 | position = new Vec3d(nbt.getDouble("x"),nbt.getDouble("y"),nbt.getDouble("z")); 17 | } 18 | public JsonObject generateSaveData() { 19 | return new JsonObject(); 20 | } 21 | public void loadSaveData(JsonObject data) { 22 | position = new Vec3d(data.getDouble("x",0),data.getDouble("y",0),data.getDouble("z",0)); 23 | } 24 | public void tickClient() {} 25 | public void tickServer() {} 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/mixin/FireBlockMixin.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.mixin; 2 | 3 | import net.minecraft.block.FireBlock; 4 | import net.minecraft.server.world.ServerWorld; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Redirect; 8 | 9 | @Mixin(FireBlock.class) 10 | public class FireBlockMixin { 11 | @Redirect(method = "scheduledTick(Lnet/minecraft/block/BlockState;Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/random/Random;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerWorld;isRaining()Z")) 12 | public boolean forceRain(ServerWorld instance) { 13 | return true; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/mixin/LightningEntityMixin.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.mixin; 2 | 3 | import net.minecraft.entity.LightningEntity; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | 9 | @Mixin(LightningEntity.class) 10 | public class LightningEntityMixin { 11 | @Inject(method = "spawnFire", at = @At("HEAD"), cancellable = true) 12 | private void cancelSpawnFire(int spreadAttempts, CallbackInfo ci) { 13 | ci.cancel(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/mixin/ServerWorldMixin.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.mixin; 2 | 3 | import net.minecraft.server.world.ServerWorld; 4 | import net.minecraft.util.math.BlockPos; 5 | import net.minecraft.util.math.MathHelper; 6 | import net.minecraft.util.math.random.Random; 7 | import net.minecraft.world.Heightmap; 8 | import net.minecraft.world.World; 9 | import net.minecraft.world.biome.Biome; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.Redirect; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 15 | import sh.talonfloof.enhancedweather.EnhancedWeather; 16 | import sh.talonfloof.enhancedweather.api.EnhancedWeatherAPI; 17 | 18 | @Mixin(ServerWorld.class) 19 | public class ServerWorldMixin { 20 | @Redirect(method = "tickChunk", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerWorld;isRaining()Z")) 21 | public boolean isRaining(ServerWorld instance) { 22 | return true; 23 | } 24 | @Redirect(method = "tickChunk", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerWorld;isThundering()Z")) 25 | public boolean isThundering(ServerWorld instance) { 26 | return true; 27 | } 28 | @Redirect(method = "tickChunk", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerWorld;hasRain(Lnet/minecraft/util/math/BlockPos;)Z")) 29 | private boolean canSpawnLightning(ServerWorld instance, BlockPos pos) { 30 | if(!EnhancedWeatherAPI.isThundering(instance, 0,pos.getX() - MathHelper.floor(EnhancedWeather.cloudX), pos.getZ() - MathHelper.floor(EnhancedWeather.cloudZ))) { 31 | return false; 32 | } else if (!instance.isSkyVisible(pos)) { 33 | return false; 34 | } else if (instance.getTopPosition(Heightmap.Type.MOTION_BLOCKING, pos).getY() > pos.getY()) { 35 | return false; 36 | } else { 37 | Biome biome = instance.getBiome(pos).value(); 38 | return biome.getPrecipitation(pos) == Biome.Precipitation.RAIN; 39 | } 40 | } 41 | @Redirect(method = "tickChunk", at = @At(value="INVOKE", target = "Lnet/minecraft/util/math/random/Random;nextInt(I)I")) 42 | private int overrideLightningSpawn(Random instance, int i) { 43 | return i == 100000 ? instance.nextInt(25000) : instance.nextInt(i); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/mixin/WorldMixin.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.mixin; 2 | 3 | import net.minecraft.util.math.BlockPos; 4 | import net.minecraft.util.math.MathHelper; 5 | import net.minecraft.world.Heightmap; 6 | import net.minecraft.world.World; 7 | import net.minecraft.world.biome.Biome; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 12 | import sh.talonfloof.enhancedweather.EnhancedWeather; 13 | import sh.talonfloof.enhancedweather.api.EnhancedWeatherAPI; 14 | 15 | @Mixin(World.class) 16 | public class WorldMixin { 17 | @Inject(method = "hasRain(Lnet/minecraft/util/math/BlockPos;)Z", at = @At("RETURN"), cancellable = true) 18 | public void hasRain(BlockPos pos, CallbackInfoReturnable cir) { 19 | if (!EnhancedWeatherAPI.isRaining(((World)(Object)this),pos.getX() - MathHelper.floor(EnhancedWeather.cloudX), pos.getZ() - MathHelper.floor(EnhancedWeather.cloudZ))) { 20 | cir.setReturnValue(false); 21 | return; 22 | } 23 | if (!((World)(Object)this).isSkyVisible(pos)) { 24 | cir.setReturnValue(false); 25 | return; 26 | } 27 | if (((World)(Object)this).getTopPosition(Heightmap.Type.MOTION_BLOCKING, pos).getY() > pos.getY()) { 28 | cir.setReturnValue(false); 29 | return; 30 | } 31 | Biome biome = ((World)(Object)this).getBiome(pos).value(); 32 | cir.setReturnValue(biome.getPrecipitation(pos) == Biome.Precipitation.RAIN); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/network/ScreenOpen.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.network; 2 | 3 | import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; 4 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 5 | import net.minecraft.network.PacketByteBuf; 6 | import net.minecraft.server.MinecraftServer; 7 | import net.minecraft.server.network.ServerPlayerEntity; 8 | import net.minecraft.util.Identifier; 9 | import net.minecraft.util.math.BlockPos; 10 | 11 | public class ScreenOpen { 12 | public static Identifier PACKET_ID = new Identifier("enhancedweather","screen_open"); 13 | public static void send(ServerPlayerEntity player, BlockPos pos) { 14 | PacketByteBuf buf = PacketByteBufs.create(); 15 | buf.writeBlockPos(pos); 16 | ServerPlayNetworking.send(player, PACKET_ID, buf); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/network/SuppressAlertServer.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.network; 2 | 3 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 4 | import net.minecraft.network.PacketByteBuf; 5 | import net.minecraft.server.MinecraftServer; 6 | import net.minecraft.server.network.ServerPlayNetworkHandler; 7 | import net.minecraft.server.network.ServerPlayerEntity; 8 | import net.minecraft.util.Identifier; 9 | import net.minecraft.util.math.BlockPos; 10 | 11 | import static sh.talonfloof.enhancedweather.block.RadarBlock.LIGHT; 12 | 13 | public class SuppressAlertServer { 14 | public static final Identifier PACKET_ID = new Identifier("enhancedweather","suppress_alert"); 15 | public static void onReceive(MinecraftServer minecraftServer, ServerPlayerEntity serverPlayerEntity, ServerPlayNetworkHandler ignored, PacketByteBuf packetByteBuf, PacketSender ignored2) { 16 | BlockPos pos = packetByteBuf.readBlockPos(); 17 | serverPlayerEntity.getServerWorld().setBlockState(pos,serverPlayerEntity.getServerWorld().getBlockState(pos).with(LIGHT,false)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/network/UpdateConditions.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.network; 2 | 3 | import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; 4 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 5 | import net.minecraft.network.PacketByteBuf; 6 | import net.minecraft.server.MinecraftServer; 7 | import net.minecraft.server.network.ServerPlayerEntity; 8 | import net.minecraft.util.Identifier; 9 | import sh.talonfloof.enhancedweather.WindManager; 10 | 11 | public class UpdateConditions { 12 | public static Identifier PACKET_ID = new Identifier("enhancedweather","update_conditions"); 13 | public static void send(MinecraftServer server, ServerPlayerEntity player, float windX, float windZ, double cloudX, double cloudZ) { 14 | PacketByteBuf buf = PacketByteBufs.create(); 15 | buf.writeFloat(windX); 16 | buf.writeFloat(windZ); 17 | buf.writeFloat(WindManager.windSpeed); 18 | buf.writeDouble(cloudX); 19 | buf.writeDouble(cloudZ); 20 | ServerPlayNetworking.send(player, PACKET_ID, buf); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/network/UpdateEvent.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.network; 2 | 3 | import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; 4 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 5 | import net.minecraft.nbt.NbtCompound; 6 | import net.minecraft.network.PacketByteBuf; 7 | import net.minecraft.server.MinecraftServer; 8 | import net.minecraft.server.network.ServerPlayerEntity; 9 | import net.minecraft.util.Identifier; 10 | 11 | import java.util.UUID; 12 | 13 | public class UpdateEvent { 14 | public static Identifier PACKET_ID = new Identifier("enhancedweather","update_event"); 15 | public static void send(MinecraftServer server, UUID id, NbtCompound data, ServerPlayerEntity player) { 16 | PacketByteBuf buf = PacketByteBufs.create(); 17 | buf.writeLong(id.getLeastSignificantBits()); 18 | buf.writeLong(id.getMostSignificantBits()); 19 | buf.writeNbt(data); 20 | ServerPlayNetworking.send(player, PACKET_ID, buf); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/util/ImageSampler.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.util; 2 | 3 | import net.minecraft.util.math.MathHelper; 4 | 5 | import javax.imageio.ImageIO; 6 | import java.awt.image.BufferedImage; 7 | import java.io.IOException; 8 | import java.net.URL; 9 | 10 | public class ImageSampler { 11 | private final float[] data; 12 | private final int width; 13 | private final int height; 14 | 15 | private boolean smooth = false; 16 | 17 | public ImageSampler(String path) { 18 | URL url = Thread.currentThread().getContextClassLoader().getResource(path); 19 | BufferedImage image; 20 | 21 | try { 22 | image = ImageIO.read(url); 23 | } 24 | catch (IOException e) { 25 | e.printStackTrace(); 26 | image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); 27 | } 28 | 29 | width = image.getWidth(); 30 | height = image.getWidth(); 31 | data = new float[width * height]; 32 | 33 | int[] pixels = new int[data.length]; 34 | image.getRGB(0, 0, width, height, pixels, 0, width); 35 | 36 | for (int i = 0; i < data.length; i++) { 37 | data[i] = (pixels[i] & 255) / 255F; 38 | } 39 | } 40 | 41 | private static float interpolate2D( 42 | double x, double y, 43 | float v1, float v2, float v3, float v4 44 | ) { 45 | return (float)MathHelper.lerp(y, MathHelper.lerp(x, v1, v2), MathHelper.lerp(x, v3, v4)); 46 | } 47 | 48 | public float sample(double x, double z) { 49 | long x1 = MathHelper.floor(x); 50 | long z1 = MathHelper.floor(z); 51 | long x2 = MathUtil.wrap(x1 + 1, width); 52 | long z2 = MathUtil.wrap(z1 + 1, height); 53 | double dx = x - x1; 54 | double dz = z - z1; 55 | x1 = MathUtil.wrap(x1, width); 56 | z1 = MathUtil.wrap(z1, height); 57 | 58 | float a = data[getIndex((int)x1, (int)z1)]; 59 | float b = data[getIndex((int)x2, (int)z1)]; 60 | float c = data[getIndex((int)x1, (int)z2)]; 61 | float d = data[getIndex((int)x2, (int)z2)]; 62 | 63 | if (smooth) { 64 | dx = smoothStep(dx); 65 | dz = smoothStep(dz); 66 | } 67 | 68 | return interpolate2D( 69 | dx, dz, a, b, c, d 70 | ); 71 | } 72 | 73 | private int getIndex(int x, int z) { 74 | return z * width + x; 75 | } 76 | 77 | public ImageSampler setSmooth(boolean smooth) { 78 | this.smooth = smooth; 79 | return this; 80 | } 81 | 82 | private double smoothStep(double x) { 83 | return x * x * x * (x * (x * 6 - 15) + 10); 84 | } 85 | } -------------------------------------------------------------------------------- /src/main/java/sh/talonfloof/enhancedweather/util/MathUtil.java: -------------------------------------------------------------------------------- 1 | package sh.talonfloof.enhancedweather.util; 2 | 3 | import net.minecraft.util.math.MathHelper; 4 | 5 | public class MathUtil { 6 | public static long wrap(long value, long side) { 7 | if (side != 0 && (side & (side - 1)) == 0) { 8 | return value & (side - 1); 9 | } 10 | long result = (value - value / side * side); 11 | return result < 0 ? result + side : result; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/blockstates/radar.json: -------------------------------------------------------------------------------- 1 | { 2 | "variants": { 3 | "facing=north,light=false": { "model": "enhancedweather:block/radar", "y": 180 }, 4 | "facing=north,light=true": { "model": "enhancedweather:block/radar_light", "y": 180 }, 5 | "facing=east,light=false": { "model": "enhancedweather:block/radar", "y": 270 }, 6 | "facing=east,light=true": { "model": "enhancedweather:block/radar_light", "y": 270 }, 7 | "facing=south,light=false": { "model": "enhancedweather:block/radar", "y": 0 }, 8 | "facing=south,light=true": { "model": "enhancedweather:block/radar_light", "y": 0 }, 9 | "facing=west,light=false": { "model": "enhancedweather:block/radar", "y": 90 }, 10 | "facing=west,light=true": { "model": "enhancedweather:block/radar_light", "y": 90 } 11 | } 12 | } -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/icon.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "text.config.enhancedweather.title": "Enhanced Weather Config Screen", 3 | "text.config.enhancedweather.section.client": "Client", 4 | "text.config.enhancedweather.section.weather": "Weather", 5 | "text.config.enhancedweather.section.wind": "Wind", 6 | "text.config.enhancedweather.section.misc": "Miscellaneous", 7 | "text.config.enhancedweather.option.Client_ParticleRain": "Particle-based Precipitation", 8 | "text.config.enhancedweather.option.Client_ParticleRain.tooltip": "We recommended disabling this if you're using shaders", 9 | "text.config.enhancedweather.option.Client_ShowRainbow": "Show Rainbows", 10 | "text.config.enhancedweather.option.Client_ShowRainbow.tooltip": "We recommended disabling this if you're using shaders", 11 | "text.config.enhancedweather.option.Client_CloudRadius": "Cloud Render Radius", 12 | "text.config.enhancedweather.option.Client_CloudRadius.tooltip": "Changes the radius of clouds that are rendered", 13 | "text.config.enhancedweather.option.Client_ParticlesMoveWithWind": "Particles Move with Wind", 14 | "text.config.enhancedweather.option.Client_ParticlesMoveWithWind.tooltip": "Sets if particle velocity is affected by wind", 15 | "text.config.enhancedweather.option.Weather_ReducedRainFronts": "Reduce Rain Fronts", 16 | "text.config.enhancedweather.option.Weather_ReducedRainFronts.tooltip": "Enabling this reduces the amount of rain fronts", 17 | "text.config.enhancedweather.option.Weather_TornadoMinimumWind": "Tornado Minimum Wind Speed", 18 | "text.config.enhancedweather.option.Weather_TornadoMinimumWind.tooltip": "The minimum wind speed that tornadoes can spawn and exist in", 19 | "text.config.enhancedweather.option.Weather_TornadoSpawnChance": "Tornado Spawn Chance", 20 | "text.config.enhancedweather.option.Weather_TornadoSpawnChance.tooltip": "The chance (1 in [number]) of a tornado spawning in the right conditions", 21 | "text.config.enhancedweather.option.Wind_LowWindChance": "Low Wind Event Chance", 22 | "text.config.enhancedweather.option.Wind_LowWindChance.tooltip": "The chance (1 in [number]) of a low wind event occurring", 23 | "text.config.enhancedweather.option.Wind_HighWindChance": "High Wind Event Chance", 24 | "text.config.enhancedweather.option.Wind_HighWindChance.tooltip": "The chance (1 in [number]) of a high wind event occurring", 25 | "text.config.enhancedweather.option.Wind_LowWindBaseTime": "Low Wind Event Base Time", 26 | "text.config.enhancedweather.option.Wind_LowWindBaseTime.tooltip": "Base Time (in ticks) that a low wind event will last", 27 | "text.config.enhancedweather.option.Wind_LowWindExtraTime": "Low Wind Event Extra Time", 28 | "text.config.enhancedweather.option.Wind_LowWindExtraTime.tooltip": "Maximum extra time (in ticks) that a low wind event will last", 29 | "text.config.enhancedweather.option.Wind_HighWindBaseTime": "High Wind Event Base Time", 30 | "text.config.enhancedweather.option.Wind_HighWindBaseTime.tooltip": "Base Time (in ticks) that a high wind event will last", 31 | "text.config.enhancedweather.option.Wind_HighWindExtraTime": "High Wind Event Extra Time", 32 | "text.config.enhancedweather.option.Wind_HighWindExtraTime.tooltip": "Maximum extra time (in ticks) that a high wind event will last", 33 | "text.config.enhancedweather.option.Wind_LowWindThreshold": "Low Wind Threshold", 34 | "text.config.enhancedweather.option.Wind_LowWindThreshold.tooltip": "The lowest wind speed that a low wind event will drop to", 35 | "text.config.enhancedweather.option.Misc_DimensionWhitelist": "Dimension Whitelist", 36 | "text.config.enhancedweather.option.Misc_DimensionWhitelist.tooltip": "Enable a dimension to have clouds in it", 37 | "block.enhancedweather.radar": "Weather Radar" 38 | } -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/models/block/radar.json: -------------------------------------------------------------------------------- 1 | { 2 | "credit": "Made with Blockbench by Talon", 3 | "textures": { 4 | "0": "enhancedweather:block/radar", 5 | "particle": "enhancedweather:block/radar" 6 | }, 7 | "elements": [ 8 | { 9 | "from": [0, 0, 0], 10 | "to": [16, 16, 16], 11 | "faces": { 12 | "north": {"uv": [4, 4, 8, 8], "texture": "#0"}, 13 | "east": {"uv": [0, 4, 4, 8], "texture": "#0"}, 14 | "south": {"uv": [12, 0, 16, 4], "texture": "#0"}, 15 | "west": {"uv": [8, 0, 12, 4], "texture": "#0"}, 16 | "up": {"uv": [4, 0, 8, 4], "texture": "#0"}, 17 | "down": {"uv": [0, 0, 4, 4], "texture": "#0"} 18 | } 19 | }, 20 | { 21 | "from": [1, 16, 1], 22 | "to": [2, 32, 2], 23 | "faces": { 24 | "north": {"uv": [0.75, 12, 1, 16], "texture": "#0"}, 25 | "east": {"uv": [0.5, 12, 0.75, 16], "texture": "#0"}, 26 | "south": {"uv": [0.25, 12, 0.5, 16], "texture": "#0"}, 27 | "west": {"uv": [0, 12, 0.25, 16], "texture": "#0"}, 28 | "up": {"uv": [0, 11.75, 0.25, 12], "texture": "#0"}, 29 | "down": {"uv": [0.25, 11.75, 0.5, 12], "texture": "#0"} 30 | } 31 | } 32 | ], 33 | "display": { 34 | "thirdperson_righthand": { 35 | "rotation": [75, 45, 0], 36 | "translation": [0, 2.5, 0], 37 | "scale": [0.375, 0.375, 0.375] 38 | }, 39 | "thirdperson_lefthand": { 40 | "rotation": [75, 45, 0], 41 | "translation": [0, 2.5, 0], 42 | "scale": [0.375, 0.375, 0.375] 43 | }, 44 | "firstperson_righthand": { 45 | "rotation": [0, 45, 0], 46 | "scale": [0.4, 0.4, 0.4] 47 | }, 48 | "firstperson_lefthand": { 49 | "rotation": [0, 225, 0], 50 | "scale": [0.4, 0.4, 0.4] 51 | }, 52 | "ground": { 53 | "translation": [0, 3, 0], 54 | "scale": [0.25, 0.25, 0.25] 55 | }, 56 | "gui": { 57 | "rotation": [30, 225, 0], 58 | "scale": [0.625, 0.625, 0.625] 59 | }, 60 | "fixed": { 61 | "scale": [0.5, 0.5, 0.5] 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/models/block/radar_light.json: -------------------------------------------------------------------------------- 1 | { 2 | "credit": "Made with Blockbench by Talon", 3 | "textures": { 4 | "0": "enhancedweather:block/radar_light", 5 | "particle": "enhancedweather:block/radar" 6 | }, 7 | "elements": [ 8 | { 9 | "from": [0, 0, 0], 10 | "to": [16, 16, 16], 11 | "faces": { 12 | "north": {"uv": [4, 4, 8, 8], "texture": "#0"}, 13 | "east": {"uv": [0, 4, 4, 8], "texture": "#0"}, 14 | "south": {"uv": [12, 0, 16, 4], "texture": "#0"}, 15 | "west": {"uv": [8, 0, 12, 4], "texture": "#0"}, 16 | "up": {"uv": [4, 0, 8, 4], "texture": "#0"}, 17 | "down": {"uv": [0, 0, 4, 4], "texture": "#0"} 18 | } 19 | }, 20 | { 21 | "from": [1, 16, 1], 22 | "to": [2, 32, 2], 23 | "faces": { 24 | "north": {"uv": [0.75, 12, 1, 16], "texture": "#0"}, 25 | "east": {"uv": [0.5, 12, 0.75, 16], "texture": "#0"}, 26 | "south": {"uv": [0.25, 12, 0.5, 16], "texture": "#0"}, 27 | "west": {"uv": [0, 12, 0.25, 16], "texture": "#0"}, 28 | "up": {"uv": [0, 11.75, 0.25, 12], "texture": "#0"}, 29 | "down": {"uv": [0.25, 11.75, 0.5, 12], "texture": "#0"} 30 | } 31 | } 32 | ], 33 | "display": { 34 | "thirdperson_righthand": { 35 | "rotation": [75, 45, 0], 36 | "translation": [0, 2.5, 0], 37 | "scale": [0.375, 0.375, 0.375] 38 | }, 39 | "thirdperson_lefthand": { 40 | "rotation": [75, 45, 0], 41 | "translation": [0, 2.5, 0], 42 | "scale": [0.375, 0.375, 0.375] 43 | }, 44 | "firstperson_righthand": { 45 | "rotation": [0, 45, 0], 46 | "scale": [0.4, 0.4, 0.4] 47 | }, 48 | "firstperson_lefthand": { 49 | "rotation": [0, 225, 0], 50 | "scale": [0.4, 0.4, 0.4] 51 | }, 52 | "ground": { 53 | "translation": [0, 3, 0], 54 | "scale": [0.25, 0.25, 0.25] 55 | }, 56 | "gui": { 57 | "rotation": [30, 225, 0], 58 | "scale": [0.625, 0.625, 0.625] 59 | }, 60 | "fixed": { 61 | "scale": [0.5, 0.5, 0.5] 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/models/item/radar.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "enhancedweather:block/radar" 3 | } -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/particles/hail.json: -------------------------------------------------------------------------------- 1 | { 2 | "textures": [ 3 | "enhancedweather:hail" 4 | ] 5 | } -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/particles/rain.json: -------------------------------------------------------------------------------- 1 | { 2 | "textures": [ 3 | "enhancedweather:rain" 4 | ] 5 | } -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/particles/snow.json: -------------------------------------------------------------------------------- 1 | { 2 | "textures": [ 3 | "enhancedweather:snow1", 4 | "enhancedweather:snow2", 5 | "enhancedweather:snow3", 6 | "enhancedweather:snow4" 7 | ] 8 | } -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/particles/tornado.json: -------------------------------------------------------------------------------- 1 | { 2 | "textures": [ 3 | "enhancedweather:tornado2" 4 | ] 5 | } -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/sounds.json: -------------------------------------------------------------------------------- 1 | { 2 | "radar.beep": { 3 | "category": "block", 4 | "sounds": [ 5 | { 6 | "name": "enhancedweather:radar_beep", 7 | "stream": true 8 | } 9 | ] 10 | } 11 | } -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/sounds/radar_beep.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/sounds/radar_beep.ogg -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/block/radar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/block/radar.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/block/radar.png.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "animation": { 3 | "frametime": 6 4 | } 5 | } -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/block/radar_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/block/radar_light.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/block/radar_light.png.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "animation": { 3 | "frametime": 6 4 | } 5 | } -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/cloud/cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/cloud/cloud.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/gui/radar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/gui/radar.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/gui/radar_alert_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/gui/radar_alert_light.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/gui/tornado_symbol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/gui/tornado_symbol.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/particle/hail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/particle/hail.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/particle/rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/particle/rain.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/particle/snow1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/particle/snow1.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/particle/snow2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/particle/snow2.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/particle/snow3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/particle/snow3.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/particle/snow4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/particle/snow4.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/particle/tornado.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/particle/tornado.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/particle/tornado2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/particle/tornado2.png -------------------------------------------------------------------------------- /src/main/resources/assets/enhancedweather/textures/sky/rainbow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/enhancedweather/textures/sky/rainbow.png -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/sounds.json: -------------------------------------------------------------------------------- 1 | { 2 | "weather.rain": { 3 | "category": "weather", 4 | "replace": true, 5 | "sounds": [ 6 | { 7 | "name": "minecraft:ambient/weather/rain1", 8 | "volume": 0.2 9 | }, 10 | { 11 | "name": "minecraft:ambient/weather/rain2", 12 | "volume": 0.2 13 | }, 14 | { 15 | "name": "minecraft:ambient/weather/rain3", 16 | "volume": 0.2 17 | }, 18 | { 19 | "name": "minecraft:ambient/weather/rain4", 20 | "volume": 0.2 21 | } 22 | ] 23 | }, 24 | "weather.rain.above": { 25 | "category": "weather", 26 | "replace": true, 27 | "sounds": [ 28 | { 29 | "name": "minecraft:ambient/weather/rain1", 30 | "volume": 0.2 31 | }, 32 | { 33 | "name": "minecraft:ambient/weather/rain2", 34 | "volume": 0.2 35 | }, 36 | { 37 | "name": "minecraft:ambient/weather/rain3", 38 | "volume": 0.2 39 | }, 40 | { 41 | "name": "minecraft:ambient/weather/rain4", 42 | "volume": 0.2 43 | } 44 | ] 45 | }, 46 | "entity.lightning_bolt.thunder": { 47 | "replace": true, 48 | "sounds": [ 49 | { 50 | "name": "minecraft:ambient/weather/thunder1", 51 | "stream": true 52 | }, 53 | { 54 | "name": "minecraft:ambient/weather/thunder2", 55 | "stream": true 56 | }, 57 | { 58 | "name": "minecraft:ambient/weather/thunder3", 59 | "stream": true 60 | }, 61 | { 62 | "name": "minecraft:ambient/weather/thunder4", 63 | "stream": true 64 | }, 65 | { 66 | "name": "minecraft:ambient/weather/thunder5", 67 | "stream": true 68 | }, 69 | { 70 | "name": "minecraft:ambient/weather/thunder6", 71 | "stream": true 72 | } 73 | ] 74 | } 75 | } -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/sounds/ambient/weather/rain1.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/minecraft/sounds/ambient/weather/rain1.ogg -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/sounds/ambient/weather/rain2.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/minecraft/sounds/ambient/weather/rain2.ogg -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/sounds/ambient/weather/rain3.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/minecraft/sounds/ambient/weather/rain3.ogg -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/sounds/ambient/weather/rain4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/minecraft/sounds/ambient/weather/rain4.ogg -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/sounds/ambient/weather/thunder1.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/minecraft/sounds/ambient/weather/thunder1.ogg -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/sounds/ambient/weather/thunder2.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/minecraft/sounds/ambient/weather/thunder2.ogg -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/sounds/ambient/weather/thunder3.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/minecraft/sounds/ambient/weather/thunder3.ogg -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/sounds/ambient/weather/thunder4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/minecraft/sounds/ambient/weather/thunder4.ogg -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/sounds/ambient/weather/thunder5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/minecraft/sounds/ambient/weather/thunder5.ogg -------------------------------------------------------------------------------- /src/main/resources/assets/minecraft/sounds/ambient/weather/thunder6.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/assets/minecraft/sounds/ambient/weather/thunder6.ogg -------------------------------------------------------------------------------- /src/main/resources/data/enhancedweather/clouds/large_details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/data/enhancedweather/clouds/large_details.png -------------------------------------------------------------------------------- /src/main/resources/data/enhancedweather/clouds/main_shape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/data/enhancedweather/clouds/main_shape.png -------------------------------------------------------------------------------- /src/main/resources/data/enhancedweather/clouds/rain_density.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/data/enhancedweather/clouds/rain_density.png -------------------------------------------------------------------------------- /src/main/resources/data/enhancedweather/clouds/rain_fronts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/data/enhancedweather/clouds/rain_fronts.png -------------------------------------------------------------------------------- /src/main/resources/data/enhancedweather/clouds/thunderstorms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/data/enhancedweather/clouds/thunderstorms.png -------------------------------------------------------------------------------- /src/main/resources/data/enhancedweather/clouds/variation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TalonFloof/EnhancedWeather/fa090481ef35a9568f4fb7251e24d83ed614f464/src/main/resources/data/enhancedweather/clouds/variation.png -------------------------------------------------------------------------------- /src/main/resources/data/enhancedweather/loot_tables/blocks/radar.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:block", 3 | "pools": [ 4 | { 5 | "rolls": 1, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "name": "enhancedweather:radar" 10 | } 11 | ], 12 | "conditions": [ 13 | { 14 | "condition": "minecraft:survives_explosion" 15 | } 16 | ] 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /src/main/resources/data/enhancedweather/recipes/radar.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "#G#", 5 | "#R#", 6 | "###" 7 | ], 8 | "key": { 9 | "#": {"item": "minecraft:iron_ingot"}, 10 | "R": {"item": "minecraft:redstone"}, 11 | "G": {"item": "minecraft:glass"} 12 | }, 13 | "result": { 14 | "item": "enhancedweather:radar", 15 | "count": 1 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "values": [ 4 | "enhancedweather:radar" 5 | ] 6 | } -------------------------------------------------------------------------------- /src/main/resources/enhancedweather.accesswidener: -------------------------------------------------------------------------------- 1 | accessWidener v1 named 2 | accessible field net/minecraft/world/biome/Biome weather Lnet/minecraft/world/biome/Biome$Weather; 3 | accessible class net/minecraft/world/biome/Biome$Weather 4 | accessible field net/minecraft/client/particle/Particle velocityX D 5 | accessible field net/minecraft/client/particle/Particle velocityZ D -------------------------------------------------------------------------------- /src/main/resources/enhancedweather.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "sh.talonfloof.enhancedweather.mixin", 4 | "compatibilityLevel": "JAVA_17", 5 | "mixins": [ 6 | "FireBlockMixin", 7 | "LightningEntityMixin", 8 | "ServerWorldMixin", 9 | "WorldMixin" 10 | ], 11 | "injectors": { 12 | "defaultRequire": 1 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "enhancedweather", 4 | "version": "${version}", 5 | "name": "Enhanced Weather", 6 | "description": "The ultimate weather mod for Minecraft Fabric", 7 | "authors": [ 8 | "TalonFloof" 9 | ], 10 | "contact": { 11 | "sources": "https://github.com/TalonFloof/EnhancedWeather" 12 | }, 13 | "license": "MIT", 14 | "icon": "assets/enhancedweather/icon.png", 15 | "environment": "*", 16 | "entrypoints": { 17 | "main": [ 18 | "sh.talonfloof.enhancedweather.EnhancedWeather" 19 | ], 20 | "client": [ 21 | "sh.talonfloof.enhancedweather.EnhancedWeatherClient" 22 | ] 23 | }, 24 | "mixins": [ 25 | "enhancedweather.mixins.json", 26 | { 27 | "config": "enhancedweather.client.mixins.json", 28 | "environment": "client" 29 | } 30 | ], 31 | "accessWidener": "enhancedweather.accesswidener", 32 | "depends": { 33 | "fabricloader": "*", 34 | "minecraft": "~1.20.4", 35 | "java": ">=17", 36 | "fabric-api": "*" 37 | } 38 | } --------------------------------------------------------------------------------