diff --git a/.github/scripts/changelog-comment.cjs b/.github/scripts/changelog-comment.cjs index 81abb01..b5731c1 100644 --- a/.github/scripts/changelog-comment.cjs +++ b/.github/scripts/changelog-comment.cjs @@ -17,7 +17,7 @@ module.exports = async ({ github, context }) => { const issue_number = pull.number; const repo = { ...context.repo, issue_number }; const comments = await github.paginate(github.rest.issues.listComments, repo); - for (const project of ['sounds', 'mru', 'shields']) { + for (const project of ['sounds', 'mru', 'shields', 'fog']) { if (!pull.labels.some(label => label.name === `project:${project}`)) continue; const marker = `[release-changelog-${project}]: #`; if (comments.some(comment => comment.user.type === 'Bot' && comment.body.split(/\r?\n/).includes(marker))) continue; diff --git a/.github/scripts/prepare-release.mjs b/.github/scripts/prepare-release.mjs index 1bde467..4d45d8f 100644 --- a/.github/scripts/prepare-release.mjs +++ b/.github/scripts/prepare-release.mjs @@ -11,7 +11,7 @@ const git = (...values) => run('git', values); const project = option('project'); const version = option('version'); const versionPattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/; -if (!['sounds', 'mru', 'shields'].includes(project) || !versionPattern.test(version ?? '')) throw new Error('Provide --project sounds|mru|shields and --version X.Y.Z. Optional: --from REF, --write.'); +if (!['sounds', 'mru', 'shields', 'fog'].includes(project) || !versionPattern.test(version ?? '')) throw new Error('Provide --project sounds|mru|shields|fog and --version X.Y.Z. Optional: --from REF, --write.'); const suffix = version.match(/^[^-+]+(?:-([^+]+))?(?:\+(.+))?$/); if ([suffix?.[1], suffix?.[2]].filter(Boolean).some(value => value.split('.').some(part => !part)) || suffix?.[1]?.split('.').some(part => /^0\d+$/.test(part))) throw new Error('Invalid semantic version suffix'); const head = git('rev-parse', 'HEAD'); diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index d5dc4df..edb06bb 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -7,7 +7,7 @@ on: description: project type: choice required: true - options: [sounds, mru, shields] + options: [sounds, mru, shields, fog] version: description: version type: string diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e25b670..76a01d2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,6 +6,7 @@ on: - mru/v* - sounds/v* - shields/v* + - fog/v* workflow_dispatch: inputs: tag: @@ -32,8 +33,8 @@ jobs: RELEASE_TAG: ${{ inputs.tag || github.ref_name }} run: | case "$RELEASE_TAG" in - sounds/v*|mru/v*|shields/v*) ;; - *) echo 'Expected a sounds/v, mru/v, or shields/v release tag'; exit 1 ;; + sounds/v*|mru/v*|shields/v*|fog/v*) ;; + *) echo 'Expected a sounds/v, mru/v, shields/v, or fog/v release tag'; exit 1 ;; esac test "$(git rev-parse HEAD)" = "$(git rev-parse "refs/tags/$RELEASE_TAG^{commit}")" echo "RELEASE_MOD=${RELEASE_TAG%%/*}" >> "$GITHUB_ENV" @@ -50,7 +51,7 @@ jobs: GITHUB_TOKEN: ${{ github.token }} run: | case "$RELEASE_MOD" in - mru|sounds|shields) task=":$RELEASE_MOD:publishMods" ;; + mru|sounds|shields|fog) task=":$RELEASE_MOD:publishMods" ;; *) exit 1 ;; esac GITHUB_REF_TYPE=tag GITHUB_REF_NAME="$RELEASE_TAG" GITHUB_SHA="$(git rev-parse HEAD)" bash ./gradlew --no-daemon --build-cache "$task" diff --git a/.gitignore b/.gitignore index d90f08f..d9a06b2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .idea/ .gradle/ **/.gradle/ +**/.kotlin/ **/build/ **/run/ **/runs/ diff --git a/build-logic/src/main/kotlin/imb11.fabric-mod.gradle.kts b/build-logic/src/main/kotlin/imb11.fabric-mod.gradle.kts index 93e86b6..7243909 100644 --- a/build-logic/src/main/kotlin/imb11.fabric-mod.gradle.kts +++ b/build-logic/src/main/kotlin/imb11.fabric-mod.gradle.kts @@ -21,10 +21,12 @@ loom { } } runs { + if (metadata.optional("mod.environment") == "client") { + remove(getByName("server")) + } configureEach { isIdeConfigGenerated = true configName = "${metadata.required("mod.name")} - $targetMinecraftVersion - Fabric - ${name.replaceFirstChar { it.titlecase() }}" - appendProjectPathToConfigName.set(false) ideConfigFolder.set(metadata.required("mod.name")) runDir(rootProject.file("run/${metadata.id}/$targetMinecraftVersion/fabric/$name").relativeTo(project.projectDir).invariantSeparatorsPath) } diff --git a/build-logic/src/main/kotlin/imb11.mod.gradle.kts b/build-logic/src/main/kotlin/imb11.mod.gradle.kts index d8998f4..a960d3f 100644 --- a/build-logic/src/main/kotlin/imb11.mod.gradle.kts +++ b/build-logic/src/main/kotlin/imb11.mod.gradle.kts @@ -86,6 +86,7 @@ val resourceProperties = mapOf( "target_loader" to if (loader == "fabric") catalog.findVersion("fabric-loader").get().requiredVersion else "[${catalog.findVersion("neoforge").get().requiredVersion},)", "target_fabricloader" to catalog.findVersion("fabric-loader").get().requiredVersion, + "target_architectury" to catalog.findVersion("architectury").map { it.requiredVersion }.orElse(""), "target_yacl" to if (loader == "fabric") ">=$yaclVersion" else yaclVersion, "target_mru" to if (loader == "fabric") ">=$requiredModVersion" else requiredModVersion ) @@ -113,6 +114,7 @@ jsonlang { repositories { mavenCentral() + maven("https://maven.architectury.dev") maven("https://maven.fabricmc.net/") maven("https://maven.neoforged.net/releases/") maven("https://maven.shedaniel.me/") diff --git a/build-logic/src/main/kotlin/imb11.neoforge-mod.gradle.kts b/build-logic/src/main/kotlin/imb11.neoforge-mod.gradle.kts index deba734..00b9322 100644 --- a/build-logic/src/main/kotlin/imb11.neoforge-mod.gradle.kts +++ b/build-logic/src/main/kotlin/imb11.neoforge-mod.gradle.kts @@ -29,9 +29,11 @@ neoForge { client() gameDirectory.set(rootProject.layout.projectDirectory.dir("run/${metadata.id}/$minecraftVersion/neoforge/client")) } - register("server") { - server() - gameDirectory.set(rootProject.layout.projectDirectory.dir("run/${metadata.id}/$minecraftVersion/neoforge/server")) + if (metadata.optional("mod.environment") != "client") { + register("server") { + server() + gameDirectory.set(rootProject.layout.projectDirectory.dir("run/${metadata.id}/$minecraftVersion/neoforge/server")) + } } } } diff --git a/build-logic/src/main/kotlin/imb11.publish-mod.gradle.kts b/build-logic/src/main/kotlin/imb11.publish-mod.gradle.kts index 38ca1af..3ac53bc 100644 --- a/build-logic/src/main/kotlin/imb11.publish-mod.gradle.kts +++ b/build-logic/src/main/kotlin/imb11.publish-mod.gradle.kts @@ -6,6 +6,7 @@ plugins { } val modData = readModMetadata(layout.projectDirectory) +val clientOnly = modData.optional("mod.environment") == "client" || modData.id == "sounds" val releaseTag = "${modData.id}/v${modData.version}" val publishDryRun = providers.gradleProperty("publishDryRun").map(String::toBoolean).orElse(false) val releaseChangelog = providers.fileContents(layout.projectDirectory.file("CHANGELOG.md")).asText.map { contents -> @@ -75,7 +76,7 @@ publishMods { projectId = modData.required("publish.modrinth") accessToken = providers.environmentVariable("MODRINTH_TOKEN") minecraftVersions.add(minecraftVersion) - environment = if (modData.id == "sounds") ModrinthEnvironment.CLIENT_ONLY else ModrinthEnvironment.CLIENT_AND_SERVER + environment = if (clientOnly) ModrinthEnvironment.CLIENT_ONLY else ModrinthEnvironment.CLIENT_AND_SERVER requiredMods.forEach { requires(it) } } @@ -85,7 +86,7 @@ publishMods { accessToken = providers.environmentVariable("CURSEFORGE_TOKEN") minecraftVersions.add(minecraftVersion) client = true - server = modData.id != "sounds" + server = !clientOnly requiredMods.forEach { requires(it) } } } diff --git a/build-logic/src/main/kotlin/imb11.root.gradle.kts b/build-logic/src/main/kotlin/imb11.root.gradle.kts index ff6a1ca..9408f45 100644 --- a/build-logic/src/main/kotlin/imb11.root.gradle.kts +++ b/build-logic/src/main/kotlin/imb11.root.gradle.kts @@ -55,9 +55,11 @@ tasks.register("publishAllMods") { dependsOn(modProjects.map { "${it.path}:publishMods" }) } -project(":sounds").pluginManager.withPlugin("imb11.publish-mod") { - project(":sounds").tasks.withType().configureEach { - mustRunAfter(":mru:publishMods") +listOf(":sounds", ":fog").forEach { mod -> + project(mod).pluginManager.withPlugin("imb11.publish-mod") { + project(mod).tasks.withType().configureEach { + mustRunAfter(":mru:publishMods") + } } } diff --git a/fog/CHANGELOG.md b/fog/CHANGELOG.md new file mode 100644 index 0000000..99b912b --- /dev/null +++ b/fog/CHANGELOG.md @@ -0,0 +1,319 @@ +# Changelog + +## [1.11.0] - 2025-10-07 + +### Added + +- Support for Minecraft 1.21.10. + +## [1.10.0] - 2025-10-04 + +### Added + +- Support for Minecraft 1.21.9 (by [cassiancc](https://github.com/cassiancc) in [#99](https://github.com/IMB11/Fog/pull/99)). + +## [1.9.3] - 2025-07-27 + +### Added + +- Support for Minecraft 1.21.8. + +## [1.9.2] - 2025-07-11 + +### Changed + +- Updated Russian (`ru_ru`) translations (by [mpustovoi](https://github.com/mpustovoi) in [#91](https://github.com/IMB11/Fog/pull/91)) + +### Fixed + +- A crash on startup on NeoForge due to an invalid Mixin configuration + +## [1.9.1] - 2025-07-10 + +### Fixed + +- A dependency error on startup due to the M.R.U dependency being specified incorrectly on Minecraft 1.21.7 +- A crash on startup due to a mixins not remapping correctly +- An incorrect translation key for the `enableMod` configuration option + +## [1.9.0] - 2025-07-09 + +### Added + +- Argentine Spanish (`es_ar`) translation (by [Texaliuz](https://github.com/Texaliuz) in [#81](https://github.com/IMB11/Fog/pull/81)) +- Support for Minecraft 1.21.6 and 1.21.7 + +### Changed + +- Made fog brighter during rainstorms and darker during thunderstorms +- Replaced the `disableRaininessEffect` configuration option with `rainFogMultiplier` +- Replaced the `disableUndergroundFogMultiplier` configuration option with `undergroundFogMultiplier` +- Renamed and inverted various configuration options +- Improved the configuration screen + - Condensed all configuration options into 3 categories: general, transition speeds and compatibility + +### Fixed + +- The `/fog debug` command not working due to the hexadecimal color in some cases +- The sunrise/sunset fog colors being applied when the darkness effect is active + +## [1.8.0] - 2025-04-17 + +### Added + +- Support for Minecraft 1.21.5. + +## [1.7.0] - 2025-04-10 + +### Added + +- Added an option to disable the mod automatically when Iris shaders are active. This is enabled by default. +- Added an option to disable the logic where the fog color would match the sky color when the player goes over a certain altitude. ("Enable High Altitude Fog") +- Added an option to prioritize Polytone fog colors over Fog's fog definitions. ("Prioritize Polytone Fog Colors") + +### Changed + +- Reworked sunset/sunrise blending logic, now sunsets and sunrises work spectacularly with the Fog mod. + +## [1.6.4] - 2025-03-02 + +### Fixed + +- Fixed an incorrect dependency declaration for Architectury API on NeoForge + +## [1.6.3] - 2025-03-01 + +### Fixed + +- Fixed an incorrect dependency declaration on NeoForge + +## [1.6.2] - 2025-02-23 + +### Changed + +- Updated the Simplified Chinese (`zh_cn`) language files (by [Chiloven945](https://github.com/Chiloven945) in https://github.com/IMB11/Fog/pull/64) + +### Fixed + +- Fixed the Overworld's default fog colors + - Nighttime fog is now pitch black again by default (in most biomes) in the Overworld +- Fixed M.R.U not being specified as a required dependency on NeoForge +- Fixed compatibility with Architectury API `v15.0.2` (on Minecraft 1.21.4) + - Architectury API `v15.0.1` (on Minecraft 1.21.4) has been marked as incompatible + +## [1.6.1] - 2024-12-27 + +### Changed + +- Updated Russian (`ru_ru`) translations. + +### Fixed + +- Fixed dependency issues for Minecraft 1.21.3. + +## [1.6.0] - 2024-12-27 + +### Added + +- Support for Minecraft 1.21.4. +- Sunrise and sunset enhancements for more vibrant transitions between day and night. +- Configurable moon phase modifiers that darken biome fog at night. + +### Changed + +- Reorganized the configuration screen into categories. +- Replaced the disabled dimensions list with a disabled biomes list. Existing configurations need updating. +- Default fog colors are now extracted from `DimensionEffects`/`DimensionSpecialEffects` to improve compatibility with mods such as [The Bumblezone](https://modrinth.com/mod/the-bumblezone-fabric) and [The Aether](https://modrinth.com/mod/aether). +- Disabled cloud whitening by default to improve clouds at night and during sunrise and sunset. It can still be enabled in the configuration screen. + +## [1.5.3] - 2024-12-06 + +### Changed + +- Updated YACL to `v3.6.2` + +## [1.5.2] - 2024-10-20 + +### Changed + +- Updated the Russian translations (by [mpustovoi](https://github.com/mpustovoi) in #44) + +## [1.5.1] - 2024-10-20 + +### Changed + +- Updated the Traditional Chinese translations (by [yichifauzi](https://github.com/yichifauzi) in #43) + +## [1.5.0] - 2024-10-20 + +### Added + +- Added Simplified Chinese translations, thank you @Chiloven945! +- Added a keybinding to toggle the fog modifications, it is unbinded by default, you must set it before you use it. @IMB11 +- Added configuration options for various transitions, @IMB11 + - e.g. fog colours, start/end multipliers, etc. +- Added a dimension disable list to the configuration screen, @Steveplays28 + - Replaced the Nether dimension toggle + +### Changed + +- Custom fog definitions must now be supplied through resource packs instead of the configuration folder. Default definitions must also be overridden through resource packs. +- Made the badlands, beach and default biome colours darker during nighttime, @Steveplays28 + - The default nighttime fog colour for most biomes has been changed to pitch black + +### Removed + +- Removed the (un)packing system for the built-in resource pack, @IMB11 + - Should fix a lot of crashes and compatibility issues +- Removed haze from the debug command and the language files as it no longer exists, @Steveplays28 + +### Fixed + +- Fixed a crash when other mods mess around with `RenderLayer`s, @Steveplays28 +- Fixed cloud whitening (when sodium is not installed) for 1.21+, @Steveplays28 +- Fixed the `raininess` effect breaking when standing under trees/walking over non-full blocks, @Steveplays28 + +## [1.4.1] - 2024-09-10 + +### Changed + +- Updated the Russian translation (`ru_ru`) by @mpustovoi in [#26]() + +### Fixed + +- Compatibility with Sodium `v0.6.0` + - By extension, all resource reload issues with other mods (e.x. Frostiful and Guarding) should be fixed as well +- Resource reload fixes were developed with help from cortex, XFactHD, Pepper and others. + +## [1.4.0] - 2024-08-31 + +### Added + +- Added a warning that shows when Fog updates and the new update modifies some of the default biome colours - it will recommend you to backup any changes within the `.minecraft/config/fog/fog_definitions` folder and then delete it so the default biome colours can be reset and updated. We will look into a diff-like system for this at a later date. + +### Changed + +- Updated biome colours for: swamp biomes, jungle biomes, badlands/mesa biomes, sandy biomes (desert/beach), the end biomes and icy aquatic biomes. They should be much less bright and more consistent with the default vanilla biome colours now. +- Required YACL 3.5.0, Architectury API and MRU. + +### Fixed + +- Fixed various issues with underground fog, there will be less of a flicker when coming out of caves, and the underground multiplier will no longer rarely kick in when you enter buildings. +- Fixed issue where fog goes black when it's raining. +- Potentially fix some crash issues on 1.20.1 forge with YACL 3.5.0 - let us know if you're still encountering crashes here. + +## [1.3.1] - 2024-08-15 + +### Changed + +- Updated the required MRU version to 1.0.0. +- Moved shared functionality, including external resource pack handling, into MRU for reuse by other mods. + +## [1.3.0] - 2024-08-14 + +### Added + +- Added support for 1.21.1. +- Added new point-based calculations to detect if a player is underground. This should fix issues where being inside a building tricks Fog into thinking you're underground. + +### Changed + +- The default day and night colours have been changed, night is now much darker and closer resembles the vanilla night fog colours. Vice versa for the day colours. +- The colours for the `#c:is_swamp` fog definition have been modified to account for these new default colours. Delete the `.minecraft/config/fog/fog_definitions/assets/c/fog_definitions/tag/biome/is_swamp.json` file to get the updated file. +- When in caves, the fog start will be much closer, fixing issues where there is a "pane" of colour blocking the view. It also massively improves cave fog in general. + +### Removed + +- Removed "Haze" system in favour of a single blend between day and night colours. + +### Fixed + +- Fixed issue where resource packs could not override Fog's default definitions due to the fact that Fog's resource pack was being loaded at the top regardless of the ordering on the Select Resource Pack screen. + +## [1.2.0] - 2024-08-09 + +### Added + +- Turkish (`tr_tr`) translations (by @digi2303 in [#15](https://github.com/IMB11/Fog/pull/15)). + +## [1.1.0] - 2024-08-07 + +### Added + +- Ukrainian (`uk_ua`) translations (by @Tarteroycc in [#12](https://github.com/IMB11/Fog/pull/12)). + +## [1.0.5] - 2024-08-04 + +### Fixed + +- Rewrote external resource pack loading to fix loading issues with packs in the configuration directory. + +## [1.0.4] - 2024-08-04 + +### Added + +- Added Russian translations, thanks @mpustovoi + +### Fixed + +- Fixed `FileSystem` crashes on NeoForge and Forge. + +## [1.0.3] - 2024-08-03 + +### Fixed + +- Fixed a startup crash caused by an incorrect check for asset namespace subdirectories. + +## [1.0.2] - 2024-08-03 + +### Fixed + +- Fixed external resource packs not being unpacked from the jar into `config/fog/fog_definitions`. +- Fixed resource packs failing to load in some scenarios. +- Fixed intermittent resource unpacker crashes affecting Windows users, with debugging help from @arcyteo000. + +## [1.0.1] - 2024-08-03 + +### Added + +- Simplified Chinese translations. + +### Fixed + +- Fixed the resource pack format. + +## [1.0.0] - 2024-08-03 + +### Added + +- Initial release of Fog. + +[1.11.0]: https://github.com/IMB11/Fog/releases/tag/1.11.0 +[1.10.0]: https://github.com/IMB11/Fog/releases/tag/1.10.0 +[1.9.3]: https://github.com/IMB11/Fog/releases/tag/1.9.3 +[1.9.2]: https://github.com/IMB11/Fog/releases/tag/1.9.2 +[1.9.1]: https://github.com/IMB11/Fog/releases/tag/1.9.1 +[1.9.0]: https://github.com/IMB11/Fog/releases/tag/1.9.0 +[1.8.0]: https://github.com/IMB11/Fog/releases/tag/1.8.0 +[1.7.0]: https://github.com/IMB11/Fog/releases/tag/1.7.0 +[1.6.4]: https://github.com/IMB11/Fog/releases/tag/1.6.4 +[1.6.3]: https://github.com/IMB11/Fog/releases/tag/1.6.3 +[1.6.2]: https://github.com/IMB11/Fog/releases/tag/1.6.2 +[1.6.1]: https://github.com/IMB11/Fog/releases/tag/1.6.1 +[1.6.0]: https://github.com/IMB11/Fog/releases/tag/1.6.0 +[1.5.3]: https://github.com/IMB11/Fog/releases/tag/1.5.3 +[1.5.2]: https://github.com/IMB11/Fog/releases/tag/1.5.2 +[1.5.1]: https://github.com/IMB11/Fog/releases/tag/1.5.1 +[1.5.0]: https://github.com/IMB11/Fog/releases/tag/1.5.0 +[1.4.1]: https://github.com/IMB11/Fog/releases/tag/1.4.1 +[1.4.0]: https://github.com/IMB11/Fog/releases/tag/1.4.0 +[1.3.1]: https://github.com/IMB11/Fog/releases/tag/1.3.1 +[1.3.0]: https://github.com/IMB11/Fog/releases/tag/1.3.0 +[1.2.0]: https://github.com/IMB11/Fog/releases/tag/1.2.0 +[1.1.0]: https://github.com/IMB11/Fog/releases/tag/1.1.0 +[1.0.5]: https://github.com/IMB11/Fog/releases/tag/1.0.5 +[1.0.4]: https://github.com/IMB11/Fog/releases/tag/1.0.4 +[1.0.3]: https://github.com/IMB11/Fog/releases/tag/1.0.3 +[1.0.2]: https://github.com/IMB11/Fog/releases/tag/1.0.2 +[1.0.1]: https://github.com/IMB11/Fog/releases/tag/1.0.1 +[1.0.0]: https://github.com/IMB11/Fog/releases/tag/1.0.0 diff --git a/fog/DEVELOPER_CERTIFICATE_OF_ORIGIN b/fog/DEVELOPER_CERTIFICATE_OF_ORIGIN new file mode 100644 index 0000000..b42564d --- /dev/null +++ b/fog/DEVELOPER_CERTIFICATE_OF_ORIGIN @@ -0,0 +1,29 @@ +Developer Certificate of Origin + +Everyone is permitted to copy and distribute verbatim copies of this document, but changing it is not allowed unless both Calum H. (IMB11) and Steveplays agree. + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I +have the right to submit it under the "All Rights Reserved" status +of this repository and I hereby assign all rights, title, and interest +in the contribution to Calum H. (IMB11) and Steveplays; or + +(b) The contribution is based upon previous work that, to the best +of my knowledge, is covered under an appropriate license and I +have the right under that license to submit that work with modifications, +whether created in whole or in part by me, and I hereby assign all rights, +title, and interest in the contribution to Calum H. (IMB11) and Steveplays; or + +(c) The contribution was provided directly to me by some other +person who certified (a), (b), or (c) and I have not modified it, +and I hereby assign all rights, title, and interest in the contribution +to Calum H. (IMB11) and Steveplays. + +(d) I understand and agree that this project and the contribution +are public and that a record of the contribution (including all +personal information I submit with it, including my sign-off) is +maintained indefinitely and may be redistributed consistent with +this project's "All Rights Reserved" status. + +Calum H. (IMB11) and Steveplays must both agree to any changes to this document. diff --git a/fog/LICENSE b/fog/LICENSE new file mode 100644 index 0000000..e7bbae6 --- /dev/null +++ b/fog/LICENSE @@ -0,0 +1,16 @@ +ALL RIGHTS RESERVED + +Copyright (c) 2024-2026 Calum H. (IMB11), Steveplays + +THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Notwithstanding the above, the fog definition files +located within the "resources" or "generated" folder of this source code +project are dedicated to the public domain under the terms +of the Creative Commons Zero (CC0) 1.0 Universal license. diff --git a/fog/branch.gradle.kts b/fog/branch.gradle.kts new file mode 100644 index 0000000..f8f400d --- /dev/null +++ b/fog/branch.gradle.kts @@ -0,0 +1,3 @@ +plugins { + id("imb11.publish-mod") +} diff --git a/fog/build.fabric.gradle.kts b/fog/build.fabric.gradle.kts new file mode 100644 index 0000000..0a969aa --- /dev/null +++ b/fog/build.fabric.gradle.kts @@ -0,0 +1,55 @@ +plugins { + id("imb11.fabric-mod") +} + +stonecutter { + replacements.string { + direction = minecraftVersion == "26.3" + replace("gameRenderer.getMainCamera()", "gameRenderer.mainCamera()") + replace(".gui.getChat()", ".gui.hud.getChat()") + replace(".gui.getBossOverlay()", ".gui.hud.getBossOverlay()") + } +} + +val mruProject = project(":mru:${project.name}") +evaluationDependsOn(mruProject.path) + +val polytoneLibraries = configurations.create("polytoneLibraries") { + isCanBeConsumed = false + isTransitive = false +} + +dependencies { + implementation(project(mruProject.path)) + implementation(mcLibrary("yacl-fabric")) + implementation(mcLibrary("modmenu")) + compileOnly(mcLibrary("iris-fabric")) + if (minecraftVersion == "26.1.2") { + compileOnly(mcLibrary("polytone-fabric")) + add(polytoneLibraries.name, mcLibrary("polytone-fabric")) + compileOnly(files(provider { + polytoneLibraries.files.flatMap { zipTree(it).matching { include("META-INF/jars/*.jar", "META-INF/jarjar/*.jar") }.files } + })) + } +} + +loom { + mods { + register("mru") { + sourceSet(mruProject.extensions.getByType().getByName("main")) + } + } +} + +fabricApi { + configureDataGeneration { + outputDirectory = project.parent!!.file("src/main/generated") + addToResources = false + client = true + } +} + +loom.runs.named("datagen") { + configName = "Fog - ${project.minecraftVersion} - Fabric - Data Generation" + runDir(rootProject.file("run/fog/${project.minecraftVersion}/fabric/datagen").relativeTo(project.projectDir).invariantSeparatorsPath) +} diff --git a/fog/build.neoforge.gradle.kts b/fog/build.neoforge.gradle.kts new file mode 100644 index 0000000..38755f9 --- /dev/null +++ b/fog/build.neoforge.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("imb11.neoforge-mod") +} + +stonecutter { + replacements.string { + direction = minecraftVersion == "26.3" + replace("gameRenderer.getMainCamera()", "gameRenderer.mainCamera()") + replace(".gui.getChat()", ".gui.hud.getChat()") + replace(".gui.getBossOverlay()", ".gui.hud.getBossOverlay()") + } +} + +val mruProject = project(":mru:${project.name}") +evaluationDependsOn(mruProject.path) + +val polytoneLibraries = configurations.create("polytoneLibraries") { + isCanBeConsumed = false + isTransitive = false +} + +dependencies { + implementation(project(mruProject.path)) + implementation(mcLibrary("yacl-neoforge")) + compileOnly(mcLibrary("iris-neoforge")) + if (minecraftVersion == "26.1.2") { + compileOnly(mcLibrary("polytone-neoforge")) + add(polytoneLibraries.name, mcLibrary("polytone-neoforge")) + compileOnly(files(provider { + polytoneLibraries.files.flatMap { zipTree(it).matching { include("META-INF/jars/*.jar", "META-INF/jarjar/*.jar") }.files } + })) + } +} + +neoForge { + interfaceInjectionData.from(mruProject.tasks.named("stonecutterGenerate").map { + mruProject.layout.buildDirectory.file("generated/stonecutter/main/resources/interfaces.json").get() + }) + mods { + register("mru") { + sourceSet(mruProject.extensions.getByType().getByName("main")) + } + } +} diff --git a/fog/docs/media/legacy/fog_looks_good_now_cave_fog.png b/fog/docs/media/legacy/fog_looks_good_now_cave_fog.png new file mode 100644 index 0000000..7ccf0ba Binary files /dev/null and b/fog/docs/media/legacy/fog_looks_good_now_cave_fog.png differ diff --git a/fog/docs/media/legacy/fog_looks_good_now_config_screen.png b/fog/docs/media/legacy/fog_looks_good_now_config_screen.png new file mode 100644 index 0000000..94db16f Binary files /dev/null and b/fog/docs/media/legacy/fog_looks_good_now_config_screen.png differ diff --git a/fog/docs/media/legacy/fog_looks_good_now_lush_cave.png b/fog/docs/media/legacy/fog_looks_good_now_lush_cave.png new file mode 100644 index 0000000..834faa2 Binary files /dev/null and b/fog/docs/media/legacy/fog_looks_good_now_lush_cave.png differ diff --git a/fog/docs/media/legacy/fog_looks_good_now_taiga.png b/fog/docs/media/legacy/fog_looks_good_now_taiga.png new file mode 100644 index 0000000..9e374c0 Binary files /dev/null and b/fog/docs/media/legacy/fog_looks_good_now_taiga.png differ diff --git a/fog/mod.properties b/fog/mod.properties new file mode 100644 index 0000000..3d9c57d --- /dev/null +++ b/fog/mod.properties @@ -0,0 +1,12 @@ +mod.id=fog +mod.name=Fog +mod.description=An expansive and dynamic overhaul to Minecraft's fog rendering system. +mod.license=All-Rights-Reserved +mod.version=1.11.0 +mod.group=dev.imb11.fog +mod.required=mru +mod.environment=client +publish.modrinth=WuGVWUF2 +publish.curseforge=815438 +publish.dependencies.fabric=fabric-api,architectury-api,yacl,mru +publish.dependencies.neoforge=architectury-api,yacl,mru diff --git a/fog/src/main/generated/.cache/479d532b8ab79818d0335395e7c3c8b4e15a0c44 b/fog/src/main/generated/.cache/479d532b8ab79818d0335395e7c3c8b4e15a0c44 new file mode 100644 index 0000000..16ce8b1 --- /dev/null +++ b/fog/src/main/generated/.cache/479d532b8ab79818d0335395e7c3c8b4e15a0c44 @@ -0,0 +1,15 @@ +// 1.21.1 2024-10-19T17:06:20.6411437 Fog/Custom Fog Definition:fog +ed7a26be0cdc64db4e2714898fec43817761c00b assets\minecraft\fog_definitions\biome\crimson_forest.json +01930365bb419a96ae82b2e45b99af5d94b8df5c assets\c\fog_definitions\tag\biome\is_beach.json +61268868389f80ddd2fc175dab578a5a6d3775dd assets\c\fog_definitions\tag\biome\is_aquatic_icy.json +efa18c3764d4d5d57a4ca2f3dabd69d188148a19 assets\minecraft\fog_definitions\biome\soul_sand_valley.json +66dbd1cc3283d1f6a3f9f8c789e67baabc193059 assets\c\fog_definitions\tag\biome\is_snowy.json +081f23017dccbbbbf86d0fed5183724dd3b2fae7 assets\minecraft\fog_definitions\biome\basalt_deltas.json +4057cc9fe572b9cf63a07711d50ab18b01d92d72 assets\c\fog_definitions\tag\biome\is_badlands.json +d18991fdc8b5c612a3ae1b45144585860b1bf064 assets\minecraft\fog_definitions\biome\nether_wastes.json +6ab53206f31ea26518ebf301389f655c2846e67e assets\c\fog_definitions\tag\biome\is_desert.json +024071636ecdb7f6288625a11a90b2d75d65c917 assets\minecraft\fog_definitions\biome\sparse_jungle.json +4a095b16c1146432aee0cd907ceb87d33c031738 assets\c\fog_definitions\tag\biome\is_end.json +5e48288dad15e0c0bfd3db7ada891bc50cdbc5a2 assets\c\fog_definitions\tag\biome\is_jungle.json +450e4e8e01a0af4128b371ad342d4a0d7bd9e560 assets\c\fog_definitions\tag\biome\is_swamp.json +e21ca1bacda76f8e67c3a79262c54bb45b0f70ce assets\minecraft\fog_definitions\biome\warped_forest.json diff --git a/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_aquatic_icy.json b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_aquatic_icy.json new file mode 100644 index 0000000..f3dca22 --- /dev/null +++ b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_aquatic_icy.json @@ -0,0 +1,8 @@ +{ + "colors": { + "day": "#BDDBE1", + "night": "#526C72" + }, + "end_multiplier": 1.0, + "start_multiplier": 1.0 +} \ No newline at end of file diff --git a/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_badlands.json b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_badlands.json new file mode 100644 index 0000000..cbfba6e --- /dev/null +++ b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_badlands.json @@ -0,0 +1,8 @@ +{ + "colors": { + "day": "#BCA199", + "night": "#140c07" + }, + "end_multiplier": 1.0, + "start_multiplier": 1.0 +} \ No newline at end of file diff --git a/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_beach.json b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_beach.json new file mode 100644 index 0000000..ce93ca3 --- /dev/null +++ b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_beach.json @@ -0,0 +1,8 @@ +{ + "colors": { + "day": "#CBCABD", + "night": "#11110e" + }, + "end_multiplier": 1.0, + "start_multiplier": 1.0 +} \ No newline at end of file diff --git a/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_desert.json b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_desert.json new file mode 100644 index 0000000..0369a4b --- /dev/null +++ b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_desert.json @@ -0,0 +1,8 @@ +{ + "colors": { + "day": "#D1C8AB", + "night": "#827D6A" + }, + "end_multiplier": 1.0, + "start_multiplier": 1.0 +} \ No newline at end of file diff --git a/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_end.json b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_end.json new file mode 100644 index 0000000..022e03e --- /dev/null +++ b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_end.json @@ -0,0 +1,8 @@ +{ + "colors": { + "day": "#291d26", + "night": "#291d26" + }, + "end_multiplier": 0.5, + "start_multiplier": 0.5 +} \ No newline at end of file diff --git a/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_jungle.json b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_jungle.json new file mode 100644 index 0000000..23867aa --- /dev/null +++ b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_jungle.json @@ -0,0 +1,8 @@ +{ + "colors": { + "day": "#5B9071", + "night": "#171E23" + }, + "end_multiplier": 0.35, + "start_multiplier": 0.15 +} \ No newline at end of file diff --git a/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_snowy.json b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_snowy.json new file mode 100644 index 0000000..8ff7761 --- /dev/null +++ b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_snowy.json @@ -0,0 +1,8 @@ +{ + "colors": { + "day": "#DFEBF4", + "night": "#687782" + }, + "end_multiplier": 1.0, + "start_multiplier": 1.0 +} \ No newline at end of file diff --git a/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_swamp.json b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_swamp.json new file mode 100644 index 0000000..008b8c8 --- /dev/null +++ b/fog/src/main/generated/assets/c/fog_definitions/tag/biome/is_swamp.json @@ -0,0 +1,8 @@ +{ + "colors": { + "day": "#BDC8C2", + "night": "#5A6459" + }, + "end_multiplier": 1.0, + "start_multiplier": 1.0 +} \ No newline at end of file diff --git a/fog/src/main/generated/assets/minecraft/fog_definitions/biome/basalt_deltas.json b/fog/src/main/generated/assets/minecraft/fog_definitions/biome/basalt_deltas.json new file mode 100644 index 0000000..21d4bf8 --- /dev/null +++ b/fog/src/main/generated/assets/minecraft/fog_definitions/biome/basalt_deltas.json @@ -0,0 +1,8 @@ +{ + "colors": { + "day": "#36292B", + "night": "#36292B" + }, + "end_multiplier": 0.01, + "start_multiplier": 0.8 +} \ No newline at end of file diff --git a/fog/src/main/generated/assets/minecraft/fog_definitions/biome/crimson_forest.json b/fog/src/main/generated/assets/minecraft/fog_definitions/biome/crimson_forest.json new file mode 100644 index 0000000..eae3810 --- /dev/null +++ b/fog/src/main/generated/assets/minecraft/fog_definitions/biome/crimson_forest.json @@ -0,0 +1,8 @@ +{ + "colors": { + "day": "#700f18", + "night": "#700f18" + }, + "end_multiplier": 0.01, + "start_multiplier": 0.8 +} \ No newline at end of file diff --git a/fog/src/main/generated/assets/minecraft/fog_definitions/biome/nether_wastes.json b/fog/src/main/generated/assets/minecraft/fog_definitions/biome/nether_wastes.json new file mode 100644 index 0000000..d242f17 --- /dev/null +++ b/fog/src/main/generated/assets/minecraft/fog_definitions/biome/nether_wastes.json @@ -0,0 +1,8 @@ +{ + "colors": { + "day": "#330808", + "night": "#330808" + }, + "end_multiplier": 0.01, + "start_multiplier": 1.0 +} \ No newline at end of file diff --git a/fog/src/main/generated/assets/minecraft/fog_definitions/biome/soul_sand_valley.json b/fog/src/main/generated/assets/minecraft/fog_definitions/biome/soul_sand_valley.json new file mode 100644 index 0000000..8dc9dce --- /dev/null +++ b/fog/src/main/generated/assets/minecraft/fog_definitions/biome/soul_sand_valley.json @@ -0,0 +1,8 @@ +{ + "colors": { + "day": "#005157", + "night": "#005157" + }, + "end_multiplier": 0.01, + "start_multiplier": 1.0 +} \ No newline at end of file diff --git a/fog/src/main/generated/assets/minecraft/fog_definitions/biome/sparse_jungle.json b/fog/src/main/generated/assets/minecraft/fog_definitions/biome/sparse_jungle.json new file mode 100644 index 0000000..720de2f --- /dev/null +++ b/fog/src/main/generated/assets/minecraft/fog_definitions/biome/sparse_jungle.json @@ -0,0 +1,8 @@ +{ + "colors": { + "day": "#7EBAA2", + "night": "#1A2122" + }, + "end_multiplier": 1.0, + "start_multiplier": 0.75 +} \ No newline at end of file diff --git a/fog/src/main/generated/assets/minecraft/fog_definitions/biome/warped_forest.json b/fog/src/main/generated/assets/minecraft/fog_definitions/biome/warped_forest.json new file mode 100644 index 0000000..dec357c --- /dev/null +++ b/fog/src/main/generated/assets/minecraft/fog_definitions/biome/warped_forest.json @@ -0,0 +1,8 @@ +{ + "colors": { + "day": "#0f4c4c", + "night": "#0f4c4c" + }, + "end_multiplier": 0.01, + "start_multiplier": 0.8 +} \ No newline at end of file diff --git a/fog/src/main/java/dev/imb11/fog/api/CustomFogDefinition.java b/fog/src/main/java/dev/imb11/fog/api/CustomFogDefinition.java new file mode 100644 index 0000000..8c79979 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/api/CustomFogDefinition.java @@ -0,0 +1,134 @@ +package dev.imb11.fog.api; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.minecraft.client.multiplayer.ClientLevel; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +/** + * Represents a custom fog definition. + */ +public final class CustomFogDefinition { + public static CustomFogDefinition getDefault(ClientLevel world) { + return new CustomFogDefinition(1.0f, 1.0f, FogColors.getDefault(world)); + } + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.FLOAT.fieldOf("start_multiplier").forGetter(CustomFogDefinition::startMultiplier), + Codec.FLOAT.fieldOf("end_multiplier").forGetter(CustomFogDefinition::endMultiplier), + FogColors.CODEC.optionalFieldOf("colors", null).forGetter(CustomFogDefinition::colors) + ).apply(instance, CustomFogDefinition::new)); + + private final float startMultiplier; + private final float endMultiplier; + private final @Nullable FogColors colors; + + /** + * @param startMultiplier The multiplier to apply to the fog start distance. + * @param endMultiplier The multiplier to apply to the fog end distance. + * @param colors The colors to apply to the fog. + */ + private CustomFogDefinition(float startMultiplier, float endMultiplier, @Nullable FogColors colors) { + this.startMultiplier = startMultiplier; + this.endMultiplier = endMultiplier; + this.colors = colors; + } + + /** + * @return The multiplier to apply to the fog start distance. + */ + public float startMultiplier() {return startMultiplier;} + + /** + * @return The multiplier to apply to the fog end distance. + */ + public float endMultiplier() {return endMultiplier;} + + /** + * @return The colors to apply to the fog, null if no colors are defined. + */ + public @Nullable FogColors colors() {return colors;} + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (CustomFogDefinition) obj; + return Float.floatToIntBits(this.startMultiplier) == Float.floatToIntBits(that.startMultiplier) && + Float.floatToIntBits(this.endMultiplier) == Float.floatToIntBits(that.endMultiplier) && + Objects.equals(this.colors, that.colors); + } + + @Override + public int hashCode() { + return Objects.hash(startMultiplier, endMultiplier, colors); + } + + @Override + public String toString() { + return "CustomFogDefinition[" + + "startMultiplier=" + startMultiplier + ", " + + "endMultiplier=" + endMultiplier + ", " + + "colors=" + colors + ']'; + } + + /** + * A builder for {@link CustomFogDefinition}. + */ + public static class Builder { + private float startMultiplier = getDefault(null).startMultiplier(); + private float endMultiplier = getDefault(null).endMultiplier(); + private FogColors colors = getDefault(null).colors(); + + public static Builder create() { + return new Builder(); + } + + /** + * @param startMultiplier The multiplier to apply to the fog start distance. + * @return This builder. + */ + public Builder startMultiplier(float startMultiplier) { + this.startMultiplier = startMultiplier; + return this; + } + + /** + * @param endMultiplier The multiplier to apply to the fog end distance. + * @return This builder. + */ + public Builder endMultiplier(float endMultiplier) { + this.endMultiplier = endMultiplier; + return this; + } + + /** + * @param colors The colors to apply to the fog. + * @return This builder. + */ + public Builder colors(FogColors colors) { + this.colors = colors; + return this; + } + + /** + * @param day The color of the fog during the day - in #RRGGBB format. + * @param night The color of the fog during the night - in #RRGGBB format. + * @return This builder. + */ + public Builder colors(String day, String night) { + this.colors = new FogColors(day, night); + return this; + } + + /** + * @return A new custom fog definition using the supplied values or the defaults if not specified. + */ + public CustomFogDefinition build() { + return new CustomFogDefinition(startMultiplier, endMultiplier, colors); + } + } +} diff --git a/fog/src/main/java/dev/imb11/fog/api/FogColors.java b/fog/src/main/java/dev/imb11/fog/api/FogColors.java new file mode 100644 index 0000000..7d0a756 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/api/FogColors.java @@ -0,0 +1,118 @@ +package dev.imb11.fog.api; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import dev.imb11.fog.client.util.color.Color; +import net.minecraft.client.Minecraft; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.attribute.EnvironmentAttributes; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + + +/** + * Represents the colors of the fog during the day and night. + */ +public class FogColors { + public static @NotNull FogColors getDefault(@Nullable ClientLevel world) { + if (world == null || world.dimensionType().skybox() == DimensionType.Skybox.OVERWORLD) { + return new FogColors("#b9d2fd", "#000000"); + } + + var camera = Minecraft.getInstance().gameRenderer.getMainCamera(); + var color = world.environmentAttributes().getValue(EnvironmentAttributes.FOG_COLOR, camera.position()); + Vec3 dayColor = new Color(color).asVec3d(); + return new FogColors(Color.from(dayColor).asHex(), Color.from(dayColor.scale(0.2D)).asHex()); + } + public static final FogColors DEFAULT_CAVE = new FogColors("#212121", "#101010"); + public static final Codec CODEC = RecordCodecBuilder + .create(instance -> instance.group(Codec.STRING.fieldOf("day").forGetter(FogColors::getDay), Codec.STRING.fieldOf("night").forGetter(FogColors::getNight)).apply(instance, FogColors::new)); + + private final @NotNull String day; + private final @NotNull String night; + + private transient @Nullable Color dayCached; + private transient @Nullable Color nightCached; + + /** + * @param day The color of the fog during the day - in #RRGGBB format. + * @param night The color of the fog during the night - in #RRGGBB format. + */ + public FogColors(@NotNull String day, @NotNull String night) { + assert day.matches("^#[0-9a-fA-F]{6}$") : "Invalid day color format: " + day; + assert night.matches("^#[0-9a-fA-F]{6}$") : "Invalid night color format: " + night; + this.day = day; + this.night = night; + } + + /** + * @return The color object of the fog during the day. + */ + public Color getDayColor() { + if (dayCached == null) { + dayCached = Color.parse(day); + } + + return dayCached; + } + + /** + * @return The color object of the fog during the night. + */ + public Color getNightColor() { + if (nightCached == null) { + nightCached = Color.parse(night); + } + + return nightCached; + } + + /** + * @return The color of the fog during the day - in #RRGGBB format. + */ + private @NotNull String getDay() { + return day; + } + + /** + * @return The color of the fog during the night - in #RRGGBB format. + */ + private @NotNull String getNight() { + return night; + } + + /** + * A builder for fog colors. + */ + public static class Builder { + private @NotNull String day = getDefault(null).getDay(); + private @NotNull String night = getDefault(null).getNight(); + + /** + * @param day The color of the fog during the day - in #RRGGBB format. + * @return The builder. + */ + public @NotNull Builder day(@NotNull String day) { + this.day = day; + return this; + } + + /** + * @param night The color of the fog during the night - in #RRGGBB format. + * @return The builder. + */ + public @NotNull Builder night(@NotNull String night) { + this.night = night; + return this; + } + + /** + * @return The fog colors built from the builder, or using the default values if not specified. + */ + public @NotNull FogColors build() { + return new FogColors(day, night); + } + } +} diff --git a/fog/src/main/java/dev/imb11/fog/api/providers/CustomFogDefinitionDataProvider.java b/fog/src/main/java/dev/imb11/fog/api/providers/CustomFogDefinitionDataProvider.java new file mode 100644 index 0000000..e6c5eaa --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/api/providers/CustomFogDefinitionDataProvider.java @@ -0,0 +1,72 @@ +/*? if fabric && >=1.20.6 {*/ +package dev.imb11.fog.api.providers; + +import dev.imb11.fog.api.CustomFogDefinition; +import dev.imb11.fog.client.resource.FogResourceReloader; +import net.fabricmc.fabric.api.datagen.v1.FabricPackOutput; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricCodecDataProvider; +import net.minecraft.data.PackOutput; +import net.minecraft.core.HolderLookup; +import net.minecraft.tags.TagKey; +import net.minecraft.resources.Identifier; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.levelgen.structure.Structure; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; + +import static dev.imb11.fog.client.resource.FogResourceReloader.FOG_DEFINITIONS_FOLDER_NAME; + +public abstract class CustomFogDefinitionDataProvider extends FabricCodecDataProvider { + private final FabricPackOutput output; + + public CustomFogDefinitionDataProvider(@NotNull FabricPackOutput dataOutput, @NotNull CompletableFuture lookup) { + super(dataOutput, lookup, PackOutput.Target.RESOURCE_PACK, FOG_DEFINITIONS_FOLDER_NAME, CustomFogDefinition.CODEC); + output = dataOutput; + } + + /** + * Accepts all custom fog definitions for biomes. + * + * @param provider A consumer that accepts the {@link Identifier} of the biome, and {@link CustomFogDefinition} to apply. + */ + public void acceptBiomes(@NotNull BiConsumer provider) {} + + /** + * Accepts all custom fog definitions for biome tags. + * + * @param provider A consumer that accepts the {@link Identifier} of the biome tag, and {@link CustomFogDefinition} to apply. + */ + public void acceptBiomeTags(@NotNull BiConsumer, CustomFogDefinition> provider) {} + + /** + * @param provider A consumer that accepts the {@link Identifier} of the structure, and the {@link CustomFogDefinition} to apply. + * @deprecated Not yet implemented, structure fog definitions are loaded, but are not applied to the game. + */ + @SuppressWarnings("DeprecatedIsStillUsed") + @Deprecated + public void acceptStructures(BiConsumer provider) {} + + /** + * @param provider A consumer that accepts the {@link Identifier} of the structure tag, and {@link CustomFogDefinition} to apply. + * @deprecated Not yet implemented, structure fog definitions are loaded, but are not applied to the game. + */ + @SuppressWarnings("DeprecatedIsStillUsed") + @Deprecated + public void acceptStructureTags(BiConsumer, CustomFogDefinition> provider) {} + + protected void configure(BiConsumer provider, HolderLookup.Provider lookup) { + acceptBiomes((id, fog) -> provider.accept(id.withPrefix(FogResourceReloader.BIOME_FOLDER_NAME + "/"), fog)); + acceptBiomeTags((tag, fog) -> provider.accept(tag.location().withPrefix(FogResourceReloader.BIOME_TAGS_FOLDER_NAME + "/"), fog)); + acceptStructures((id, fog) -> provider.accept(id.withPrefix(FogResourceReloader.STRUCTURE_FOLDER_NAME + "/"), fog)); + acceptStructureTags( + (tag, fog) -> provider.accept(tag.location().withPrefix(FogResourceReloader.STRUCTURE_TAGS_FOLDER_NAME + "/"), fog)); + } + + @Override + public String getName() { + return "Custom Fog Definition:" + this.output.getModId(); + } +} +/*?}*/ diff --git a/fog/src/main/java/dev/imb11/fog/client/FogClient.java b/fog/src/main/java/dev/imb11/fog/client/FogClient.java new file mode 100644 index 0000000..9ed37b5 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/FogClient.java @@ -0,0 +1,46 @@ +package dev.imb11.fog.client; + +import cc.cassian.mru.Platform; +import dev.imb11.fog.client.command.FogClientCommands; +import dev.imb11.fog.client.resource.FogResourceReloader; +import dev.imb11.fog.client.util.FogKeybinds; +import dev.imb11.fog.config.FogConfig; +//? fabric { +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; +import net.fabricmc.fabric.api.resource.v1.ResourceLoader; +//?} +import net.minecraft.server.packs.PackType; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.file.Path; + +public class FogClient { + public static final @NotNull String MOD_ID = "fog"; + public static final @NotNull String MOD_NAME = "Fog"; + public static final @NotNull Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + + public static Path getConfigPath(String configFileName, String configExtension) { + return Platform.INSTANCE.configPath().resolve(configFileName + "." + configExtension); + } + + public static boolean isModInstalled(String modid) { + return Platform.INSTANCE.isLoaded(modid); + } + + public static void initialize() { + LOGGER.info("Loading {}.", MOD_NAME); + FogConfig.load(); + + FogKeybinds.init(); + //? fabric { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, context) -> { + FogClientCommands.register(dispatcher); + }); + ResourceLoader.get(PackType.CLIENT_RESOURCES).registerReloadListener(FogResourceReloader.IDENTIFIER, new FogResourceReloader()); + ClientTickEvents.END_LEVEL_TICK.register((level)->FogManager.getInstance().onEndTick(level)); + //?} + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/FogManager.java b/fog/src/main/java/dev/imb11/fog/client/FogManager.java new file mode 100644 index 0000000..075f582 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/FogManager.java @@ -0,0 +1,290 @@ +package dev.imb11.fog.client; + +import dev.imb11.fog.api.CustomFogDefinition; +import dev.imb11.fog.api.FogColors; +import dev.imb11.fog.client.compat.polytone.PolytoneCompat; +import dev.imb11.fog.client.registry.FogRegistry; +import dev.imb11.fog.client.util.TickUtil; +import dev.imb11.fog.client.util.color.Color; +import dev.imb11.fog.client.util.math.DarknessCalculation; +import dev.imb11.fog.client.util.math.InterpolatedValue; +import dev.imb11.fog.client.util.math.MathUtil; +import dev.imb11.fog.client.util.player.PlayerUtil; +import dev.imb11.fog.client.util.world.ClientWorldUtil; +import dev.imb11.fog.config.FogConfig; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.attribute.EnvironmentAttributes; +import net.minecraft.util.ARGB; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class FogManager { + public static FogManager INSTANCE = new FogManager(); + + public final InterpolatedValue raininess; + public final InterpolatedValue undergroundness; + public final InterpolatedValue fogStart; + public final InterpolatedValue fogEnd; + public final InterpolatedValue darkness; + public final InterpolatedValue fogColorRed; + public final InterpolatedValue fogColorGreen; + public final InterpolatedValue fogColorBlue; + public final InterpolatedValue currentSkyLight; + public final InterpolatedValue currentBlockLight; + public final InterpolatedValue currentLight; + public final InterpolatedValue currentStartMultiplier; + public final InterpolatedValue currentEndMultiplier; + + public boolean hasSetup = false; + + public FogManager() { + @NotNull FogConfig config = FogConfig.getInstance(); + + raininess = new InterpolatedValue(0.0f, config.raininessTransitionSpeed); + undergroundness = new InterpolatedValue(0.0f, config.undergroundnessTransitionSpeed); + fogStart = new InterpolatedValue(config.initialFogStart, config.fogStartTransitionSpeed); + fogEnd = new InterpolatedValue(config.initialFogEnd, config.fogEndTransitionSpeed); + darkness = new InterpolatedValue(0.0f, config.darknessTransitionSpeed); + fogColorRed = new InterpolatedValue(-1.0f, config.fogColorTransitionSpeed); + fogColorGreen = new InterpolatedValue(-1.0f, config.fogColorTransitionSpeed); + fogColorBlue = new InterpolatedValue(-1.0f, config.fogColorTransitionSpeed); + currentSkyLight = new InterpolatedValue(16.0F); + currentBlockLight = new InterpolatedValue(16.0F); + currentLight = new InterpolatedValue(16.0F); + currentStartMultiplier = new InterpolatedValue(1.0F, config.startMultiplierTransitionSpeed); + currentEndMultiplier = new InterpolatedValue(1.0F, config.endMultiplierTransitionSpeed); + + fogStart.resetTo(config.initialFogStart); + fogEnd.resetTo(config.initialFogEnd); + } + + public static @NotNull FogManager getInstance() { + return INSTANCE; + } + + public static boolean isInDisabledBiome() { + @NotNull var client = Minecraft.getInstance(); + @Nullable var world = client.level; + @Nullable var player = client.player; + if (world == null || player == null) { + return false; + } + + return FogConfig.getInstance().disabledBiomes.contains(world.getBiome(player.blockPosition()).unwrapKey().map(key -> key.identifier().toString()).orElse("")); + } + + private static float getBlendFactor(@NotNull ClientLevel world) { + long time = Math.floorMod(world.getDefaultClockTime(), 24000); + float blendFactor; + if (time < 11000) { + // Daytime + blendFactor = 1.0f; + } else if (time < 13000) { + // Blend from day to night + blendFactor = MathUtil.lerp(1.0f, 0.0f, (time - 11000) / 2000f); + } else if (time < 22000) { + // Nighttime + blendFactor = 0.0f; + } else if (time < 23000) { + // Blend from night to day + blendFactor = MathUtil.lerp(0.0f, 1.0f, (time - 22000) / 1000f); + } else { + // Constant day from 23000 to 24000 ticks + blendFactor = 1.0f; + } + return blendFactor; + } + + public void onEndTick(@NotNull ClientLevel clientWorld) { + @NotNull final var client = Minecraft.getInstance(); + @Nullable final var clientPlayer = client.player; + if (clientPlayer == null) { + return; + } + + @Nullable final BlockPos clientPlayerBlockPosition = clientPlayer.blockPosition(); + if (clientPlayerBlockPosition == null) { + return; + } + + var isClientPlayerAboveGround = PlayerUtil.isPlayerAboveGround(clientPlayer); + if (isClientPlayerAboveGround) { + this.undergroundness.interpolate(0f); + } else { + this.undergroundness.interpolate(1f); + } + + if (isClientPlayerAboveGround && clientWorld.getBiome( + clientPlayer.blockPosition()).value().hasPrecipitation() && clientWorld.isRaining()) { + raininess.interpolate(clientWorld.isThundering() ? 1f : 0.5f); + } else { + raininess.interpolate(0f); + } + + float density = ClientWorldUtil.isFogDenseAtPosition(clientWorld, clientPlayerBlockPosition) ? 0.9f : 1.0f; + float tickDelta = TickUtil.getTickDelta(); + + DarknessCalculation darknessCalculation = DarknessCalculation.of( + client, fogStart.getDefaultValue(), fogEnd.getDefaultValue() * density, tickDelta); + var biomeKey = clientWorld.getBiome(clientPlayer.blockPosition()); + @NotNull var clientPlayerBiomeKeyOptional = biomeKey.unwrapKey(); + if (clientPlayerBiomeKeyOptional.isEmpty()) { + return; + } + + CustomFogDefinition fogDefinition = FogRegistry.getFogDefinitionOrDefault( + clientPlayerBiomeKeyOptional.get().identifier(), clientWorld); + @Nullable FogColors colors = fogDefinition.colors(); + if (colors == null || !FogConfig.getInstance().enableBiomeSpecificFogColors) { + colors = FogColors.getDefault(clientWorld); + } + float blendFactor = getBlendFactor(clientWorld); + Color finalNightColor = getFinalNightColor(clientWorld, colors); + + // Base day/night color blending + float red = Mth.lerp(blendFactor, finalNightColor.red / 255f, colors.getDayColor().red / 255f); + float green = Mth.lerp(blendFactor, finalNightColor.green / 255f, colors.getDayColor().green / 255f); + float blue = Mth.lerp(blendFactor, finalNightColor.blue / 255f, colors.getDayColor().blue / 255f); + + Color polytoneColor = PolytoneCompat.getFogColorFromPolytone(tickDelta); + if (polytoneColor != null) { + red = polytoneColor.red / 255f; + green = polytoneColor.green / 255f; + blue = polytoneColor.blue / 255f; + } + + if (!hasSetup) { + this.fogColorRed.set(red); + this.fogColorGreen.set(green); + this.fogColorBlue.set(blue); + hasSetup = true; + } else { + this.fogColorRed.interpolate(red); + this.fogColorGreen.interpolate(green); + this.fogColorBlue.interpolate(blue); + } + + this.currentStartMultiplier.interpolate(fogDefinition.startMultiplier()); + this.currentEndMultiplier.interpolate(fogDefinition.endMultiplier()); + + this.fogStart.interpolate(darknessCalculation.fogStart()); + this.fogEnd.interpolate(darknessCalculation.fogEnd()); + this.darkness.interpolate(darknessCalculation.darknessValue()); + + this.currentSkyLight.interpolate(clientWorld.getBrightness(LightLayer.SKY, clientPlayerBlockPosition)); + this.currentBlockLight.interpolate(clientWorld.getBrightness(LightLayer.BLOCK, clientPlayerBlockPosition)); + this.currentLight.interpolate(clientWorld.getMaxLocalRawBrightness(clientPlayerBlockPosition, 0)); + } + + private @NotNull Color getFinalNightColor(@NotNull ClientLevel world, FogColors fogColors) { + if (!FogConfig.getInstance().enableMoonFogColorInfluence) { + return fogColors.getNightColor(); + } + + @NotNull Color newMoonColor = Color.from(FogConfig.getInstance().newMoonColor); + float blendFactor = switch (world.environmentAttributes().getValue(EnvironmentAttributes.MOON_PHASE, Minecraft.getInstance().gameRenderer.getMainCamera().position()).index()) { + case 0 -> 0.0f; + case 1, 7 -> 0.25f; + case 2, 6 -> 0.5f; + case 3, 5 -> 0.75f; + case 4 -> 1.0f; + default -> 1.0f; + }; + return fogColors.getNightColor().lerp(newMoonColor, blendFactor); + } + + public float getUndergroundFactor(@NotNull Minecraft client, float tickDelta) { + @Nullable var clientCamera = client.getCameraEntity(); + @Nullable var clientWorld = client.level; + if (clientCamera == null || clientWorld == null) { + return 0.0F; + } + + float clientCameraYPosition = (float) clientCamera.getY(); + float seaLevel = clientWorld.getSeaLevel(); + // Map the client camera's Y position to a factor between 0 and 1 based on the sea level (+/- 32) + float yFactor = Mth.clamp( + MathUtil.mapRange(seaLevel - 32.0F, seaLevel + 32.0F, 1.0F, 0.0F, clientCameraYPosition), 0.0F, 1.0F); + float undergroundnessValue = this.undergroundness.get(tickDelta); + float skyLight = this.currentSkyLight.get(tickDelta); + // Calculate the underground factor by lerping between yFactor, undergroundness, and sky light + return Mth.lerp(yFactor, 1.0F - undergroundnessValue, skyLight / 16.0F); + } + + public @NotNull FogSettings getFogSettings(float tickDelta, float viewDistance) { + @NotNull var fogConfig = FogConfig.getInstance(); + float fogStart = this.fogStart.get(tickDelta) * this.currentStartMultiplier.get(tickDelta); + float fogEnd = this.fogEnd.get(tickDelta) * this.currentEndMultiplier.get(tickDelta); + float fogRed = this.fogColorRed.get(tickDelta); + float fogGreen = this.fogColorGreen.get(tickDelta); + float fogBlue = this.fogColorBlue.get(tickDelta); + + // Sunrise/sunset + float[] sunriseSunsetAdjustedFogColors = blendFogColorWithSunriseSunsetColors( + Minecraft.getInstance(), fogRed, fogGreen, fogBlue, tickDelta); + fogRed = sunriseSunsetAdjustedFogColors[0]; + fogGreen = sunriseSunsetAdjustedFogColors[1]; + fogBlue = sunriseSunsetAdjustedFogColors[2]; + + // Darkness + float darknessFogColorMultiplier = 1f - this.darkness.get(tickDelta); + fogRed *= darknessFogColorMultiplier; + fogGreen *= darknessFogColorMultiplier; + fogBlue *= darknessFogColorMultiplier; + + // "Undergroundness" + float undergroundness = this.undergroundness.get(tickDelta); + float undergroundFogMultiplier = 1f - undergroundness * fogConfig.undergroundFogMultiplier; + fogStart *= undergroundFogMultiplier; + fogEnd *= undergroundFogMultiplier; + + // Raininess + float rainFogMultiplier = 1f - Math.clamp(this.raininess.get(tickDelta) - undergroundness, 0f, 1f) * fogConfig.rainFogMultiplier; + fogStart *= rainFogMultiplier; + fogEnd *= Math.clamp(rainFogMultiplier, 0.5f, 1f); + fogRed *= rainFogMultiplier; + fogGreen *= rainFogMultiplier; + fogBlue *= rainFogMultiplier; + + return new FogSettings(fogStart * viewDistance, fogEnd * viewDistance, fogRed, fogGreen, fogBlue); + } + + /** + * Applies sunrise/sunset color blending to fog color. + * Uses vanilla Minecraft's sunset detection for accurate timing. + */ + private float[] blendFogColorWithSunriseSunsetColors(@NotNull Minecraft client, float red, float green, float blue, float tickDelta) { + if (!FogConfig.getInstance().enableSunFogColorInfluence || client.level == null) { + return new float[]{red, green, blue}; + } + + var probe = client.gameRenderer.getMainCamera().attributeProbe(); + var sunsetColor = probe.getValue(EnvironmentAttributes.SUNRISE_SUNSET_COLOR, tickDelta); + //? if <26.3 { + float alpha = ARGB.alphaFloat(sunsetColor); + //?} else { + /*float alpha = sunsetColor.w(); + *///?} + if (alpha > 0.0F) { + float sunAngle = probe.getValue(EnvironmentAttributes.SUN_ANGLE, tickDelta) * Mth.DEG_TO_RAD; + float blend = Mth.clamp(1.0F - Math.abs(Mth.cos(sunAngle)) / 0.4F, 0.0F, 1.0F); + blend = blend * blend * (3.0F - 2.0F * blend) * 0.7F; + //? if <26.3 { + red = Mth.lerp(blend, red, ARGB.redFloat(sunsetColor)); + green = Mth.lerp(blend, green, ARGB.greenFloat(sunsetColor)); + blue = Mth.lerp(blend, blue, ARGB.blueFloat(sunsetColor)); + //?} else { + /*red = Mth.lerp(blend, red, sunsetColor.x()); + green = Mth.lerp(blend, green, sunsetColor.y()); + blue = Mth.lerp(blend, blue, sunsetColor.z()); + *///?} + } + return new float[]{red, green, blue}; + } + + public record FogSettings(double fogStart, double fogEnd, float fogRed, float fogGreen, float fogBlue) {} +} diff --git a/fog/src/main/java/dev/imb11/fog/client/command/FogClientCommands.java b/fog/src/main/java/dev/imb11/fog/client/command/FogClientCommands.java new file mode 100644 index 0000000..d79aa0b --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/command/FogClientCommands.java @@ -0,0 +1,130 @@ +package dev.imb11.fog.client.command; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import dev.imb11.fog.client.FogManager; +import dev.imb11.fog.client.util.TickUtil; +import dev.imb11.fog.client.util.color.Color; +import dev.imb11.fog.config.FogConfig; +//? fabric { +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import static net.fabricmc.fabric.api.client.command.v2.ClientCommands.literal; +//?} else { +/* +import net.minecraft.commands.CommandSourceStack; +import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal; +*///?} +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.network.chat.Component; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.MutableComponent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class FogClientCommands { + //~ if fabric 'CommandSourceStack'->'FabricClientCommandSource' { + public static void register(CommandDispatcher dispatcher) { + LiteralArgumentBuilder fogNode = literal("fog"); + + fogNode = fogNode.then(LiteralArgumentBuilder.literal("reset").executes(commandContext -> reset(new ClientCommandContext(commandContext)))); + + fogNode = fogNode.then(LiteralArgumentBuilder.literal("toggle").executes(commandContext -> toggle(new ClientCommandContext(commandContext)))); + + fogNode = fogNode.then(LiteralArgumentBuilder.literal("debug").executes(commandContext -> outputDebug(new ClientCommandContext(commandContext)))); + + dispatcher.register(fogNode); + } + //~} + + private static int outputDebug(ClientCommandContext commandContext) { + @NotNull var client = Minecraft.getInstance(); + @Nullable ClientLevel clientWorld = client.level; + if (clientWorld == null) { + commandContext.sendFailure(Component.translatable("fog.command.debug.failure")); + return 0; + } + + @NotNull FogManager manager = FogManager.INSTANCE; + float tickDelta = TickUtil.getTickDelta(); + @NotNull Color fogColor = new Color((int) (manager.fogColorRed.get(tickDelta) * 255), + (int) (manager.fogColorGreen.get(tickDelta) * 255), (int) (manager.fogColorBlue.get(tickDelta) * 255)); + @NotNull String fogColorHex = String.format("#§c%02x§a%02x§9%02x", fogColor.red, fogColor.green, fogColor.blue); + + @SuppressWarnings("TextBlockMigration") @NotNull String debugInfoTable = String.format( + "§b§7[§rFog§b§7]§r Current Fog Manager State:\n" + + "§b§7[§rFog§b§7]§r Raininess: §6%.2f§r\n" + + "§b§7[§rFog§b§7]§r \"Undergroundness\": §6%.2f§r\n" + + "§b§7[§rFog§b§7]§r Fog Start: §6%.2f§r\n" + + "§b§7[§rFog§b§7]§r Fog End: §6%.2f§r\n" + + "§b§7[§rFog§b§7]§r Darkness: §6%.2f§r\n" + + "§b§7[§rFog§b§7]§r Fog Color: §6%s§r\n" + + "§b§7[§rFog§b§7]§r Current Sky Light: §6%.2f§r\n" + + "§b§7[§rFog§b§7]§r Current Block Light: §6%.2f§r\n" + + "§b§7[§rFog§b§7]§r Current Light: §6%.2f§r\n" + + "§b§7[§rFog§b§7]§r Current Start Multiplier: §6%.2f§r\n" + + "§b§7[§rFog§b§7]§r Current End Multiplier: §6%.2f§r", + manager.raininess.get(tickDelta), + manager.undergroundness.get(tickDelta), + manager.fogStart.get(tickDelta), + manager.fogEnd.get(tickDelta), + manager.darkness.get(tickDelta), + fogColorHex, + manager.currentSkyLight.get(tickDelta), + manager.currentBlockLight.get(tickDelta), + manager.currentLight.get(tickDelta), + manager.currentStartMultiplier.get(tickDelta), + manager.currentEndMultiplier.get(tickDelta) + ); + + commandContext.sendFeedback(Component.literal(debugInfoTable)); + return 1; + } + + private static int reset(@NotNull ClientCommandContext commandContext) { + FogConfig.load(); + FogManager.INSTANCE = new FogManager(); + commandContext.sendFeedback( + Component.literal("§b§7[§rFog§b§7]§r ").append(Component.translatable("fog.command.reset").withStyle(ChatFormatting.GOLD))); + return 1; + } + + private static int toggle(@NotNull ClientCommandContext commandContext) { + FogConfig config = FogConfig.getInstance(); + config.enableMod = !config.enableMod; + + FogConfig.save(); + + commandContext.sendFeedback(Component.literal("§b§7[§rFog§b§7]§r ").append( + Component.translatable("fog.command.toggle." + (config.enableMod ? "enabled" : "disabled")).withStyle(ChatFormatting.GOLD))); + + return 1; + } + + //? fabric { + + private record ClientCommandContext(CommandContext commandContext) { + public void sendFailure(MutableComponent failure) { + commandContext.getSource().sendError(failure); + } + + public void sendFeedback(MutableComponent feedback) { + commandContext.getSource().sendFeedback(feedback); + + } + } + //?} else { + + /*private record ClientCommandContext(CommandContext commandContext) { + + public void sendFailure(MutableComponent failure) { + commandContext.getSource().sendFailure(failure); + } + + public void sendFeedback(MutableComponent feedback) { + commandContext.getSource().sendSuccess(()-> feedback, false); + } + } + *///?} +} diff --git a/fog/src/main/java/dev/imb11/fog/client/compat/modmenu/FogClientModMenuCompat.java b/fog/src/main/java/dev/imb11/fog/client/compat/modmenu/FogClientModMenuCompat.java new file mode 100644 index 0000000..c18ffcc --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/compat/modmenu/FogClientModMenuCompat.java @@ -0,0 +1,14 @@ +/*? if fabric {*/ +package dev.imb11.fog.client.compat.modmenu; + +import com.terraformersmc.modmenu.api.ConfigScreenFactory; +import com.terraformersmc.modmenu.api.ModMenuApi; +import dev.imb11.fog.config.FogConfig; + +public class FogClientModMenuCompat implements ModMenuApi { + @Override + public ConfigScreenFactory getModConfigScreenFactory() { + return parent -> FogConfig.getInstance().getYetAnotherConfigLibInstance().generateScreen(parent); + } +} +/*?}*/ diff --git a/fog/src/main/java/dev/imb11/fog/client/compat/polytone/IrisCompat.java b/fog/src/main/java/dev/imb11/fog/client/compat/polytone/IrisCompat.java new file mode 100644 index 0000000..b0c1303 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/compat/polytone/IrisCompat.java @@ -0,0 +1,13 @@ +package dev.imb11.fog.client.compat.polytone; + +import dev.imb11.fog.client.FogClient; +import dev.imb11.fog.config.FogConfig; +import net.irisshaders.iris.api.v0.IrisApi; + +public class IrisCompat { + public static boolean shouldDisableMod() { + return FogClient.isModInstalled("iris") + && FogConfig.getInstance().disableModWhenIrisShaderPackIsEnabled + && IrisApi.getInstance().isShaderPackInUse(); + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/compat/polytone/PolytoneCompat.java b/fog/src/main/java/dev/imb11/fog/client/compat/polytone/PolytoneCompat.java new file mode 100644 index 0000000..b2dc096 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/compat/polytone/PolytoneCompat.java @@ -0,0 +1,47 @@ +package dev.imb11.fog.client.compat.polytone; + +import dev.imb11.fog.client.FogClient; +import dev.imb11.fog.client.util.color.Color; +import dev.imb11.fog.config.FogConfig; +import net.minecraft.client.Minecraft; +import net.minecraft.world.attribute.EnvironmentAttributes; +//? if <26.3 { +import net.mehvahdjukaar.polytone.Polytone; +//?} +import org.jetbrains.annotations.Nullable; + +public class PolytoneCompat { + public static boolean shouldUsePolytone() { + //? if <26.3 { + return FogClient.isModInstalled("polytone") && FogConfig.getInstance().prioritizePolytoneFogDefinitions; + //?} else { + /*return false; + *///?} + } + + public static @Nullable Color getFogColorFromPolytone(float partialTick) { + //? if <26.3 { + if (!shouldUsePolytone()) { + return null; + } + + var client = Minecraft.getInstance(); + var level = client.level; + if (level == null) { + return null; + } + + var camera = client.gameRenderer.getMainCamera(); + var position = camera.position(); + var biome = level.getBiomeManager().getNoiseBiomeAtPosition(position.x, position.y, position.z).value(); + var effects = Polytone.BIOME_MODIFIERS.modifiersByBiome().get(biome); + if (effects == null || !effects.attributeModifications().getAllModifiedAttributes().contains(EnvironmentAttributes.FOG_COLOR)) { + return null; + } + + return new Color(camera.attributeProbe().getValue(EnvironmentAttributes.FOG_COLOR, partialTick)); + //?} else { + /*return null; + *///?} + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/registry/FogRegistry.java b/fog/src/main/java/dev/imb11/fog/client/registry/FogRegistry.java new file mode 100644 index 0000000..073f0ca --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/registry/FogRegistry.java @@ -0,0 +1,92 @@ +package dev.imb11.fog.client.registry; + +import dev.imb11.fog.api.CustomFogDefinition; + +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.core.registries.Registries; +import net.minecraft.tags.TagKey; +import net.minecraft.resources.Identifier; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.levelgen.structure.Structure; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public class FogRegistry { + private static final Map, CustomFogDefinition> STRUCTURE_TAG_FOG_REGISTRY = new ConcurrentHashMap<>(); + private static final Map STRUCTURE_FOG_REGISTRY = new ConcurrentHashMap<>(); + private static final Map, CustomFogDefinition> BIOME_TAG_FOG_REGISTRY = new ConcurrentHashMap<>(); + private static final Map BIOME_FOG_REGISTRY = new ConcurrentHashMap<>(); + private static final Map TAGGED_BIOME_TO_FOG_CACHE = new ConcurrentHashMap<>(); + private static final Map> TAGGED_BIOME_SKIP_LIST = new ConcurrentHashMap<>(); + + public static @NotNull Map, CustomFogDefinition> getStructureTagFogRegistry() { + return STRUCTURE_TAG_FOG_REGISTRY; + } + + public static @NotNull Map getStructureFogRegistry() { + return STRUCTURE_FOG_REGISTRY; + } + + public static @NotNull Map, CustomFogDefinition> getBiomeTagFogRegistry() { + return BIOME_TAG_FOG_REGISTRY; + } + + public static @NotNull Map getBiomeFogRegistry() { + return BIOME_FOG_REGISTRY; + } + + public static @NotNull CustomFogDefinition getFogDefinitionOrDefault(@NotNull Identifier biomeId, @NotNull ClientLevel world) { + CustomFogDefinition biomeFogDefinition = getBiomeFogRegistry().get(biomeId); + if (biomeFogDefinition != null) { + return biomeFogDefinition; + } + + Identifier cachedFogId = TAGGED_BIOME_TO_FOG_CACHE.get(biomeId); + if (cachedFogId != null) { + return getBiomeTagFogRegistry().get(TagKey.create(Registries.BIOME, cachedFogId)); + } + + Set skippedTags = TAGGED_BIOME_SKIP_LIST.getOrDefault(biomeId, new HashSet<>()); + + Registry biomeRegistry = world.registryAccess().lookupOrThrow(Registries.BIOME); + + for (var biomeTagFogEntry : getBiomeTagFogRegistry().entrySet()) { + TagKey tagKey = biomeTagFogEntry.getKey(); + Identifier tagId = tagKey.location(); + + if (skippedTags.contains(tagId)) { + continue; + } + + var entryListOptional = biomeRegistry.get(tagKey); + + if (entryListOptional.isPresent()) { + var entryList = entryListOptional.get(); + for (var entry : entryList) { + //noinspection OptionalGetWithoutIsPresent + if (entry.unwrapKey().orElseThrow().identifier().equals(biomeId)) { + TAGGED_BIOME_TO_FOG_CACHE.put(biomeId, tagId); + TAGGED_BIOME_SKIP_LIST.put(biomeId, skippedTags); + return biomeTagFogEntry.getValue(); + } + } + skippedTags.add(tagId); + } + } + + TAGGED_BIOME_SKIP_LIST.put(biomeId, skippedTags); + return CustomFogDefinition.getDefault(world); + } + + public static void resetCaches() { + TAGGED_BIOME_TO_FOG_CACHE.clear(); + TAGGED_BIOME_SKIP_LIST.clear(); + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/resource/FogResourceReloader.java b/fog/src/main/java/dev/imb11/fog/client/resource/FogResourceReloader.java new file mode 100644 index 0000000..b2883cb --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/resource/FogResourceReloader.java @@ -0,0 +1,92 @@ +package dev.imb11.fog.client.resource; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.mojang.serialization.JsonOps; +import dev.imb11.fog.api.CustomFogDefinition; +import dev.imb11.fog.client.FogClient; +import dev.imb11.fog.client.registry.FogRegistry; + +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.core.registries.Registries; +import net.minecraft.tags.TagKey; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.server.packs.resources.SimplePreparableReloadListener; +import net.minecraft.resources.Identifier; +import net.minecraft.util.profiling.ProfilerFiller; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.Map; +import java.util.function.Function; + +import static dev.imb11.fog.client.FogClient.MOD_ID; + +public class FogResourceReloader extends SimplePreparableReloadListener { + public static final @NotNull Identifier IDENTIFIER = Identifier.fromNamespaceAndPath(MOD_ID, "resource_reloader"); + private static final @NotNull String TAG_FOLDER_NAME = "tag"; + public static final @NotNull String FOG_DEFINITIONS_FOLDER_NAME = "fog_definitions"; + public static final @NotNull String STRUCTURE_FOLDER_NAME = "structure"; + public static final @NotNull String STRUCTURE_TAGS_FOLDER_NAME = String.format("%s/%s", TAG_FOLDER_NAME, STRUCTURE_FOLDER_NAME); + public static final @NotNull String BIOME_FOLDER_NAME = "biome"; + public static final @NotNull String BIOME_TAGS_FOLDER_NAME = String.format("%s/%s", TAG_FOLDER_NAME, BIOME_FOLDER_NAME); + + private static final @NotNull Gson GSON = new Gson(); + private static final @NotNull String JSON_FILE_SUFFIX = ".json"; + + /** + * The preparation stage, ran on worker threads. + */ + @Override + protected @Nullable Void prepare(ResourceManager resourceManager, ProfilerFiller profiler) { + FogRegistry.resetCaches(); + + loadTaggedFogs(resourceManager, STRUCTURE_TAGS_FOLDER_NAME, FogRegistry.getStructureTagFogRegistry(), Registries.STRUCTURE); + loadTaggedFogs(resourceManager, BIOME_TAGS_FOLDER_NAME, FogRegistry.getBiomeTagFogRegistry(), Registries.BIOME); + loadFogs(resourceManager, STRUCTURE_FOLDER_NAME, FogRegistry.getStructureFogRegistry()); + loadFogs(resourceManager, BIOME_FOLDER_NAME, FogRegistry.getBiomeFogRegistry()); + return null; + } + + /** + * The apply stage, ran on the main thread. + */ + @Override + protected void apply(@Nullable Void prepared, ResourceManager resourceManager, ProfilerFiller profiler) { + // NO-OP + } + + private void loadFogs(@NotNull ResourceManager resourceManager, @NotNull String folderName, @NotNull Map fogRegistry, @NotNull Function keyGenerator) { + fogRegistry.clear(); + + @NotNull var jsonFogs = resourceManager.listResources(String.format("%s/%s", FOG_DEFINITIONS_FOLDER_NAME, folderName), identifier -> identifier.toString().endsWith(JSON_FILE_SUFFIX)); + for (@NotNull var jsonFog : jsonFogs.entrySet()) { + @NotNull var jsonFogPath = jsonFog.getKey(); + @NotNull var jsonFogPathSplit = jsonFogPath.getPath().replace(JSON_FILE_SUFFIX, "").split("/"); + @NotNull var fogIdentifier = Identifier.fromNamespaceAndPath(jsonFogPath.getNamespace(), jsonFogPathSplit[jsonFogPathSplit.length - 1]); + K fogKey = keyGenerator.apply(fogIdentifier.toString()); + + if (fogRegistry.containsKey(fogKey)) { + continue; + } + + try { + fogRegistry.put(fogKey, + CustomFogDefinition.CODEC.parse(JsonOps.INSTANCE, GSON.fromJson(new String(jsonFog.getValue().open().readAllBytes()), JsonElement.class)).result().orElseThrow()); + } catch (IOException e) { + FogClient.LOGGER.error("Exception thrown while deserializing a fog definition (identifier: {}): {}", fogIdentifier, e); + } + } + } + + private void loadTaggedFogs(@NotNull ResourceManager resourceManager, @NotNull String folderName, @NotNull Map, CustomFogDefinition> fogRegistry, + ResourceKey> registryKey) { + loadFogs(resourceManager, folderName, fogRegistry, identifier -> TagKey.create(registryKey, Identifier.tryParse(identifier))); + } + + private void loadFogs(@NotNull ResourceManager resourceManager, @NotNull String folderName, @NotNull Map fogRegistry) { + loadFogs(resourceManager, folderName, fogRegistry, Identifier::tryParse); + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/util/ChunkSectionUtil.java b/fog/src/main/java/dev/imb11/fog/client/util/ChunkSectionUtil.java new file mode 100644 index 0000000..e9613e3 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/util/ChunkSectionUtil.java @@ -0,0 +1,5 @@ +package dev.imb11.fog.client.util; + +public class ChunkSectionUtil { + public static final int CHUNK_SECTION_DIAMETER = 16; +} diff --git a/fog/src/main/java/dev/imb11/fog/client/util/FogConfigHelper.java b/fog/src/main/java/dev/imb11/fog/client/util/FogConfigHelper.java new file mode 100644 index 0000000..689a8bd --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/util/FogConfigHelper.java @@ -0,0 +1,60 @@ +package dev.imb11.fog.client.util; + +import dev.imb11.mru.yacl.ConfigHelper; +import dev.imb11.mru.yacl.EntryType; +import dev.isxander.yacl3.api.Option; +import dev.isxander.yacl3.api.controller.FloatFieldControllerBuilder; +import dev.isxander.yacl3.api.controller.ValueFormatter; +import net.minecraft.network.chat.Component; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +public class FogConfigHelper extends ConfigHelper { + /** + * Create a new ConfigHelper. + * + * @param modID The mod ID. + * @param configTranslationKey The translation key for the config. + */ + public FogConfigHelper(@NotNull String modID, @NotNull String configTranslationKey) { + super(modID, configTranslationKey); + } + + public static final ValueFormatter THREE_DECIMAL_FORMATTER = value -> Component.literal(String.format("%.3f", value)); + + public @NotNull Option getFieldTDP( + @NotNull String name, + float min, + float max, + float defaultValue, + Supplier getter, + Consumer setter, + ValueFormatter formatter, + boolean withImage + ) { + return Option.createBuilder() + .name(getText(EntryType.OPTION_NAME, name)) + .description(get(name, withImage)) + .binding(defaultValue, getter, setter) + .controller(opt -> FloatFieldControllerBuilder.create(opt) + .min(min) + .max(max) + .formatValue(formatter)) + .build(); + } + + // Overloaded method without withImage parameter (defaults to false) + public @NotNull Option getFieldTDP( + @NotNull String name, + float min, + float max, + float defaultValue, + Supplier getter, + Consumer setter + ) { + return getFieldTDP(name, min, max, defaultValue, getter, setter, THREE_DECIMAL_FORMATTER, false); + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/util/FogKeybinds.java b/fog/src/main/java/dev/imb11/fog/client/util/FogKeybinds.java new file mode 100644 index 0000000..08fdd75 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/util/FogKeybinds.java @@ -0,0 +1,44 @@ +package dev.imb11.fog.client.util; + +import dev.imb11.fog.config.FogConfig; +//? fabric { +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; +import net.fabricmc.fabric.api.client.keymapping.v1.KeyMappingHelper; +//?} +import net.minecraft.client.KeyMapping; +import com.mojang.blaze3d.platform.InputConstants; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.ChatFormatting; + +public class FogKeybinds { + public static KeyMapping toggleKeybind; + + public static void init() { + + toggleKeybind = new KeyMapping( + "key.fog.toggle", + InputConstants.UNKNOWN.getValue(), + + KeyMapping.Category.MISC + + ); + + //? fabric { + KeyMappingHelper.registerKeyMapping(toggleKeybind); + ClientTickEvents.END_LEVEL_TICK.register((level)->FogKeybinds.tickKeyMapping()); + //?} + } + + public static void tickKeyMapping() { + while (toggleKeybind.consumeClick()) { + FogConfig config = FogConfig.getInstance(); + config.enableMod = !config.enableMod; + + FogConfig.save(); + + Minecraft.getInstance().gui.getChat().addClientSystemMessage(Component.literal("§b§7[§rFog§b§7]§r ").append( + Component.translatable("fog.command.toggle." + (config.enableMod ? "enabled" : "disabled")).withStyle(ChatFormatting.GOLD))); + } + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/util/TickUtil.java b/fog/src/main/java/dev/imb11/fog/client/util/TickUtil.java new file mode 100644 index 0000000..5adf9cc --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/util/TickUtil.java @@ -0,0 +1,11 @@ +package dev.imb11.fog.client.util; + +import net.minecraft.client.Minecraft; + +public class TickUtil { + public static float getTickDelta() { + + return Minecraft.getInstance().getDeltaTracker().getGameTimeDeltaPartialTick(true); + + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/util/color/Color.java b/fog/src/main/java/dev/imb11/fog/client/util/color/Color.java new file mode 100644 index 0000000..3c7a060 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/util/color/Color.java @@ -0,0 +1,167 @@ +package dev.imb11.fog.client.util.color; + +import dev.imb11.fog.client.util.math.MathUtil; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; + +import static dev.imb11.fog.client.util.math.MathUtil.clamp; + +/** + * Color class that takes in red, green and blue values between 0-255. Values outside of this range are truncated. + */ +public class Color { + public int red; + public int green; + public int blue; + + private static final int BIG_HEX_COLOR_CHARACTER_LENGTH = 6; + private static final int SMALL_HEX_COLOR_CHARACTER_LENGTH = 3; + + public Color(int red, int green, int blue) { + this.red = clamp(red, 0, 255); + this.green = clamp(green, 0, 255); + this.blue = clamp(blue, 0, 255); + } + + public Color(int hex) { + red = (hex >> 16) & 0xFF; + green = (hex >> 8) & 0xFF; + blue = hex & 0xFF; + } + + public Color(org.joml.Vector3fc color) { + this((int) (color.x() * 255), (int) (color.y() * 255), (int) (color.z() * 255)); + } + + public Color(@NotNull Color color) { + red = color.red; + green = color.green; + blue = color.blue; + } + + private static final Map colorCache = new HashMap<>(); + public static Color from(java.awt.Color awtColor) { + return colorCache.computeIfAbsent(awtColor, color -> new Color(color.getRed(), color.getGreen(), color.getBlue())); + } + + public static Color from(Vec3 vec3d) { + return new Color((int) (vec3d.x * 255), (int) (vec3d.y * 255), (int) (vec3d.z * 255)); + } + + public Vec3 asVec3d() { + return new Vec3(red / 255.0f, green / 255.0f, blue / 255.0f); + } + + public String asHex() { + return String.format("#%02x%02x%02x", red, green, blue); + } + + @Override + public String toString() { + return String.format("Color(%s, %s, %s)", red, green, blue); + } + + /** + * Parses hexadecimal strings, in either {@code 0xfff} (the {@code 0x} prefix is required) or {@code #FFF} format (the {@code #} prefix is not required). + * + * @param hex A hexadecimal string, in either {@code 0xfff} (the {@code 0x} prefix is required) or {@code #FFF} format (the {@code #} prefix is not required). + * @return The parsed {@link Color}. + * @throws NumberFormatException Thrown when the {@code 0xfff} format was detected, but it couldn't be parsed by {@code Integer.parseInt(hex, 16)}. + */ + public static @NotNull Color parse(@NotNull String hex) throws NumberFormatException { + hex = hex.trim(); + + // Parse the 0xfff format + if (hex.startsWith("0x")) { + hex = hex.substring(2); + int hexValue = Integer.parseInt(hex, 16); + return new Color((hexValue >> 16) & 0xFF, (hexValue >> 8) & 0xFF, hexValue & 0xFF); + } + + // Parse the #FFF format + if (hex.startsWith("#")) { + hex = hex.substring(1); + } + + int red; + int green; + int blue; + var hexLength = hex.length(); + if (hexLength == SMALL_HEX_COLOR_CHARACTER_LENGTH) { + red = Integer.parseInt(hex.substring(0, 1), 16) * 255 / 16; + green = Integer.parseInt(hex.substring(1, 2), 16) * 255 / 16; + blue = Integer.parseInt(hex.substring(2, 3), 16) * 255 / 16; + } else if (hexLength == BIG_HEX_COLOR_CHARACTER_LENGTH) { + red = Integer.parseInt(hex.substring(0, 2), 16); + green = Integer.parseInt(hex.substring(2, 4), 16); + blue = Integer.parseInt(hex.substring(4, 6), 16); + } else { + throw new NumberFormatException( + "Hex value {} was detected as the #FFF format, but it didn't have the correct amount of characters (3 or 6)."); + } + + return new Color(red, green, blue); + } + + public int toInt() { + int hex = red; + hex = (hex << 8) + green; + hex = (hex << 8) + blue; + + return hex; + } + + public Color multiply(@NotNull Color color) { + var newColor = new Color(this); + + newColor.red = clamp(newColor.red * color.red, 0, 255); + newColor.green = clamp(newColor.green * color.green, 0, 255); + newColor.blue = clamp(newColor.blue * color.blue, 0, 255); + + return newColor; + } + + public Color add(@NotNull Color color) { + var newColor = new Color(this); + + newColor.red = clamp(newColor.red + color.red, 0, 255); + newColor.green = clamp(newColor.green + color.green, 0, 255); + newColor.blue = clamp(newColor.blue + color.blue, 0, 255); + + return newColor; + } + + public Color subtract(@NotNull Color color) { + var newColor = new Color(this); + + newColor.red = clamp(newColor.red - color.red, 0, 255); + newColor.green = clamp(newColor.green - color.green, 0, 255); + newColor.blue = clamp(newColor.blue - color.blue, 0, 255); + + return newColor; + } + + public Color invert() { + var newColor = new Color(this); + + newColor.red = clamp(255 - this.red, 0, 255); + newColor.green = clamp(255 - this.green, 0, 255); + newColor.blue = clamp(255 - this.blue, 0, 255); + + return newColor; + } + + public Color lerp(@NotNull Color endColor, float t) { + var newColor = new Color(this); + + newColor.red = MathUtil.lerp(this.red, endColor.red, t); + newColor.green = MathUtil.lerp(this.green, endColor.green, t); + newColor.blue = MathUtil.lerp(this.blue, endColor.blue, t); + + return newColor; + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/util/math/CloudCalculator.java b/fog/src/main/java/dev/imb11/fog/client/util/math/CloudCalculator.java new file mode 100644 index 0000000..a6b0a45 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/util/math/CloudCalculator.java @@ -0,0 +1,35 @@ +package dev.imb11.fog.client.util.math; + +public class CloudCalculator { + // TODO: Constants into FogConfig and make the relevant mixin toggleable. + public static float getCloudColor(long worldTime) { + // Define the color values + float dayColor = 1.0f; + float nightColor = 0.25f; + float cloudColor; + + if (worldTime < 10000) { + // Daytime + cloudColor = dayColor; + } else if (worldTime < 11000) { + // Transition starts just after 5:00 PM but still dayColor + cloudColor = dayColor; + } else if (worldTime < 13000) { + // Blend from dayColor to nightColor + float t = (float) (worldTime - 11000) / 2000; + cloudColor = MathUtil.lerp(dayColor, nightColor, t); + } else if (worldTime < 22000) { + // Nighttime + cloudColor = nightColor; + } else if (worldTime < 23000) { + // Blend from nightColor to dayColor + float t = (float) (worldTime - 22000) / 1000; + cloudColor = MathUtil.lerp(nightColor, dayColor, t); + } else { + // Constant dayColor from 23000 to 24000 ticks + cloudColor = dayColor; + } + + return cloudColor; + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/util/math/DarknessCalculation.java b/fog/src/main/java/dev/imb11/fog/client/util/math/DarknessCalculation.java new file mode 100644 index 0000000..ce2de95 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/util/math/DarknessCalculation.java @@ -0,0 +1,48 @@ +package dev.imb11.fog.client.util.math; + +import net.minecraft.client.Minecraft; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.util.Mth; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +public record DarknessCalculation(float fogStart, float fogEnd, float darknessValue) { + @Contract("_, _, _, _ -> new") + public static @NotNull DarknessCalculation of(@NotNull Minecraft client, float fogStart, float fogEnd, float deltaTick) { + float renderDistance = client.options.getEffectiveRenderDistance() * 16.0F; + Entity entity = client.getCameraEntity(); + float darknessValue = 0.0F; + if (!(entity instanceof LivingEntity livingEntity)) { + return new DarknessCalculation(fogStart, fogEnd, darknessValue); + } + + if (livingEntity.hasEffect(MobEffects.BLINDNESS)) { + fogStart = (4 * 16) / renderDistance; + fogEnd = (8 * 16) / renderDistance; + darknessValue = 1.0F; + } else if (livingEntity.hasEffect(MobEffects.DARKNESS)) { + MobEffectInstance effect = livingEntity.getEffect(MobEffects.DARKNESS); + if (effect != null) { + float factor = client.options.darknessEffectScale().get().floatValue(); + float intensity = effect.getBlendFactor(livingEntity, deltaTick) * factor; + + float darknessScale = calculateDarknessScale(livingEntity, deltaTick); + fogStart = ((8.0F * 16) / renderDistance) * (1 - darknessScale); + fogEnd = (15.0F * 16) / renderDistance; + darknessValue = intensity; + } + } + + return new DarknessCalculation(fogStart, fogEnd, darknessValue); + } + + private static float calculateDarknessScale(@NotNull LivingEntity entity, float deltaTick) { + float darknessFactor = entity.getEffect(MobEffects.DARKNESS).getBlendFactor(entity, deltaTick); + + float factor = 0.45F * darknessFactor; + return Math.max(0.0F, Mth.cos((entity.tickCount - deltaTick) * (float) Math.PI * 0.025F) * factor); + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/util/math/EnvironmentCalculations.java b/fog/src/main/java/dev/imb11/fog/client/util/math/EnvironmentCalculations.java new file mode 100644 index 0000000..4e26566 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/util/math/EnvironmentCalculations.java @@ -0,0 +1,66 @@ +package dev.imb11.fog.client.util.math; + +import dev.imb11.fog.api.FogColors; +import dev.imb11.fog.client.FogManager; +import dev.imb11.fog.client.util.color.Color; +import dev.imb11.fog.config.FogConfig; +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.attribute.EnvironmentAttributes; +import org.jetbrains.annotations.NotNull; + +public class EnvironmentCalculations { + public static FogManager.FogSettings apply(float undergroundFactor, FogManager.FogSettings settings, float tickDelta) { + return fixElytraColor( + applyCaveFog(undergroundFactor, settings), + tickDelta, + Minecraft.getInstance(), + Minecraft.getInstance().player, + Minecraft.getInstance().level + ); + } + + private static FogManager.@NotNull FogSettings applyCaveFog(float undergroundFactor, FogManager.FogSettings settings) { + FogColors belowGroundColors = FogColors.DEFAULT_CAVE; + Color belowColor = belowGroundColors.getNightColor(); + + float fogColorR = Mth.lerp(undergroundFactor, belowColor.red / 255f, settings.fogRed()), + fogColorG = Mth.lerp(undergroundFactor, belowColor.green / 255f, settings.fogGreen()), + fogColorB = Mth.lerp(undergroundFactor, belowColor.blue / 255f, settings.fogBlue()); + + return new FogManager.FogSettings(settings.fogStart(), settings.fogEnd(), fogColorR, fogColorG, fogColorB); + } + + public static FogManager.FogSettings fixElytraColor(FogManager.FogSettings input, float tickDelta, Minecraft client, LocalPlayer player, ClientLevel world) { + if (player == null || world == null || !FogConfig.getInstance().enableHighAltitudeFogColorInfluence) return input; + + float fogColorR = input.fogRed(); + float fogColorG = input.fogGreen(); + float fogColorB = input.fogBlue(); + + int surfaceTopLevel = world.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, (int) player.getX(), (int) player.getZ()); + int viewCutoff = surfaceTopLevel + (client.options.renderDistance().get() * 32); + int distancePastCutoff = (int) (player.getY() - viewCutoff); + + // TODO: Try and do something with fogStart here, eg: when fogStart as a blockpos is above the top level, start lerping. + // Check if player cannot see the top of the surface using their viewDistance option + if (client.player.getY() > viewCutoff) { + // Range from viewCutoff to viewCutoff + 25 + float percentageCutoff = Mth.clamp(distancePastCutoff / 25f, 0, 1); + Vec3 skyColour; + + skyColour = new Color(client.gameRenderer.getMainCamera().attributeProbe().getValue(EnvironmentAttributes.SKY_COLOR, tickDelta)).asVec3d(); + + // Lerp between the fog color and the sky color + fogColorR = (float) Mth.lerp(percentageCutoff, fogColorR, skyColour.x); + fogColorG = (float) Mth.lerp(percentageCutoff, fogColorG, skyColour.y); + fogColorB = (float) Mth.lerp(percentageCutoff, fogColorB, skyColour.z); + } + + return new FogManager.FogSettings(input.fogStart(), input.fogEnd(), fogColorR, fogColorG, fogColorB); + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/util/math/InterpolatedValue.java b/fog/src/main/java/dev/imb11/fog/client/util/math/InterpolatedValue.java new file mode 100644 index 0000000..42ff5e8 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/util/math/InterpolatedValue.java @@ -0,0 +1,76 @@ +package dev.imb11.fog.client.util.math; + +import net.minecraft.util.Mth; + +// TODO: Remove unused methods +public class InterpolatedValue { + private static final float DEFAULT_INTERPOLATION_SPEED = 0.05f; + + private final float interpolationSpeed; + + private float defaultValue; + private float previousValue; + private float currentValue; + + public InterpolatedValue(float defaultValue, float interpolationSpeed) { + this.defaultValue = defaultValue; + this.currentValue = defaultValue; + this.interpolationSpeed = interpolationSpeed; + } + + public InterpolatedValue(float defaultValue) { + this(defaultValue, DEFAULT_INTERPOLATION_SPEED); + } + + public void set(float value) { + this.previousValue = this.currentValue; + this.currentValue = value; + } + + public void set(double value) { + this.set((float) value); + } + + public void setDefaultValue(float value) { + this.defaultValue = value; + } + + public void setDefaultValue(double value) { + this.setDefaultValue((float) value); + } + + public void interpolate(float value, float interpolationSpeed) { + this.set(Float.isNaN(value) ? Mth.lerp(interpolationSpeed, currentValue, defaultValue) : Mth.lerp(interpolationSpeed, + currentValue, value + )); + } + + public void interpolate(double value, float interpolationSpeed) { + this.interpolate((float) value, interpolationSpeed); + } + + public void interpolate(float value) { + this.interpolate(value, this.interpolationSpeed); + } + + public void interpolate(double value) { + this.interpolate((float) value); + } + + public void interpolate() { + this.set(Mth.lerp(interpolationSpeed, currentValue, defaultValue)); + } + + public float get(float deltaTick) { + return Mth.lerp(deltaTick, previousValue, currentValue); + } + + public float getDefaultValue() { + return this.defaultValue; + } + + public void resetTo(float initialFogStart) { + this.defaultValue = initialFogStart; + this.currentValue = initialFogStart; + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/util/math/MathUtil.java b/fog/src/main/java/dev/imb11/fog/client/util/math/MathUtil.java new file mode 100644 index 0000000..8bdf5f7 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/util/math/MathUtil.java @@ -0,0 +1,41 @@ +package dev.imb11.fog.client.util.math; + +import net.minecraft.util.Mth; + +public class MathUtil { + public static int clamp(int value, int min, int max) { + if (value < min) { + value = min; + } else if (value > max) { + value = max; + } + + return value; + } + + public static float cube(float value) { + return value * value * value; + } + + public static int lerp(int start, int end, float t) { + return Math.round(start * (1.0f - t) + (end * t)); + } + + public static float lerp(float start, float end, float t) { + return start * (1.0f - t) + (end * t); + } + + /** + * Maps a value between a range, from a starting minimum/maximum value to an ending maximum/maximum value. + * + * @param fromMin The starting minimum value. + * @param fromMax The starting maximum value. + * @param toMin The ending minimum value. + * @param toMax The ending maximum value. + * @param value The value that should be mapped. + * @return The value, mapped between a range, from a starting minimum/maximum value to an ending maximum/maximum value. + */ + public static float mapRange(float fromMin, float fromMax, float toMin, float toMax, float value) { + return toMin + (Mth.clamp(value, fromMin, fromMax) - fromMin) * (toMax - toMin) / (fromMax - fromMin); + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/util/player/PlayerUtil.java b/fog/src/main/java/dev/imb11/fog/client/util/player/PlayerUtil.java new file mode 100644 index 0000000..c5ba714 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/util/player/PlayerUtil.java @@ -0,0 +1,74 @@ +package dev.imb11.fog.client.util.player; + +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PlayerUtil { + private static boolean isPlayerAboveGroundCachedResult = false; + private static long lastPlayerAboveGroundCheckTime = -1; + + public static boolean isPlayerAboveGround(LocalPlayer clientPlayerEntity) { + // Cache the result for 0.25 seconds + if (System.currentTimeMillis() - lastPlayerAboveGroundCheckTime < 250) { + return isPlayerAboveGroundCachedResult; + } + + lastPlayerAboveGroundCheckTime = System.currentTimeMillis(); + isPlayerAboveGroundCachedResult = isPlayerAboveGroundImpl(clientPlayerEntity); + return isPlayerAboveGroundCachedResult; + } + + /** + * Checks if 10 random points within a 5x5 radius around the player are above ground, to determine if the player is above ground. + * + * @param clientPlayerEntity The player that should be checked. + * @return {@code true} if more than 65% of the points are above ground, {@code false}. + */ + private static boolean isPlayerAboveGroundImpl(@NotNull LocalPlayer clientPlayerEntity) { + if (clientPlayerEntity.isUnderWater()) { + return true; + } + + @Nullable Level clientWorld = clientPlayerEntity.level(); + + if (clientWorld == null) { + return true; + } + + // Random point within 5x5 radius of player + double x = clientPlayerEntity.getX(); + double z = clientPlayerEntity.getZ(); + double y = clientPlayerEntity.getEyeY(); + // Check 10 points around the player to see if they are above ground, 65% of the points must be underground to return false + int points = 10; + int undergroundPoints = 0; + for (int i = 0; i < points; i++) { + double dx = (Math.random() - 0.5) * 5; + double dz = (Math.random() - 0.5) * 5; + + float topY = clientWorld.getHeight(Heightmap.Types.WORLD_SURFACE_WG, (int) (x + dx), (int) (z + dz)); + float seaLevel = clientWorld.getSeaLevel() - 0.25f; + + // Offset topY using sea level info to prevent false positives, eg: house roofs etc. + topY = Math.max(topY, seaLevel); + + if (y < topY && y < seaLevel) { + undergroundPoints++; + } + } + + // Check point at player eyes too. + int topY = clientWorld.getHeight(Heightmap.Types.WORLD_SURFACE_WG, (int) x, (int) z); + int seaLevel = clientWorld.getSeaLevel(); + if (y < topY && y < seaLevel - 0.25f) { + undergroundPoints++; + } + + // Return if player is above ground + return undergroundPoints < points * 0.65; + } +} diff --git a/fog/src/main/java/dev/imb11/fog/client/util/world/ClientWorldUtil.java b/fog/src/main/java/dev/imb11/fog/client/util/world/ClientWorldUtil.java new file mode 100644 index 0000000..f33fb27 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/client/util/world/ClientWorldUtil.java @@ -0,0 +1,15 @@ +package dev.imb11.fog.client.util.world; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.attribute.EnvironmentAttributes; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; + +public class ClientWorldUtil { + public static boolean isFogDenseAtPosition(@NotNull ClientLevel level, @NotNull BlockPos position) { + return level.environmentAttributes().getValue(EnvironmentAttributes.FOG_END_DISTANCE, Vec3.atCenterOf(position)) <= 96.0F + || Minecraft.getInstance().gui.getBossOverlay().shouldCreateWorldFog(); + } +} diff --git a/fog/src/main/java/dev/imb11/fog/config/FogConfig.java b/fog/src/main/java/dev/imb11/fog/config/FogConfig.java new file mode 100644 index 0000000..0b57661 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/config/FogConfig.java @@ -0,0 +1,318 @@ +package dev.imb11.fog.config; + +import com.google.gson.GsonBuilder; +import dev.imb11.fog.client.FogClient; +import dev.imb11.fog.client.FogManager; +import dev.imb11.fog.client.util.FogConfigHelper; +import dev.imb11.mru.yacl.EntryType; +import dev.isxander.yacl3.api.*; +import dev.isxander.yacl3.api.controller.BooleanControllerBuilder; +import dev.isxander.yacl3.api.controller.StringControllerBuilder; +import dev.isxander.yacl3.config.v2.api.ConfigClassHandler; +import dev.isxander.yacl3.config.v2.api.SerialEntry; +import dev.isxander.yacl3.config.v2.api.serializer.GsonConfigSerializerBuilder; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; +import java.util.List; + +import static dev.imb11.fog.client.FogClient.MOD_ID; + +public class FogConfig { + private static final String CONFIG_FILE_NAME = "config"; + private static final String CONFIG_FILE_EXTENSION = "json"; + private static final ConfigClassHandler HANDLER = ConfigClassHandler + .createBuilder(FogConfig.class) + .id(Identifier.fromNamespaceAndPath(MOD_ID, CONFIG_FILE_NAME)) + .serializer(config -> GsonConfigSerializerBuilder + .create(config) + .setPath(FogClient.getConfigPath(CONFIG_FILE_NAME, CONFIG_FILE_EXTENSION)) + .appendGsonBuilder(GsonBuilder::setPrettyPrinting) + .build()) + .build(); + private static final FogConfigHelper HELPER = new FogConfigHelper(MOD_ID, "config"); + + @SerialEntry + public boolean enableMod = true; + /** + * The Nether has good fog, it doesn't need changing unless the player really wants to. + */ + @SerialEntry + public @NotNull List disabledBiomes = List.of( + "minecraft:nether_wastes", + "minecraft:crimson_forest", + "minecraft:warped_forest", + "minecraft:soul_sand_valley", + "minecraft:basalt_deltas" + ); + + @SerialEntry + public float rainFogMultiplier = 0.9f; + @SerialEntry + public float undergroundFogMultiplier = 0.5f; + @SerialEntry + public boolean enableBiomeSpecificFogColors = true; + @SerialEntry + public boolean enableCloudWhitening = false; + @SerialEntry + public float initialFogStart = 0.1f; + @SerialEntry + public float initialFogEnd = 0.85f; + + @SerialEntry + public float raininessTransitionSpeed = 0.005f; + @SerialEntry + public float undergroundnessTransitionSpeed = 0.005f; + @SerialEntry + public float fogStartTransitionSpeed = 0.005f; + @SerialEntry + public float fogEndTransitionSpeed = 0.005f; + @SerialEntry + public float darknessTransitionSpeed = 0.005f; + @SerialEntry + public float fogColorTransitionSpeed = 0.025f; + @SerialEntry + public float startMultiplierTransitionSpeed = 0.0075f; + @SerialEntry + public float endMultiplierTransitionSpeed = 0.0075f; + @SerialEntry + public boolean enableMoonFogColorInfluence = true; + @SerialEntry + public Color newMoonColor = new Color(0, 0, 0, 255); + @SerialEntry + public boolean enableSunFogColorInfluence = true; + @SerialEntry + public boolean enableHighAltitudeFogColorInfluence = true; + @SerialEntry + public boolean prioritizePolytoneFogDefinitions = true; + @SerialEntry + public boolean disableModWhenIrisShaderPackIsEnabled = true; + + public static @NotNull FogConfig getInstance() { + return HANDLER.instance(); + } + + public static void load() { + HANDLER.load(); + } + + public static void save() { + HANDLER.save(); + } + + public @NotNull YetAnotherConfigLib getYetAnotherConfigLibInstance() { + return YetAnotherConfigLib.create(HANDLER, ((defaults, config, builder) -> builder + .title(Component.empty()) + .save(() -> { + HANDLER.save(); + FogManager.INSTANCE = new FogManager(); + }) + .category(ConfigCategory.createBuilder() + .name(HELPER.getText(EntryType.CATEGORY_NAME, "general")) + .option(Option.createBuilder() + .name(HELPER.getText(EntryType.OPTION_NAME, "enable_mod")) + .description(unused -> OptionDescription.createBuilder() + .text(HELPER.getText( + EntryType.OPTION_DESCRIPTION, + "enable_mod" + )) + .build()) + .binding( + defaults.enableMod, () -> enableMod, + newEnableMod -> enableMod = newEnableMod + ) + .controller(BooleanControllerBuilder::create) + .build() + ) + .option(ButtonOption.createBuilder() + .name(HELPER.getText(EntryType.OPTION_NAME, "reset_fog_modifications")) + .description(OptionDescription.of(HELPER.getText(EntryType.OPTION_DESCRIPTION, "reset_fog_modifications"))) + .action((yaclScreen, buttonOption) -> { + FogConfig.load(); + FogManager.INSTANCE = new FogManager(); + }) + .build() + ) + .option(LabelOption.createBuilder() + .line(Component.literal("")) + .build() + ) + .option(HELPER.get( + "enable_biome_specific_fog_colors", defaults.enableBiomeSpecificFogColors, + () -> config.enableBiomeSpecificFogColors, val -> config.enableBiomeSpecificFogColors = val + )) + .option(HELPER.get("enable_high_altitude_fog_color_influence", defaults.enableHighAltitudeFogColorInfluence, + () -> config.enableHighAltitudeFogColorInfluence, val -> config.enableHighAltitudeFogColorInfluence = val + )) + .option(HELPER.get( + "enable_sun_fog_color_influence", defaults.enableSunFogColorInfluence, + () -> config.enableSunFogColorInfluence, val -> config.enableSunFogColorInfluence = val + )) + .option(HELPER.get( + "enable_moon_fog_color_influence", defaults.enableMoonFogColorInfluence, + () -> config.enableMoonFogColorInfluence, + val -> config.enableMoonFogColorInfluence = val + )) + .option(HELPER.get( + "new_moon_color", defaults.newMoonColor, () -> config.newMoonColor, + val -> config.newMoonColor = val + )) + .option(Option.createBuilder() + .name(HELPER.getText(EntryType.OPTION_NAME, "enable_cloud_whitening")) + .description(unused -> OptionDescription.createBuilder() + .text(HELPER.getText( + EntryType.OPTION_DESCRIPTION, + "enable_cloud_whitening" + )) + .build()) + .binding( + defaults.enableCloudWhitening, () -> enableCloudWhitening, + newDisableCloudWhitening -> enableCloudWhitening = newDisableCloudWhitening + ) + .controller(option -> BooleanControllerBuilder.create(option).coloured(true).trueFalseFormatter()) + .available(!FogClient.isModInstalled("sodium")) + .build() + ) + .option(LabelOption.createBuilder() + .line(Component.literal("")) + .build() + ) + .option(HELPER.getSlider( + "rain_fog_multiplier", 0f, 1f, 0.05f, defaults.rainFogMultiplier, + () -> config.rainFogMultiplier, val -> config.rainFogMultiplier = val + )) + .option(HELPER.getSlider( + "underground_fog_multiplier", 0f, 1f, 0.05f,defaults.undergroundFogMultiplier, + () -> config.undergroundFogMultiplier, + val -> config.undergroundFogMultiplier = val + )) + .option(LabelOption.createBuilder() + .line(Component.literal("")) + .build() + ) + .group(ListOption.createBuilder() + .name(Component.translatable( + String.format("%s.config.option.disabled_biomes", MOD_ID))) + .binding( + defaults.disabledBiomes, () -> disabledBiomes, + val -> disabledBiomes = val + ) + .controller(StringControllerBuilder::create) + .initial("mod_id:dimension_id") + .collapsed(true) + .build() + ) + .group(OptionGroup.createBuilder() + .name(Component.translatable( + String.format("%s.config.group.initial_values", MOD_ID))) + .option(HELPER.getSlider( + "initial_fog_start", 0f, 1f, 0.05f, defaults.initialFogStart, () -> config.initialFogStart, + val -> config.initialFogStart = val + )) + .option(HELPER.getSlider( + "initial_fog_end", 0f, 1f, 0.05f, defaults.initialFogEnd, () -> config.initialFogEnd, + val -> config.initialFogEnd = val + )) + .collapsed(true) + .build() + ) + .build() + ) + .category(ConfigCategory.createBuilder() + .name(HELPER.getText(EntryType.CATEGORY_NAME, "transition_speeds")) + .option(HELPER.getFieldTDP( + "fog_start_transition_speed", 0.001f, 0.5f, defaults.fogStartTransitionSpeed, + () -> config.fogStartTransitionSpeed, + val -> config.fogStartTransitionSpeed = val + )) + .option(HELPER.getFieldTDP( + "fog_end_transition_speed", 0.001f, 0.5f, defaults.fogEndTransitionSpeed, + () -> config.fogEndTransitionSpeed, + val -> config.fogEndTransitionSpeed = val + )) + .option(HELPER.getFieldTDP( + "fog_color_transition_speed", 0.001f, 0.5f, defaults.fogColorTransitionSpeed, + () -> config.fogColorTransitionSpeed, + val -> config.fogColorTransitionSpeed = val + )) + .option(LabelOption.createBuilder() + .line(Component.literal("")) + .build() + ) + .option(HELPER.getFieldTDP( + "raininess_transition_speed", 0.001f, 0.5f, defaults.raininessTransitionSpeed, + () -> config.raininessTransitionSpeed, + val -> config.raininessTransitionSpeed = val + )) + .option(HELPER.getFieldTDP( + "undergroundness_transition_speed", 0.001f, 0.5f, defaults.undergroundnessTransitionSpeed, + () -> config.undergroundnessTransitionSpeed, + val -> config.undergroundnessTransitionSpeed = val + )) + .option(HELPER.getFieldTDP( + "darkness_transition_speed", 0.001f, 0.5f, defaults.darknessTransitionSpeed, + () -> config.darknessTransitionSpeed, + val -> config.darknessTransitionSpeed = val + )) + .option(LabelOption.createBuilder() + .line(Component.literal("")) + .build() + ) + .group(OptionGroup.createBuilder() + .name(Component.translatable( + String.format("%s.config.group.multipliers", MOD_ID))) + .option(HELPER.getFieldTDP( + "start_multiplier_transition_speed", 0.001f, 0.5f, defaults.startMultiplierTransitionSpeed, + () -> config.startMultiplierTransitionSpeed, + val -> config.startMultiplierTransitionSpeed = val + )) + .option(HELPER.getFieldTDP( + "end_multiplier_transition_speed", 0.001f, 0.5f, defaults.endMultiplierTransitionSpeed, + () -> config.endMultiplierTransitionSpeed, + val -> config.endMultiplierTransitionSpeed = val + )) + .collapsed(true) + .build() + ) + .build() + ).category(ConfigCategory.createBuilder() + .name(HELPER.getText(EntryType.CATEGORY_NAME, "compatibility")) + .option(Option.createBuilder() + .name(HELPER.getText(EntryType.OPTION_NAME, "disable_mod_when_iris_shader_pack_is_enabled")) + .description(unused -> OptionDescription.createBuilder() + .text(HELPER.getText( + EntryType.OPTION_DESCRIPTION, + "disable_mod_when_iris_shader_pack_is_enabled" + )) + .build()) + .binding( + defaults.disableModWhenIrisShaderPackIsEnabled, () -> disableModWhenIrisShaderPackIsEnabled, + newDisableModWhenIrisShaderPackIsEnabled -> disableModWhenIrisShaderPackIsEnabled = newDisableModWhenIrisShaderPackIsEnabled + ) + .controller(option -> BooleanControllerBuilder.create(option).coloured(true).trueFalseFormatter()) + .available(FogClient.isModInstalled("iris")) + .build() + ) + .option(Option.createBuilder() + .name(HELPER.getText(EntryType.OPTION_NAME, "prioritize_polytone_fog_definitions")) + .description(unused -> OptionDescription.createBuilder() + .text(HELPER.getText( + EntryType.OPTION_DESCRIPTION, + "prioritize_polytone_fog_definitions" + )) + .build()) + .binding( + defaults.prioritizePolytoneFogDefinitions, () -> prioritizePolytoneFogDefinitions, + newPrioritizePolytoneFogDefinitions -> prioritizePolytoneFogDefinitions = newPrioritizePolytoneFogDefinitions + ) + .controller(option -> BooleanControllerBuilder.create(option).coloured(true).trueFalseFormatter()) + .available(FogClient.isModInstalled("polytone")) + .build() + ) + .build() + ) + )); + } +} diff --git a/fog/src/main/java/dev/imb11/fog/loaders/fabric/FogClientFabric.java b/fog/src/main/java/dev/imb11/fog/loaders/fabric/FogClientFabric.java new file mode 100644 index 0000000..2ce5e92 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/loaders/fabric/FogClientFabric.java @@ -0,0 +1,13 @@ +/*? if fabric {*/ +package dev.imb11.fog.loaders.fabric; + +import dev.imb11.fog.client.FogClient; +import net.fabricmc.api.ClientModInitializer; + +public class FogClientFabric implements ClientModInitializer { + @Override + public void onInitializeClient() { + FogClient.initialize(); + } +} +/*?}*/ diff --git a/fog/src/main/java/dev/imb11/fog/loaders/fabric/datagen/FogDatagenFabric.java b/fog/src/main/java/dev/imb11/fog/loaders/fabric/datagen/FogDatagenFabric.java new file mode 100644 index 0000000..c0104f9 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/loaders/fabric/datagen/FogDatagenFabric.java @@ -0,0 +1,23 @@ +/*? if fabric && >=1.20.6 {*/ +package dev.imb11.fog.loaders.fabric.datagen; + +import dev.imb11.fog.client.FogClient; +import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint; +import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class FogDatagenFabric implements DataGeneratorEntrypoint { + + @Override + public void onInitializeDataGenerator(@NotNull FabricDataGenerator fabricDataGenerator) { + var pack = fabricDataGenerator.createPack(); + pack.addProvider(VanillaFogDefinitionProvider::new); + } + + @Override + public @Nullable String getEffectiveModId() { + return FogClient.MOD_ID; + } +} +/*?}*/ diff --git a/fog/src/main/java/dev/imb11/fog/loaders/fabric/datagen/VanillaFogDefinitionProvider.java b/fog/src/main/java/dev/imb11/fog/loaders/fabric/datagen/VanillaFogDefinitionProvider.java new file mode 100644 index 0000000..5ebea8e --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/loaders/fabric/datagen/VanillaFogDefinitionProvider.java @@ -0,0 +1,71 @@ +/*? if fabric && >=1.20.6 {*/ +package dev.imb11.fog.loaders.fabric.datagen; + +import dev.imb11.fog.api.CustomFogDefinition; +import dev.imb11.fog.api.providers.CustomFogDefinitionDataProvider; +import net.fabricmc.fabric.api.datagen.v1.FabricPackOutput; +import net.fabricmc.fabric.api.tag.convention.v2.ConventionalBiomeTags; +import net.minecraft.core.HolderLookup; +import net.minecraft.tags.TagKey; +import net.minecraft.resources.Identifier; +import net.minecraft.world.level.biome.Biome; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; + +public class VanillaFogDefinitionProvider extends CustomFogDefinitionDataProvider { + public VanillaFogDefinitionProvider(@NotNull FabricPackOutput dataOutput, @NotNull CompletableFuture lookup) { + super(dataOutput, lookup); + } + + @Override + public void acceptBiomes(@NotNull BiConsumer provider) { + provider.accept(Identifier.tryParse("sparse_jungle"), CustomFogDefinition.Builder.create() + .colors("#7EBAA2", "#1A2122").startMultiplier(0.75f).endMultiplier(1.0f).build()); + + provider.accept(Identifier.tryParse("basalt_deltas"), CustomFogDefinition.Builder.create() + .colors("#36292B", "#36292B").startMultiplier(0.8f).endMultiplier(0.01f).build()); + + provider.accept(Identifier.tryParse("crimson_forest"), CustomFogDefinition.Builder.create() + .colors("#700f18", "#700f18").startMultiplier(0.8f).endMultiplier(0.01f).build()); + + provider.accept(Identifier.tryParse("warped_forest"), CustomFogDefinition.Builder.create() + .colors("#0f4c4c", "#0f4c4c").startMultiplier(0.8f).endMultiplier(0.01f).build()); + + provider.accept(Identifier.tryParse("soul_sand_valley"), CustomFogDefinition.Builder.create() + .colors("#005157", "#005157").startMultiplier(1.0f).endMultiplier(0.01f).build()); + + provider.accept(Identifier.tryParse("nether_wastes"), CustomFogDefinition.Builder.create() + .colors("#330808", "#330808").startMultiplier(1.0f).endMultiplier(0.01f).build()); + } + + @Override + public void acceptBiomeTags(@NotNull BiConsumer, CustomFogDefinition> provider) { + provider.accept(ConventionalBiomeTags.IS_JUNGLE, CustomFogDefinition.Builder.create() + .colors("#5B9071", "#171E23").startMultiplier(0.15f).endMultiplier(0.35f).build()); + + provider.accept(ConventionalBiomeTags.IS_SWAMP, CustomFogDefinition.Builder.create() + .colors("#BDC8C2", "#5A6459").build()); + + provider.accept(ConventionalBiomeTags.IS_BADLANDS, CustomFogDefinition.Builder.create() + .colors("#BCA199", "#140c07").build()); + + provider.accept(ConventionalBiomeTags.IS_DESERT, CustomFogDefinition.Builder.create() + .colors("#D1C8AB", "#827D6A").build()); + + provider.accept(ConventionalBiomeTags.IS_SNOWY, CustomFogDefinition.Builder.create() + .colors("#DFEBF4", "#687782").build()); + + provider.accept(ConventionalBiomeTags.IS_AQUATIC_ICY, CustomFogDefinition.Builder.create() + .colors("#BDDBE1", "#526C72").build()); + + provider.accept(ConventionalBiomeTags.IS_BEACH, CustomFogDefinition.Builder.create() + .colors("#CBCABD", "#11110e").build()); + + provider.accept(ConventionalBiomeTags.IS_END, CustomFogDefinition.Builder.create() + .colors("#291d26", "#291d26") + .startMultiplier(0.5f).endMultiplier(0.5f).build()); + } +} +/*?}*/ diff --git a/fog/src/main/java/dev/imb11/fog/loaders/neoforge/FogClientNeoForge.java b/fog/src/main/java/dev/imb11/fog/loaders/neoforge/FogClientNeoForge.java new file mode 100644 index 0000000..8ea2c46 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/loaders/neoforge/FogClientNeoForge.java @@ -0,0 +1,54 @@ +/*? if neoforge {*/ +/*package dev.imb11.fog.loaders.neoforge; + +import dev.imb11.fog.client.FogClient; +import dev.imb11.fog.client.FogManager; +import dev.imb11.fog.client.command.FogClientCommands; +import dev.imb11.fog.client.resource.FogResourceReloader; +import dev.imb11.fog.client.util.FogKeybinds; +import dev.imb11.fog.config.FogConfig; +import net.minecraft.client.Minecraft; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.ModContainer; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.fml.common.Mod; +import net.neoforged.neoforge.client.event.AddClientReloadListenersEvent; +import net.neoforged.neoforge.client.event.ClientTickEvent; +import net.neoforged.neoforge.client.event.RegisterClientCommandsEvent; +import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; +import net.neoforged.neoforge.client.gui.IConfigScreenFactory; + +@EventBusSubscriber +@Mod(value = "fog", dist = Dist.CLIENT) +public class FogClientNeoForge { + public FogClientNeoForge(ModContainer container) { + FogClient.initialize(); + container.registerExtensionPoint(IConfigScreenFactory.class, + (client, parent) -> FogConfig.getInstance().getYetAnotherConfigLibInstance().generateScreen(parent)); + } + + @SubscribeEvent + public static void registerKeyMappings(RegisterKeyMappingsEvent event) { + event.register(FogKeybinds.toggleKeybind); + + } + + @SubscribeEvent + public static void tickLevel(ClientTickEvent.Post event) { + FogKeybinds.tickKeyMapping(); + FogManager.getInstance().onEndTick(Minecraft.getInstance().level); + } + + @SubscribeEvent + public static void registerReloadListener(AddClientReloadListenersEvent event) { + event.addListener(FogResourceReloader.IDENTIFIER, new FogResourceReloader()); + } + + @SubscribeEvent + public static void registerClientCommands(RegisterClientCommandsEvent event) { + FogClientCommands.register(event.getDispatcher()); + } +} + +*//*?}*/ diff --git a/fog/src/main/java/dev/imb11/fog/mixin/client/ClientPacketListenerMixin.java b/fog/src/main/java/dev/imb11/fog/mixin/client/ClientPacketListenerMixin.java new file mode 100644 index 0000000..561cf0d --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/mixin/client/ClientPacketListenerMixin.java @@ -0,0 +1,19 @@ +package dev.imb11.fog.mixin.client; + +import dev.imb11.fog.client.FogManager; +import dev.imb11.fog.client.registry.FogRegistry; +import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.network.protocol.game.ClientboundLoginPacket; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ClientPacketListener.class) +public class ClientPacketListenerMixin { + @Inject(method = "handleLogin", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Options;setServerRenderDistance(I)V", shift = At.Shift.AFTER)) + private void handleLogin(ClientboundLoginPacket packet, CallbackInfo ci) { + FogManager.INSTANCE = new FogManager(); + FogRegistry.resetCaches(); + } +} diff --git a/fog/src/main/java/dev/imb11/fog/mixin/client/rendering/FogRendererMixin.java b/fog/src/main/java/dev/imb11/fog/mixin/client/rendering/FogRendererMixin.java new file mode 100644 index 0000000..d553bb7 --- /dev/null +++ b/fog/src/main/java/dev/imb11/fog/mixin/client/rendering/FogRendererMixin.java @@ -0,0 +1,49 @@ +package dev.imb11.fog.mixin.client.rendering; + +import dev.imb11.fog.client.FogManager; +import dev.imb11.fog.client.compat.polytone.IrisCompat; +import dev.imb11.fog.client.util.math.EnvironmentCalculations; +import dev.imb11.fog.config.FogConfig; +import net.minecraft.client.Camera; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.fog.FogData; +import net.minecraft.client.renderer.fog.FogRenderer; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.material.FogType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import static dev.imb11.fog.client.util.ChunkSectionUtil.CHUNK_SECTION_DIAMETER; + +@Mixin(FogRenderer.class) +public class FogRendererMixin { + @Inject(method = "setupFog", at = @At("RETURN"), order = 900) + private void fog$modifyFog(Camera camera, int renderDistance, DeltaTracker deltaTracker, + float darkenWorldAmount, ClientLevel level, CallbackInfoReturnable cir) { + if (!FogConfig.getInstance().enableMod || FogManager.isInDisabledBiome() + || camera.getFluidInCamera() != FogType.NONE || IrisCompat.shouldDisableMod()) { + return; + } + + var manager = FogManager.getInstance(); + if (!manager.hasSetup) { + return; + } + + float partialTick = deltaTracker.getGameTimeDeltaPartialTick(false); + var settings = manager.getFogSettings(partialTick, renderDistance); + var client = Minecraft.getInstance(); + if (!level.dimensionType().hasFixedTime() || level.dimensionType().skybox() != DimensionType.Skybox.END) { + settings = EnvironmentCalculations.apply(manager.getUndergroundFactor(client, partialTick), settings, partialTick); + } + + var fog = cir.getReturnValue(); + fog.renderDistanceStart = (float) settings.fogStart() * CHUNK_SECTION_DIAMETER; + fog.renderDistanceEnd = (float) settings.fogEnd() * CHUNK_SECTION_DIAMETER; + fog.color.set(settings.fogRed(), settings.fogGreen(), settings.fogBlue(), 1.0F); + } +} diff --git a/fog/src/main/resources/META-INF/neoforge.mods.toml b/fog/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..15cfa9b --- /dev/null +++ b/fog/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,47 @@ +modLoader="javafml" +loaderVersion="[4,)" +issueTrackerURL="https://github.com/IMB11/Fog/issues" +license="All-Rights-Reserved" + +[[mods]] +modId="fog" +version="${version}" +displayName="Fog" +displayURL="https://imb11.dev/" +logoFile="assets/fog/icon.png" +authors="IMB11,Steveplays" +description="An expansive and dynamic overhaul to Minecraft's fog rendering system." + +[[mixins]] +config="fog.mixins.json" + +[mc-publish] +dependencies=["yacl"] + +[[dependencies.fog]] +modId="neoforge" +type="required" +versionRange="${target_loader}" +ordering="NONE" +side="CLIENT" + +[[dependencies.fog]] +modId="minecraft" +type="required" +versionRange="${target_minecraft}" +ordering="NONE" +side="CLIENT" + +[[dependencies.fog]] +modId="mru" +type="required" +versionRange="[${target_mru},)" +ordering="NONE" +side="CLIENT" + +[[dependencies.fog]] +modId="yet_another_config_lib_v3" +type="required" +versionRange="[${target_yacl},)" +ordering="NONE" +side="CLIENT" diff --git a/fog/src/main/resources/assets/fog/icon.png b/fog/src/main/resources/assets/fog/icon.png new file mode 100644 index 0000000..688d6e8 Binary files /dev/null and b/fog/src/main/resources/assets/fog/icon.png differ diff --git a/fog/src/main/resources/assets/fog/lang/en_us.json b/fog/src/main/resources/assets/fog/lang/en_us.json new file mode 100644 index 0000000..eeb140e --- /dev/null +++ b/fog/src/main/resources/assets/fog/lang/en_us.json @@ -0,0 +1,58 @@ +{ + "fog.config.category.general": "General", + "fog.config.category.transition_speeds": "Transition Speeds", + "fog.config.category.compatibility": "Compatibility", + "fog.config.option.enable_mod": "Enable Mod", + "fog.config.option.description.enable_mod": "Enables the Fog modifications, which is toggleable, for example, to compare to vanilla Minecraft.", + "fog.config.option.reset_fog_modifications": "Reset Fog Modifications", + "fog.config.option.description.reset_fog_modifications": "Resets fog modifications to the initial values specified in the configuration options.", + "fog.config.option.initial_fog_start": "Initial Fog Start", + "fog.config.option.description.initial_fog_start": "The initial (when the fog modifications are loaded) distance from the camera at which fog starts to appear, expressed as a percentage of view distance.", + "fog.config.option.initial_fog_end": "Initial Fog End", + "fog.config.option.description.initial_fog_end": "The initial (when the fog modifications are loaded) distance from the camera at which fog is fully opaque, expressed as a percentage of view distance.", + "fog.config.option.rain_fog_multiplier": "Rain Fog Multiplier", + "fog.config.option.description.rain_fog_multiplier": "The density and darkness of fog during rain, snow and/or thunder.", + "fog.config.option.underground_fog_multiplier": "Underground Fog Multiplier", + "fog.config.option.description.underground_fog_multiplier": "The density of fog when underground.", + "fog.config.option.enable_biome_specific_fog_colors": "Enable Biome-specific Fog Colors", + "fog.config.option.description.enable_biome_specific_fog_colors": "Enables biome-specific fog colors, which changes the fog color depending on the biome the player is in.", + "fog.config.option.disabled_biomes": "Disabled Biomes", + "fog.config.option.description.disabled_biomes": "Disables all fog modifications in the specified biomes.", + "fog.config.group.initial_values": "Initial Values", + "fog.config.option.fog_start_transition_speed": "Fog Start Transition Speed", + "fog.config.option.description.fog_start_transition_speed": "The speed at which the fog start distance transitions. Lower values result in smoother transitions.", + "fog.config.option.fog_end_transition_speed": "Fog End Transition Speed", + "fog.config.option.description.fog_end_transition_speed": "The speed at which the fog end distance transitions. Lower values result in smoother transitions.", + "fog.config.option.fog_color_transition_speed": "Fog Color Transition Speed", + "fog.config.option.description.fog_color_transition_speed": "The speed at which the fog color transitions to match environmental changes. Lower values result in smoother color changes.", + "fog.config.option.raininess_transition_speed": "Raininess Transition Speed", + "fog.config.option.description.raininess_transition_speed": "The speed at which fog changes color and density during a weather transition. Lower values result in smoother transitions.", + "fog.config.option.undergroundness_transition_speed": "Undergroundness Transition Speed", + "fog.config.option.description.undergroundness_transition_speed": "The speed at which fog transitions when underground. Lower values result in smoother transitions.", + "fog.config.option.darkness_transition_speed": "Darkness Transition Speed", + "fog.config.option.description.darkness_transition_speed": "The speed at which the darkness effect transitions. Lower values result in smoother transitions.", + "fog.config.group.multipliers": "Fog Multipliers", + "fog.config.option.start_multiplier_transition_speed": "Fog Start Multiplier Transition Speed", + "fog.config.option.description.start_multiplier_transition_speed": "The speed at which the fog start multiplier transitions. Lower values result in smoother transitions.", + "fog.config.option.end_multiplier_transition_speed": "Fog End Multiplier Transition Speed", + "fog.config.option.description.end_multiplier_transition_speed": "The speed at which the fog end multiplier transitions. Lower values result in smoother transitions.", + "fog.config.option.enable_sun_fog_color_influence": "Enable Sun Fog Color Influence", + "fog.config.option.description.enable_sun_fog_color_influence": "Enables the Sun's influence on the fog color during sunrises and sunsets.", + "fog.config.option.enable_moon_fog_color_influence": "Enable Moon Fog Color Influence", + "fog.config.option.description.enable_moon_fog_color_influence": "Enables the Moon's influence on the fog color, which depends on the Moon's phase.", + "fog.config.option.new_moon_color": "New Moon Fog Color", + "fog.config.option.description.new_moon_color": "The fog color during a New Moon.", + "fog.config.option.enable_cloud_whitening": "Enable Cloud Whitening", + "fog.config.option.description.enable_cloud_whitening": "Enables the cloud whitening effect, which unlinks cloud color from fog color. This is disabled when Sodium is present, because Sodium does this by default.", + "fog.config.option.enable_high_altitude_fog_color_influence": "Enable High Altitude Fog Color Influence", + "fog.config.option.description.enable_high_altitude_fog_color_influence": "Enables the influence of high altitudes on the fog color, matching it to the sky color. May cause issues in worlds with non-standard world heights.", + "fog.config.option.disable_mod_when_iris_shader_pack_is_enabled": "Disable Mod When Iris Shader Pack Is Enabled", + "fog.config.option.description.disable_mod_when_iris_shader_pack_is_enabled": "Disables Fog when an Iris shader pack is enabled.", + "fog.config.option.prioritize_polytone_fog_definitions": "Prioritize Polytone Fog Colors", + "fog.config.option.description.prioritize_polytone_fog_definitions": "Prioritizes fog definitions from Polytone resource packs over fog definitions from Fog resource packs.", + "key.fog.toggle": "Toggle Fog Modifications", + "fog.command.toggle.enabled": "Enabled Fog modifications.", + "fog.command.toggle.disabled": "Disabled Fog modifications.", + "fog.command.reset": "Reset Fog modifications to the initial values specified in the configuration options.", + "fog.command.debug.failure": "An error occurred while getting debug information." +} diff --git a/fog/src/main/resources/assets/fog/lang/es_ar.json b/fog/src/main/resources/assets/fog/lang/es_ar.json new file mode 100644 index 0000000..a639cc0 --- /dev/null +++ b/fog/src/main/resources/assets/fog/lang/es_ar.json @@ -0,0 +1,42 @@ +{ + "fog.config.category.transition_speeds": "Velocidades de Transición", + "fog.config.category.general": "General", + "fog.config.category.compatibility": "Compatibilidad", + "key.fog.toggle": "Activar/Desactivar Motor de Niebla", + "fog.config.option.new_moon_color": "Color de Luna Nueva", + "fog.config.option.description.new_moon_color": "Color de la niebla cuando la luna está en fase de \"Luna Nueva\". Se interpolará con el color nocturno predeterminado o del bioma si la transición por fase lunar está habilitada.", + "fog.config.option.sunset_color": "Color del Atardecer", + "fog.config.option.description.sunset_color": "Color de la niebla durante el atardecer. Se interpolará con el color diurno predeterminado o del bioma si el efecto de niebla al atardecer está habilitado.", + "fog.config.option.initial_fog_start": "Inicio Inicial de la Niebla", + "fog.config.option.description.initial_fog_start": "Distancia inicial (cuando se carga el motor de niebla) desde la cámara en la que empieza a aparecer la niebla, expresada como un porcentaje de la distancia de visión", + "fog.config.option.initial_fog_end": "Fin Inicial de la Niebla", + "fog.config.option.description.initial_fog_end": "Distancia inicial (cuando se carga el motor de niebla) desde la cámara en la que la niebla es completamente opaca, expresada como un porcentaje de la distancia de visión", + "fog.config.option.disabled_biomes": "Biomas Desactivados", + "fog.config.option.description.disabled_biomes": "Desactiva todas las modificaciones de niebla en los biomas especificados.", + "fog.config.option.fog_start_transition_speed": "Velocidad de Transición del Inicio de Niebla", + "fog.config.option.description.fog_start_transition_speed": "Controla la velocidad a la que el inicio de la niebla cambia de distancia. Valores más bajos generan transiciones más suaves.", + "fog.config.option.fog_end_transition_speed": "Velocidad de Transición del Fin de Niebla", + "fog.config.option.description.fog_end_transition_speed": "Controla la velocidad a la que el final de la niebla cambia de distancia. Valores más bajos generan transiciones más suaves.", + "fog.config.option.darkness_transition_speed": "Velocidad de Transición de Oscuridad", + "fog.config.option.description.darkness_transition_speed": "Controla la velocidad a la que cambian los niveles de oscuridad. Valores más bajos generan transiciones más suaves.", + "fog.config.option.fog_color_transition_speed": "Velocidad de Transición del Color de Niebla", + "fog.config.option.description.fog_color_transition_speed": "Controla la velocidad a la que el color de la niebla cambia según el entorno. Valores más bajos generan cambios de color más suaves.", + "fog.config.option.start_multiplier_transition_speed": "Velocidad de Transición del Multiplicador de Inicio", + "fog.config.option.description.start_multiplier_transition_speed": "Controla la velocidad de cambio del multiplicador de inicio de la niebla. Valores más bajos generan transiciones más suaves.", + "fog.config.option.end_multiplier_transition_speed": "Velocidad de Transición del Multiplicador de Fin", + "fog.config.option.description.end_multiplier_transition_speed": "Controla la velocidad de cambio del multiplicador de fin de la niebla. Valores más bajos generan transiciones más suaves.", + "fog.config.option.raininess_transition_speed": "Velocidad de Transición por Lluvia", + "fog.config.option.description.raininess_transition_speed": "Controla la velocidad a la que se aplican los efectos de lluvia. Valores más bajos generan transiciones más suaves.", + "fog.config.option.undergroundness_transition_speed": "Velocidad de Transición Subterránea", + "fog.config.option.description.undergroundness_transition_speed": "Controla la velocidad a la que se aplican los efectos de niebla subterránea. Valores más bajos generan transiciones más suaves.", + "fog.config.option.prioritize_polytone_fog_definitions": "Priorizar Colores de Niebla de Polytone", + "fog.config.option.description.prioritize_polytone_fog_definitions": "¿Los colores de niebla definidos por Polytone deben tener prioridad sobre los definidos por este mod o por resource packs compatibles?", + "fog.config.option.enable_high_altitude_fog_color_influence": "Habilitar Niebla en Altura", + "fog.config.option.description.enable_high_altitude_fog_color_influence": "¿El color de la niebla debe coincidir con el del cielo a gran altura? Útil al volar con elitros para evitar problemas con el horizonte. Puede causar problemas en mundos con alturas personalizadas.", + "fog.config.option.disable_mod_when_iris_shader_pack_is_enabled": "Desactivar el Mod si Iris Está Activo", + "fog.config.option.description.disable_mod_when_iris_shader_pack_is_enabled": "¿El mod debería desactivarse cuando los shaders de Iris estén activos?", + "fog.command.toggle.enabled": "Las modificaciones del motor de niebla han sido reactivadas.", + "fog.command.toggle.disabled": "Las modificaciones del motor de niebla han sido desactivadas.", + "fog.command.reset": "Las modificaciones del motor de niebla se recargaron y se restablecieron a los valores predeterminados del archivo de configuración.", + "fog.command.debug.failure": "Ocurrió un error al obtener la información de depuración." +} diff --git a/fog/src/main/resources/assets/fog/lang/ru_ru.json b/fog/src/main/resources/assets/fog/lang/ru_ru.json new file mode 100644 index 0000000..f26b3c5 --- /dev/null +++ b/fog/src/main/resources/assets/fog/lang/ru_ru.json @@ -0,0 +1,58 @@ +{ + "fog.config.category.general": "Общие настройки", + "fog.config.category.transition_speeds": "Скорости перехода", + "fog.config.category.compatibility": "Совместимость", + "fog.config.option.enable_mod": "Включить мод", + "fog.config.option.description.disable_mod": "Включает модификации тумана модом. Полезно, если вы хотите провести сравнение с ванильной игрой.", + "fog.config.option.reset_fog_modifications": "Сбросить настройки тумана", + "fog.config.option.description.reset_fog_modifications": "Сбрасывает настройки тумана к начальным значениям, указанным в конфигурации.", + "fog.config.option.initial_fog_start": "Начало тумана", + "fog.config.option.description.initial_fog_start": "Начальное (при включённом движке тумана) расстояние от камеры, на котором начинает появляться туман, выраженное в процентах от дальности прорисовки.", + "fog.config.option.initial_fog_end": "Конец тумана", + "fog.config.option.description.initial_fog_end": "Начальное (при включённом движке тумана) расстояние от камеры, на котором туман полностью непрозрачен, выраженное в процентах от расстояния обзора.", + "fog.config.option.rain_fog_multiplier": "Множитель тумана при дожде", + "fog.config.option.description.rain_fog_multiplier": "Плотность и темнота тумана во время дождя, снега и/или грозы.", + "fog.config.option.underground_fog_multiplier": "Множитель подземного тумана", + "fog.config.option.description.underground_fog_multiplier": "Плотность тумана в подземных условиях.", + "fog.config.option.enable_biome_specific_fog_colors": "Включить цвет тумана по биомам", + "fog.config.option.description.enable_biome_specific_fog_colors": "Включает цвет тумана в зависимости от биома, в котором находится игрок.", + "fog.config.option.disabled_biomes": "Отключенные биомы", + "fog.config.option.description.disabled_biomes": "Отключает все модификации тумана в указанных биомах.", + "fog.config.group.initial_values": "Начальные значения", + "fog.config.option.fog_start_transition_speed": "Скорость перехода к началу тумана", + "fog.config.option.description.fog_start_transition_speed": "Управляет скоростью, с которой расстояние до начала тумана изменяется на новые значения. Более низкие значения обеспечивают более плавный переход.", + "fog.config.option.fog_end_transition_speed": "Скорость перехода к концу тумана", + "fog.config.option.description.fog_end_transition_speed": "Управляет скоростью, с которой расстояние до конца тумана изменяется на новые значения. Более низкие значения обеспечивают более плавный переход.", + "fog.config.option.fog_color_transition_speed": "Скорость изменения цвета тумана", + "fog.config.option.description.fog_color_transition_speed": "Управляет скоростью изменения цвета тумана в соответствии с изменениями окружающей среды. Более низкие значения приводят к более плавному изменению цвета.", + "fog.config.option.raininess_transition_speed": "Скорость перехода в дождливость", + "fog.config.option.description.raininess_transition_speed": "Управляет скоростью, с которой дождливость влияет на переход. Более низкие значения обеспечивают более плавный переход.", + "fog.config.option.undergroundness_transition_speed": "Скорость перехода в подземность", + "fog.config.option.description.undergroundness_transition_speed": "Управляет скоростью, с которой подземность влияет на переход. Более низкие значения обеспечивают более плавный переход.", + "fog.config.option.darkness_transition_speed": "Скорость перехода в темноту", + "fog.config.option.description.darkness_transition_speed": "Управляет скоростью изменения уровня освещённости. Более низкие значения обеспечивают более плавный переход.", + "fog.config.group.multipliers": "Множители тумана", + "fog.config.option.start_multiplier_transition_speed": "Скорость перехода стартового множителя", + "fog.config.option.description.start_multiplier_transition_speed": "Управляет скоростью перехода множителя начала тумана. Более низкие значения обеспечивают более плавный переход.", + "fog.config.option.end_multiplier_transition_speed": "Скорость перехода конечного множителя", + "fog.config.option.description.end_multiplier_transition_speed": "Управляет скоростью перехода множителя окончания тумана. Более низкие значения обеспечивают более плавный переход.", + "fog.config.option.enable_sun_fog_color_influence": "Включить влияние солнца на цвет тумана", + "fog.config.option.description.enable_sun_fog_color_influence": "Включает влияние солнца на цвет тумана во время рассветов и закатов.", + "fog.config.option.enable_moon_fog_color_influence": "Включить влияние луны на цвет тумана", + "fog.config.option.description.enable_moon_fog_color_influence": "Включает влияние луны на цвет тумана, которое зависит от фазы луны.", + "fog.config.option.new_moon_color": "Цвет новолуния", + "fog.config.option.description.new_moon_color": "Цвет тумана, который используется, когда луна находится в фазе новолуния. Он будет совпадать с цветом биома или цветом ночи по умолчанию, если включен переход цвета по фазе луны.", + "fog.config.option.enable_cloud_whitening": "Включить отбеливание облаков", + "fog.config.option.description.enable_cloud_whitening": "Включает эффект отбеливания облаков, который отделяет цвет облаков от цвета тумана. Отключено при наличии Sodium, так как Sodium делает это по умолчанию.", + "fog.config.option.enable_high_altitude_fog_color_influence": "Включить туман на большой высоте", + "fog.config.option.description.enable_high_altitude_fog_color_influence": "Должен ли цвет тумана совпадать с цветом неба на больших высотах? Полезно при полётах на больших высотах на элитрах, чтобы избежать странных проблем с горизонтом. Это может вызывать проблемы в мирах с нестандартными мировыми высотами.", + "fog.config.option.disable_mod_when_iris_shader_pack_is_enabled": "Отключить мод при активном Iris", + "fog.config.option.description.disable_mod_when_iris_shader_pack_is_enabled": "Должен ли мод отключаться, когда активны шейдеры в Iris?", + "fog.config.option.prioritize_polytone_fog_definitions": "Приоритезировать цвета тумана из Polytone", + "fog.config.option.description.prioritize_polytone_fog_definitions": "Должны ли биомные цвета тумана, определённые модом Polytone, быть приоритетными по сравнению с определениями тумана, предоставляемыми этим модом и наборами ресурсов, которые используют этот мод?", + "key.fog.toggle": "Переключить движок тумана", + "fog.command.toggle.enabled": "Модификации движка тумана теперь снова доступны.", + "fog.command.toggle.disabled": "Модификации движка тумана теперь отключены.", + "fog.command.reset": "Модификации движка тумана были перезагружены и сброшены к значениям по умолчанию, указанным в конфигурации.", + "fog.command.debug.failure": "При получении отладочной информации произошла ошибка." +} diff --git a/fog/src/main/resources/assets/fog/lang/tr_tr.json b/fog/src/main/resources/assets/fog/lang/tr_tr.json new file mode 100644 index 0000000..c780f77 --- /dev/null +++ b/fog/src/main/resources/assets/fog/lang/tr_tr.json @@ -0,0 +1,10 @@ +{ + "fog.config.option.initial_fog_start": "İlk Sis Başlangıcı", + "fog.config.option.description.initial_fog_start": "Sisin görünmeye başladığı kameradan ilk (sis motoru yüklendiğinde) mesafe - görüş mesafesinin yüzdesi olarak ifade edilir", + "fog.config.option.initial_fog_end": "İlk Sis Sonu", + "fog.config.option.description.initial_fog_end": "Sisin tamamen opak olduğu kameradan ilk (sis motoru yüklendiğinde) mesafe - görüş mesafesinin yüzdesi olarak ifade edilir", + "fog.command.toggle.enabled": "Sis motoru modifikasyonları artık yeniden etkinleştirildi.", + "fog.command.toggle.disabled": "Sis motoru modifikasyonları artık devre dışı bırakıldı.", + "fog.command.reset": "Sis motoru modifikasyonları yeniden yüklendi ve yapılandırmada belirtilen varsayılan değerlere sıfırlandı.", + "fog.command.debug.failure": "Hata ayıklama bilgisi alınırken bir hata oluştu." +} diff --git a/fog/src/main/resources/assets/fog/lang/uk_ua.json b/fog/src/main/resources/assets/fog/lang/uk_ua.json new file mode 100644 index 0000000..c9eab7d --- /dev/null +++ b/fog/src/main/resources/assets/fog/lang/uk_ua.json @@ -0,0 +1,10 @@ +{ + "fog.config.option.initial_fog_start": "Початок туману", + "fog.config.option.description.initial_fog_start": "Початкова (при увімкненому двигуні туману) відстань від камери, на якій починає з'являтися туман - виражена у відсотках від відстані огляду", + "fog.config.option.initial_fog_end": "Кінець туману", + "fog.config.option.description.initial_fog_end": "Початкова (при увімкненому двигуні туману) відстань від камери, на якій туман є повністю непрозорим - виражається у відсотках від відстані огляду", + "fog.command.toggle.enabled": "Модифікації двигуна тумана тепер знову доступні.", + "fog.command.toggle.disabled": "Модифікації двигуна тумана наразі відключені.", + "fog.command.reset": "Модифікації двигуна тумана було перезавантажено та скинуто до значень за замовчуванням, вказаних у конфігурації.", + "fog.command.debug.failure": "Виникла помилка під час отримання налагоджувальної інформації." +} diff --git a/fog/src/main/resources/assets/fog/lang/zh_cn.json b/fog/src/main/resources/assets/fog/lang/zh_cn.json new file mode 100644 index 0000000..d586a39 --- /dev/null +++ b/fog/src/main/resources/assets/fog/lang/zh_cn.json @@ -0,0 +1,35 @@ +{ + "fog.config.category.transition_speeds": "过渡速度", + "fog.config.category.general": "常规设置", + "fog.config.option.new_moon_color": "新月颜色", + "fog.config.option.description.new_moon_color": "当月相为“新月”时所使用的迷雾颜色。如果启用月相颜色过渡,这将与生物群系或默认夜晚颜色进行线性插值(Linear Interpolation)。", + "fog.config.option.sunset_color": "日落颜色", + "fog.config.option.description.sunset_color": "当日落时所使用的颜色。如果启用日落迷雾效果,这将与生物群系或默认白天颜色进行线性插值(Linear Interpolation)。", + "fog.config.option.initial_fog_start": "初始迷雾起点", + "fog.config.option.description.initial_fog_start": "当迷雾引擎加载时,从相机开始出现迷雾的初始距离,以渲染距离的百分比表示。", + "fog.config.option.initial_fog_end": "初始迷雾终点", + "fog.config.option.description.initial_fog_end": "当迷雾引擎加载时,从相机开始变为透明的初始距离,以渲染距离的百分比表示。", + "fog.config.option.disabled_biomes": "禁用生物群系", + "fog.config.option.description.disabled_biomes": "禁用对特定生物群系的所有迷雾更改。", + "fog.config.option.fog_start_transition_speed": "迷雾起点过渡速度", + "fog.config.option.description.fog_start_transition_speed": "控制迷雾起点距离过渡到新值的速度,较低的值将有更平滑的过渡。", + "fog.config.option.fog_end_transition_speed": "迷雾终点过渡速度", + "fog.config.option.description.fog_end_transition_speed": "控制迷雾终点距离过渡到新值的速度,较低的值将有更平滑的过渡。", + "fog.config.option.darkness_transition_speed": "黑暗过渡速度", + "fog.config.option.description.darkness_transition_speed": "控制黑暗程度过渡的速度,较低的值将有更平滑的过渡。", + "fog.config.option.fog_color_transition_speed": "迷雾颜色过渡速度", + "fog.config.option.description.fog_color_transition_speed": "控制迷雾颜色过渡以匹配环境变化的速度,较低的值将有更平滑的颜色变化。", + "fog.config.option.start_multiplier_transition_speed": "起点倍率过渡速度", + "fog.config.option.description.start_multiplier_transition_speed": "控制迷雾起点倍率过渡的速度,较低的值将有更平滑的过渡。", + "fog.config.option.end_multiplier_transition_speed": "终点倍率过渡速度", + "fog.config.option.description.end_multiplier_transition_speed": "控制迷雾终点倍率过渡的速度,较低的值将有更平滑的过渡。", + "fog.config.option.raininess_transition_speed": "降雨过渡速度", + "fog.config.option.description.raininess_transition_speed": "控制降雨效果过渡的速度,较低的值将有更平滑的过渡。", + "fog.config.option.undergroundness_transition_speed": "地下过渡速度", + "fog.config.option.description.undergroundness_transition_speed": "控制地下迷雾效果过渡的速度,较低的值将有更平滑的过渡。", + "key.fog.toggle": "切换迷雾引擎", + "fog.command.toggle.enabled": "迷雾引擎更改已重新启用。", + "fog.command.toggle.disabled": "迷雾引擎更改已禁用。", + "fog.command.reset": "迷雾引擎更改已重载并重置至默认值。", + "fog.command.debug.failure": "获取调试信息时出现错误。" +} diff --git a/fog/src/main/resources/assets/fog/lang/zh_tw.json b/fog/src/main/resources/assets/fog/lang/zh_tw.json new file mode 100644 index 0000000..da32c33 --- /dev/null +++ b/fog/src/main/resources/assets/fog/lang/zh_tw.json @@ -0,0 +1,27 @@ +{ + "fog.config.option.initial_fog_start": "初始迷霧起始距離", + "fog.config.option.description.initial_fog_start": "迷霧開始出現的初始距離(載入迷霧引擎時) - 以視野距離的百分比表示", + "fog.config.option.initial_fog_end": "初始迷霧結束距離", + "fog.config.option.description.initial_fog_end": "迷霧完全不透明的初始距離(載入迷霧引擎時) - 以視野距離的百分比表示", + "fog.config.option.fog_start_transition_speed": "迷霧起始過渡速度", + "fog.config.option.description.fog_start_transition_speed": "控制迷霧起始距離過渡到新值的的速度。值越低,過渡越平滑。", + "fog.config.option.fog_end_transition_speed": "迷霧結束過渡速度", + "fog.config.option.description.fog_end_transition_speed": "控制迷霧結束距離過渡到新值的的速度。值越低,過渡越平滑。", + "fog.config.option.darkness_transition_speed": "黑暗過渡速度", + "fog.config.option.description.darkness_transition_speed": "控制黑暗等級過渡的速度。值越低,過渡越平滑。", + "fog.config.option.fog_color_transition_speed": "迷霧顏色過渡速度", + "fog.config.option.description.fog_color_transition_speed": "控制迷霧顏色過渡以匹配環境變化的速度。值越低,顏色變化越平滑。", + "fog.config.option.start_multiplier_transition_speed": "起始倍數過渡速度", + "fog.config.option.description.start_multiplier_transition_speed": "控制迷霧起始倍數過渡的速度。值越低,過渡越平滑。", + "fog.config.option.end_multiplier_transition_speed": "結束倍數過渡速度", + "fog.config.option.description.end_multiplier_transition_speed": "控制迷霧結束倍數過渡的速度。值越低,過渡越平滑。", + "fog.config.option.raininess_transition_speed": "降雨過渡速度", + "fog.config.option.description.raininess_transition_speed": "控制降雨效果過渡的速度。值越低,過渡越平滑。", + "fog.config.option.undergroundness_transition_speed": "地下過渡速度", + "fog.config.option.description.undergroundness_transition_speed": "控制地下迷霧效果過渡的速度。值越低,過渡越平滑。", + "key.fog.toggle": "切換迷霧引擎", + "fog.command.toggle.enabled": "現在已重新啟用迷霧引擎修改。", + "fog.command.toggle.disabled": "現在已停用迷霧引擎修改。", + "fog.command.reset": "已重新載入迷霧引擎修改,並將其重設為設定中指定的預設值。", + "fog.command.debug.failure": "取得除錯資訊時發生錯誤。" +} diff --git a/fog/src/main/resources/fabric.mod.json b/fog/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..6cd9a11 --- /dev/null +++ b/fog/src/main/resources/fabric.mod.json @@ -0,0 +1,48 @@ +{ + "schemaVersion": 1, + "id": "fog", + "version": "${version}", + "name": "Fog", + "description": "An expansive and dynamic overhaul to Minecraft's fog rendering system.", + "authors": [ + "IMB11", + "Steveplays" + ], + "contact": { + "homepage": "https://imb11.dev/", + "sources": "https://github.com/IMB11/Fog", + "issues": "https://github.com/IMB11/Fog/issues" + }, + "license": "All-Rights-Reserved", + "icon": "assets/fog/icon.png", + "environment": "client", + "entrypoints": { + "client": [ + "dev.imb11.fog.loaders.fabric.FogClientFabric" + ], + "modmenu": [ + "dev.imb11.fog.client.compat.modmenu.FogClientModMenuCompat" + ], + "fabric-datagen": [ + "dev.imb11.fog.loaders.fabric.datagen.FogDatagenFabric" + ] + }, + "mixins": [ + "fog.mixins.json" + ], + "depends": { + "fabricloader": ">=${target_loader}", + "fabric-api": "*", + "mru": "${target_mru}", + "yet_another_config_lib_v3": "${target_yacl}", + "minecraft": "${target_minecraft}", + "java": ">=25" + }, + "custom": { + "mc-publish": { + "dependencies": [ + "yacl" + ] + } + } +} diff --git a/fog/src/main/resources/fog.mixins.json b/fog/src/main/resources/fog.mixins.json new file mode 100644 index 0000000..36c2ec8 --- /dev/null +++ b/fog/src/main/resources/fog.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "package": "dev.imb11.fog.mixin", + "compatibilityLevel": "JAVA_25", + "minVersion": "0.8", + "injectors": { + "defaultRequire": 1 + }, + "client": [ + "client.ClientPacketListenerMixin", + "client.rendering.FogRendererMixin" + ] +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0754764..f871c3f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ jsonlang = "2.1-beta.4" jspecify = "1.0.0" kaleido = "0.3.3+1.3.2" -loom = "1.16.1" +loom = "1.18.2" mod-publish = "2.2.1" moddev = "2.0.147" diff --git a/gradle/minecraft/26.1.2.versions.toml b/gradle/minecraft/26.1.2.versions.toml index 6d82c77..ff47737 100644 --- a/gradle/minecraft/26.1.2.versions.toml +++ b/gradle/minecraft/26.1.2.versions.toml @@ -4,16 +4,15 @@ accessories-neoforge = "1.3.7-beta+1.21.8" cca = "8.0.0" cloth = "26.1.154" curios-neoforge = "15.0.0+26.1.2" -fabric-api = "0.155.2+26.1.2" +fabric-api = "0.155.3+26.1.2" fabric-loader = "0.19.5" forge-config-api-port-fabric = "26.1.5" forgified-fabric-api = "0.154.0+3.2.6+26.1.2" jade-fabric = "26.1.0+fabric" jei = "29.43.0.106" map-atlases = "6345967" -mcqoy = "0.4.1+fabric-26.1" -modmenu = "18.0.0-beta.1" -neoforge = "26.1.2.107" +modmenu = "18.0.2" +neoforge = "26.1.2.114" ohmega-fabric = "1.5.20-mc26.1.2" ohmega-neoforge = "1.5.20-mc26.1.2" porting-lib-transfer = "2.3.9+1.20.1" @@ -22,16 +21,26 @@ sophisticated-backpacks-fabric = "26.1.2-3.25.55.1739" sophisticated-backpacks-neoforge = "26.1.2-3.25.55.1739" sophisticated-core-fabric = "26.1.2-1.4.45.1849" sophisticated-core-neoforge = "26.1.2-1.4.45.1849" -surveyor = "1.2.4+26.1" trashslot = "Kq3z6gII" travelers-backpack-fabric = "26.1.2-11.2.6" travelers-backpack-neoforge = "26.1.2-11.2.4-neoforge" trinkets-fabric = "4.0.0-beta.3+26.1" trinkets-neoforge = "4.0.0-beta.3+26.1" -yacl-fabric = "3.9.3+26.1-fabric" -yacl-neoforge = "3.9.3+26.1-neoforge" +yacl-fabric = "3.9.7+26.1-fabric" +yacl-neoforge = "3.9.7+26.1-neoforge" +architectury = "20.1.16" +polytone-fabric = "3MAkNiv1" +polytone-neoforge = "osavRdFq" +iris-fabric = "sZbVsl2Q" +iris-neoforge = "qE5Y7GrZ" [libraries] +architectury-fabric = { module = "dev.architectury:architectury-fabric", version.ref = "architectury" } +architectury-neoforge = { module = "dev.architectury:architectury-neoforge", version.ref = "architectury" } +polytone-fabric = { module = "maven.modrinth:polytone", version.ref = "polytone-fabric" } +polytone-neoforge = { module = "maven.modrinth:polytone", version.ref = "polytone-neoforge" } +iris-fabric = { module = "maven.modrinth:iris", version.ref = "iris-fabric" } +iris-neoforge = { module = "maven.modrinth:iris", version.ref = "iris-neoforge" } accessories-fabric = { module = "io.wispforest:accessories-neoforge", version.ref = "accessories-fabric" } accessories-neoforge = { module = "io.wispforest:accessories-neoforge", version.ref = "accessories-neoforge" } cca-base = { module = "org.ladysnake.cardinal-components-api:cardinal-components-base", version.ref = "cca" } @@ -47,7 +56,6 @@ jade-fabric = { module = "maven.modrinth:jade", version.ref = "jade-fabric" } jei-fabric = { module = "mezz.jei:jei-26.1.2-fabric", version.ref = "jei" } jei-neoforge = { module = "mezz.jei:jei-26.1.2-neoforge", version.ref = "jei" } map-atlases = { module = "curse.maven:map-atlases-forge-519759", version.ref = "map-atlases" } -mcqoy = { module = "maven.modrinth:mcqoy", version.ref = "mcqoy" } modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" } neoforge = { module = "net.neoforged:neoforge", version.ref = "neoforge" } ohmega-fabric = { module = "io.github.swackyy:ohmega-fabric", version.ref = "ohmega-fabric" } @@ -59,7 +67,6 @@ sophisticated-backpacks-fabric = { module = "maven.modrinth:sophisticated-backpa sophisticated-backpacks-neoforge = { module = "maven.modrinth:sophisticated-backpacks", version.ref = "sophisticated-backpacks-neoforge" } sophisticated-core-fabric = { module = "maven.modrinth:sophisticated-core", version.ref = "sophisticated-core-fabric" } sophisticated-core-neoforge = { module = "maven.modrinth:sophisticated-core", version.ref = "sophisticated-core-neoforge" } -surveyor = { module = "maven.modrinth:surveyor", version.ref = "surveyor" } trashslot = { module = "maven.modrinth:trashslot", version.ref = "trashslot" } travelers-backpack-fabric = { module = "maven.modrinth:travelersbackpack", version.ref = "travelers-backpack-fabric" } travelers-backpack-neoforge = { module = "maven.modrinth:travelersbackpack", version.ref = "travelers-backpack-neoforge" } diff --git a/gradle/minecraft/26.3.versions.toml b/gradle/minecraft/26.3.versions.toml index 21c7f5f..a7fd6ea 100644 --- a/gradle/minecraft/26.3.versions.toml +++ b/gradle/minecraft/26.3.versions.toml @@ -1,4 +1,6 @@ [versions] +iris-fabric = "vTN4NRGW" +iris-neoforge = "Ag5S66CF" accessories-fabric = "1.4.3-beta+1.21.10" accessories-neoforge = "1.3.7-beta+1.21.8" cca = "8.0.0" @@ -11,7 +13,6 @@ forgified-fabric-api = "0.154.0+3.2.6+26.1.2" jade-fabric = "26.2.9+fabric" jei = "31.9.0.57" map-atlases = "6345967" -mcqoy = "0.4.1+fabric-26.1" modmenu = "21.0.0-alpha.1" neoforge = "26.3.0.33-beta" ohmega-fabric = "1.5.19-mc26.2" @@ -22,7 +23,6 @@ sophisticated-backpacks-fabric = "26.1.2-3.25.55.1739" sophisticated-backpacks-neoforge = "26.2-3.25.77.1959" sophisticated-core-fabric = "26.1.2-1.4.45.1849" sophisticated-core-neoforge = "26.2-1.4.75.2101" -surveyor = "1.2.4+26.1" trashslot = "Kq3z6gII" travelers-backpack-fabric = "26.1.2-11.2.6" travelers-backpack-neoforge = "26.1.2-11.2.4-neoforge" @@ -32,6 +32,8 @@ yacl-fabric = "3.9.6+26.3-fabric" yacl-neoforge = "3.9.7+26.3-neoforge" [libraries] +iris-fabric = { module = "maven.modrinth:iris", version.ref = "iris-fabric" } +iris-neoforge = { module = "maven.modrinth:iris", version.ref = "iris-neoforge" } accessories-fabric = { module = "io.wispforest:accessories-neoforge", version.ref = "accessories-fabric" } accessories-neoforge = { module = "io.wispforest:accessories-neoforge", version.ref = "accessories-neoforge" } cca-base = { module = "org.ladysnake.cardinal-components-api:cardinal-components-base", version.ref = "cca" } @@ -47,7 +49,6 @@ jade-fabric = { module = "maven.modrinth:jade", version.ref = "jade-fabric" } jei-fabric = { module = "mezz.jei:jei-26.3-fabric", version.ref = "jei" } jei-neoforge = { module = "mezz.jei:jei-26.3-neoforge", version.ref = "jei" } map-atlases = { module = "curse.maven:map-atlases-forge-519759", version.ref = "map-atlases" } -mcqoy = { module = "maven.modrinth:mcqoy", version.ref = "mcqoy" } modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" } neoforge = { module = "net.neoforged:neoforge", version.ref = "neoforge" } ohmega-fabric = { module = "io.github.swackyy:ohmega-fabric", version.ref = "ohmega-fabric" } @@ -59,7 +60,6 @@ sophisticated-backpacks-fabric = { module = "maven.modrinth:sophisticated-backpa sophisticated-backpacks-neoforge = { module = "maven.modrinth:sophisticated-backpacks", version.ref = "sophisticated-backpacks-neoforge" } sophisticated-core-fabric = { module = "maven.modrinth:sophisticated-core", version.ref = "sophisticated-core-fabric" } sophisticated-core-neoforge = { module = "maven.modrinth:sophisticated-core", version.ref = "sophisticated-core-neoforge" } -surveyor = { module = "maven.modrinth:surveyor", version.ref = "surveyor" } trashslot = { module = "maven.modrinth:trashslot", version.ref = "trashslot" } travelers-backpack-fabric = { module = "maven.modrinth:travelersbackpack", version.ref = "travelers-backpack-fabric" } travelers-backpack-neoforge = { module = "maven.modrinth:travelersbackpack", version.ref = "travelers-backpack-neoforge" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5dd3c01..1e922f4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/mru/build.fabric.gradle.kts b/mru/build.fabric.gradle.kts index d1c1cc7..fc4973c 100644 --- a/mru/build.fabric.gradle.kts +++ b/mru/build.fabric.gradle.kts @@ -33,8 +33,6 @@ dependencies { runtimeOnly(mcLibrary("cloth-fabric")) runtimeOnly(mcLibrary("yacl-fabric")) runtimeOnly(mcLibrary("modmenu")) - runtimeOnly(mcLibrary("mcqoy")) -// runtimeOnly(mcLibrary("surveyor")) } stonecutter { diff --git a/settings.gradle.kts b/settings.gradle.kts index ccd5a10..32c4f3d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -18,6 +18,7 @@ plugins { rootProject.name = "JavaEditionMods" val modTargets = mapOf( + "fog" to listOf("26.1.2", "26.3"), "mru" to listOf("26.1.2", "26.3"), "sounds" to listOf("26.1.2", "26.3"), "shields" to listOf("26.3")