diff --git a/README.md b/README.md index 0521236a..7310d2e9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![](https://jitpack.io/v/paulevsGitch/BCLib.svg)](https://jitpack.io/#paulevsGitch/BCLib) # BCLib -BCLib is a library mod for BetterX team mods, developed for Fabric, MC 1.17.1 +BCLib is a library mod for BetterX team mods, developed for Fabric, MC 1.18 ## Features: ### Rendering diff --git a/bclib.gradle b/bclib.gradle index 2f8a64ae..540c5ae0 100644 --- a/bclib.gradle +++ b/bclib.gradle @@ -7,8 +7,8 @@ buildscript { gradlePluginPortal() } } -sourceCompatibility = JavaVersion.VERSION_16 -targetCompatibility = JavaVersion.VERSION_16 +sourceCompatibility = JavaVersion.VERSION_17 +targetCompatibility = JavaVersion.VERSION_17 archivesBaseName = project.archives_base_name version = project.mod_version @@ -89,7 +89,7 @@ processResources { // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html tasks.withType(JavaCompile) { options.encoding = "UTF-8" - it.options.release = 16 + it.options.release = 17 } javadoc { diff --git a/gradle.properties b/gradle.properties index d3887f7c..b83defa9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,16 +2,16 @@ org.gradle.jvmargs=-Xmx2G #Loom -loom_version=0.8-SNAPSHOT +loom_version=0.10-SNAPSHOT # Fabric Properties # check these on https://fabricmc.net/versions.html -minecraft_version= 1.17.1 -loader_version= 0.12.5 -fabric_version = 0.42.1+1.17 +minecraft_version= 1.18 +loader_version= 0.12.6 +fabric_version = 0.43.1+1.18 # Mod Properties -mod_version = 0.5.5 +mod_version = 1.0.0 maven_group = ru.bclib archives_base_name = bclib diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 490fda85..7454180f 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f371643e..e750102e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 index 2fe81a7d..1b6c7873 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,78 +17,113 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -105,79 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 9109989e..ac1b06f9 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/src/main/java/ru/bclib/BCLib.java b/src/main/java/ru/bclib/BCLib.java index 1e450f96..bc71a685 100644 --- a/src/main/java/ru/bclib/BCLib.java +++ b/src/main/java/ru/bclib/BCLib.java @@ -20,7 +20,6 @@ import ru.bclib.util.Logger; import ru.bclib.world.generator.BCLibEndBiomeSource; import ru.bclib.world.generator.BCLibNetherBiomeSource; import ru.bclib.world.generator.GeneratorOptions; -import ru.bclib.world.surface.BCLSurfaceBuilders; import java.util.List; @@ -33,7 +32,6 @@ public class BCLib implements ModInitializer { BaseRegistry.register(); GeneratorOptions.init(); BaseBlockEntities.register(); - BCLSurfaceBuilders.register(); BCLibEndBiomeSource.register(); BCLibNetherBiomeSource.register(); TagAPI.init(); @@ -42,11 +40,11 @@ public class BCLib implements ModInitializer { DataExchangeAPI.registerMod(MOD_ID); DataExchangeAPI.registerDescriptors(List.of( - HelloClient.DESCRIPTOR, - HelloServer.DESCRIPTOR, - RequestFiles.DESCRIPTOR, - SendFiles.DESCRIPTOR, - Chunker.DESCRIPTOR + HelloClient.DESCRIPTOR, + HelloServer.DESCRIPTOR, + RequestFiles.DESCRIPTOR, + SendFiles.DESCRIPTOR, + Chunker.DESCRIPTOR )); BCLibPatch.register(); diff --git a/src/main/java/ru/bclib/api/LifeCycleAPI.java b/src/main/java/ru/bclib/api/LifeCycleAPI.java index eddba849..05ade7a5 100644 --- a/src/main/java/ru/bclib/api/LifeCycleAPI.java +++ b/src/main/java/ru/bclib/api/LifeCycleAPI.java @@ -11,7 +11,6 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.storage.LevelStorageSource; -import net.minecraft.world.level.storage.LevelStorageSource.LevelStorageAccess; import net.minecraft.world.level.storage.ServerLevelData; import java.util.ArrayList; @@ -24,6 +23,13 @@ import java.util.concurrent.Executor; public class LifeCycleAPI { private final static List onLoadLevelBiomes = new ArrayList<>(2); private final static List onLoadLevel = new ArrayList<>(2); + private final static List beforeLoadLevel = new ArrayList<>(2); + /** + * A callback function that is used for each new ServerLevel instance + */ + public interface BeforeLevelLoadCall { + void beforeLoad(); + } /** * A callback function that is used for each new ServerLevel instance @@ -52,6 +58,17 @@ public class LifeCycleAPI { boolean bl2); } + /** + * Register a callback that is called before a level is loaded or created, + * but after the {@link WorldDataAPI} was initialized and patches from + * the {@link ru.bclib.api.datafixer.DataFixerAPI} were applied. + * + * @param call The callback Method + */ + public static void beforeLevelLoad(BeforeLevelLoadCall call){ + beforeLoadLevel.add(call); + } + /** * Register a callback that is called when a new {@code ServerLevel is instantiated}. * This callback will receive the world seed as well as it's biome registry. @@ -70,6 +87,13 @@ public class LifeCycleAPI { onLoadLevel.add(call); } + /** + * For internal use, You should not call this method! + * @param src + */ + public static void _runBeforeLevelLoad(){ + beforeLoadLevel.forEach(c -> c.beforeLoad()); + } /** * For internal use, You should not call this method! * @param minecraftServer diff --git a/src/main/java/ru/bclib/api/PostInitAPI.java b/src/main/java/ru/bclib/api/PostInitAPI.java index 29adf17b..63b2c1d5 100644 --- a/src/main/java/ru/bclib/api/PostInitAPI.java +++ b/src/main/java/ru/bclib/api/PostInitAPI.java @@ -6,7 +6,10 @@ import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; import net.minecraft.client.renderer.RenderType; import net.minecraft.core.Registry; +import net.minecraft.tags.Tag; +import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; +import ru.bclib.api.biomes.BiomeAPI; import ru.bclib.blocks.BaseBarrelBlock; import ru.bclib.blocks.BaseChestBlock; import ru.bclib.blocks.BaseFurnaceBlock; @@ -16,6 +19,7 @@ import ru.bclib.client.render.BaseChestBlockEntityRenderer; import ru.bclib.client.render.BaseSignBlockEntityRenderer; import ru.bclib.interfaces.PostInitable; import ru.bclib.interfaces.RenderLayerProvider; +import ru.bclib.interfaces.TagProvider; import ru.bclib.registry.BaseBlockEntities; import java.util.List; @@ -23,6 +27,8 @@ import java.util.function.Consumer; public class PostInitAPI { private static List> postInitFunctions = Lists.newArrayList(); + private static List> blockTags = Lists.newArrayList(); + private static List> itemTags = Lists.newArrayList(); /** * Register a new function which will be called after all mods are initiated. Will be called on both client and server. @@ -48,6 +54,8 @@ public class PostInitAPI { } }); postInitFunctions = null; + blockTags = null; + itemTags = null; BiomeAPI.loadFabricAPIBiomes(); } @@ -82,5 +90,12 @@ public class PostInitAPI { else if (block instanceof BaseFurnaceBlock) { BaseBlockEntities.FURNACE.registerBlock(block); } + if (block instanceof TagProvider) { + TagProvider.class.cast(block).addTags(blockTags, itemTags); + blockTags.forEach(tag -> TagAPI.addTag(tag, block)); + itemTags.forEach(tag -> TagAPI.addTag(tag, block)); + blockTags.clear(); + itemTags.clear(); + } } } diff --git a/src/main/java/ru/bclib/api/TagAPI.java b/src/main/java/ru/bclib/api/TagAPI.java index 6da6e070..a9948037 100644 --- a/src/main/java/ru/bclib/api/TagAPI.java +++ b/src/main/java/ru/bclib/api/TagAPI.java @@ -2,7 +2,9 @@ package ru.bclib.api; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import net.fabricmc.fabric.api.tag.TagFactory; import net.fabricmc.fabric.api.tag.TagRegistry; +import net.fabricmc.fabric.impl.tag.extension.TagDelegate; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; @@ -75,7 +77,8 @@ public class TagAPI { */ public static Tag.Named makeTag(Supplier> containerSupplier, ResourceLocation id) { Tag tag = containerSupplier.get().getTag(id); - return tag == null ? TagRegistry.create(id, containerSupplier) : (Named) tag; + //return tag == null ? TagRegistry.create(id, containerSupplier) : (Named) tag; + return tag == null ? new TagDelegate<>(id, containerSupplier) : (Named) tag; } /** @@ -131,7 +134,8 @@ public class TagAPI { public static Tag.Named getMCBlockTag(String name) { ResourceLocation id = new ResourceLocation(name); Tag tag = BlockTags.getAllTags().getTag(id); - return tag == null ? (Named) TagRegistry.block(id) : (Named) tag; + //return tag == null ? (Named) TagRegistry.block(id) : (Named) tag; + return tag == null ? (Named) TagFactory.BLOCK.create(id): (Named) tag; } /** diff --git a/src/main/java/ru/bclib/api/WorldDataAPI.java b/src/main/java/ru/bclib/api/WorldDataAPI.java index b1794df7..d15cf43b 100644 --- a/src/main/java/ru/bclib/api/WorldDataAPI.java +++ b/src/main/java/ru/bclib/api/WorldDataAPI.java @@ -44,6 +44,7 @@ public class WorldDataAPI { catch (IOException e) { BCLib.LOGGER.error("World data loading failed", e); } + TAGS.put(modID, root); } else { Optional optional = FabricLoader.getInstance() @@ -58,11 +59,10 @@ public class WorldDataAPI { .getVersion() .toString()); } + TAGS.put(modID, root); saveFile(modID); } } - - TAGS.put(modID, root); }); } diff --git a/src/main/java/ru/bclib/api/biomes/BCLBiomeBuilder.java b/src/main/java/ru/bclib/api/biomes/BCLBiomeBuilder.java new file mode 100644 index 00000000..eb53ef05 --- /dev/null +++ b/src/main/java/ru/bclib/api/biomes/BCLBiomeBuilder.java @@ -0,0 +1,599 @@ +package ru.bclib.api.biomes; + +import net.fabricmc.fabric.api.biome.v1.BiomeModifications; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.data.BuiltinRegistries; +import net.minecraft.data.worldgen.BiomeDefaultFeatures; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.Music; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.level.biome.AmbientAdditionsSettings; +import net.minecraft.world.level.biome.AmbientMoodSettings; +import net.minecraft.world.level.biome.AmbientParticleSettings; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biome.BiomeBuilder; +import net.minecraft.world.level.biome.Biome.BiomeCategory; +import net.minecraft.world.level.biome.Biome.Precipitation; +import net.minecraft.world.level.biome.BiomeGenerationSettings; +import net.minecraft.world.level.biome.BiomeSpecialEffects; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.biome.MobSpawnSettings.SpawnerData; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.GenerationStep.Decoration; +import net.minecraft.world.level.levelgen.Noises; +import net.minecraft.world.level.levelgen.SurfaceRules; +import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver; +import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; +import net.minecraft.world.level.levelgen.placement.PlacedFeature; +import ru.bclib.util.ColorUtil; +import ru.bclib.world.biomes.BCLBiome; +import ru.bclib.world.features.BCLFeature; +import ru.bclib.world.structures.BCLStructureFeature; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Consumer; + +public class BCLBiomeBuilder { + private static final BCLBiomeBuilder INSTANCE = new BCLBiomeBuilder(); + private static final SurfaceRules.ConditionSource SURFACE_NOISE = SurfaceRules.noiseCondition(Noises.SOUL_SAND_LAYER, -0.012); + + private List structures = new ArrayList<>(16); + private BiomeGenerationSettings.Builder generationSettings; + private BiomeSpecialEffects.Builder effectsBuilder; + private MobSpawnSettings.Builder spawnSettings; + private SurfaceRules.RuleSource surfaceRule; + private Precipitation precipitation; + private ResourceLocation biomeID; + private BiomeCategory category; + private float temperature; + private float fogDensity; + private float downfall; + + /** + * Starts new biome building process. + * @param biomeID {@link ResourceLocation} biome identifier. + * @return prepared {@link BCLBiomeBuilder} instance. + */ + public static BCLBiomeBuilder start(ResourceLocation biomeID) { + INSTANCE.biomeID = biomeID; + INSTANCE.precipitation = Precipitation.NONE; + INSTANCE.category = BiomeCategory.NONE; + INSTANCE.generationSettings = null; + INSTANCE.effectsBuilder = null; + INSTANCE.spawnSettings = null; + INSTANCE.structures.clear(); + INSTANCE.temperature = 1.0F; + INSTANCE.fogDensity = 1.0F; + INSTANCE.downfall = 1.0F; + return INSTANCE; + } + + /** + * Set biome {@link Precipitation}. Affect biome visual effects (rain, snow, none). + * @param precipitation {@link Precipitation} + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder precipitation(Precipitation precipitation) { + this.precipitation = precipitation; + return this; + } + + /** + * Set biome category. Doesn't affect biome worldgen, but Fabric biome modifications can target biome by it. + * @param category {@link BiomeCategory} + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder category(BiomeCategory category) { + this.category = category; + return this; + } + + /** + * Set biome temperature, affect plant color, biome generation and ice formation. + * @param temperature biome temperature. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder temperature(float temperature) { + this.temperature = temperature; + return this; + } + + /** + * Set biome wetness (same as downfall). Affect plant color and biome generation. + * @param wetness biome wetness (downfall). + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder wetness(float wetness) { + this.downfall = wetness; + return this; + } + + /** + * Adds mob spawning to biome. + * @param entityType {@link EntityType} mob type. + * @param weight spawn weight. + * @param minGroupCount minimum mobs in group. + * @param maxGroupCount maximum mobs in group. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder spawn(EntityType entityType, int weight, int minGroupCount, int maxGroupCount) { + getSpawns().addSpawn(entityType.getCategory(), new SpawnerData(entityType, weight, minGroupCount, maxGroupCount)); + return this; + } + + /** + * Adds ambient particles to thr biome. + * @param particle {@link ParticleOptions} particles (or {@link net.minecraft.core.particles.ParticleType}). + * @param probability particle spawn probability, should have low value (example: 0.01F). + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder particles(ParticleOptions particle, float probability) { + getEffects().ambientParticle(new AmbientParticleSettings(particle, probability)); + return this; + } + + /** + * Sets sky color for the biome. Color is in ARGB int format. + * @param color ARGB color as integer. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder skyColor(int color) { + getEffects().skyColor(color); + return this; + } + + /** + * Sets sky color for the biome. Color represented as red, green and blue channel values. + * @param red red color component [0-255] + * @param green green color component [0-255] + * @param blue blue color component [0-255] + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder skyColor(int red, int green, int blue) { + red = Mth.clamp(red, 0, 255); + green = Mth.clamp(green, 0, 255); + blue = Mth.clamp(blue, 0, 255); + return skyColor(ColorUtil.color(red, green, blue)); + } + + /** + * Sets fog color for the biome. Color is in ARGB int format. + * @param color ARGB color as integer. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder fogColor(int color) { + getEffects().fogColor(color); + return this; + } + + /** + * Sets fog color for the biome. Color represented as red, green and blue channel values. + * @param red red color component [0-255] + * @param green green color component [0-255] + * @param blue blue color component [0-255] + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder fogColor(int red, int green, int blue) { + red = Mth.clamp(red, 0, 255); + green = Mth.clamp(green, 0, 255); + blue = Mth.clamp(blue, 0, 255); + return fogColor(ColorUtil.color(red, green, blue)); + } + + /** + * Sets fog density for the biome. + * @param density fog density as a float, default value is 1.0F. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder fogDensity(float density) { + this.fogDensity = density; + return this; + } + + /** + * Sets water color for the biome. Color is in ARGB int format. + * @param color ARGB color as integer. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder waterColor(int color) { + getEffects().waterColor(color); + return this; + } + + /** + * Sets water color for the biome. Color represented as red, green and blue channel values. + * @param red red color component [0-255] + * @param green green color component [0-255] + * @param blue blue color component [0-255] + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder waterColor(int red, int green, int blue) { + red = Mth.clamp(red, 0, 255); + green = Mth.clamp(green, 0, 255); + blue = Mth.clamp(blue, 0, 255); + return waterColor(ColorUtil.color(red, green, blue)); + } + + /** + * Sets underwater fog color for the biome. Color is in ARGB int format. + * @param color ARGB color as integer. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder waterFogColor(int color) { + getEffects().waterFogColor(color); + return this; + } + + /** + * Sets underwater fog color for the biome. Color represented as red, green and blue channel values. + * @param red red color component [0-255] + * @param green green color component [0-255] + * @param blue blue color component [0-255] + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder waterFogColor(int red, int green, int blue) { + red = Mth.clamp(red, 0, 255); + green = Mth.clamp(green, 0, 255); + blue = Mth.clamp(blue, 0, 255); + return waterFogColor(ColorUtil.color(red, green, blue)); + } + + /** + * Sets water and underwater fig color for the biome. Color is in ARGB int format. + * @param color ARGB color as integer. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder waterAndFogColor(int color) { + return waterColor(color).waterFogColor(color); + } + + /** + * Sets water and underwater fig color for the biome. Color is in ARGB int format. + * @param red red color component [0-255] + * @param green green color component [0-255] + * @param blue blue color component [0-255] + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder waterAndFogColor(int red, int green, int blue) { + red = Mth.clamp(red, 0, 255); + green = Mth.clamp(green, 0, 255); + blue = Mth.clamp(blue, 0, 255); + return waterAndFogColor(ColorUtil.color(red, green, blue)); + } + + /** + * Sets grass color for the biome. Color is in ARGB int format. + * @param color ARGB color as integer. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder grassColor(int color) { + getEffects().grassColorOverride(color); + return this; + } + + /** + * Sets grass color for the biome. Color represented as red, green and blue channel values. + * @param red red color component [0-255] + * @param green green color component [0-255] + * @param blue blue color component [0-255] + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder grassColor(int red, int green, int blue) { + red = Mth.clamp(red, 0, 255); + green = Mth.clamp(green, 0, 255); + blue = Mth.clamp(blue, 0, 255); + return grassColor(ColorUtil.color(red, green, blue)); + } + + /** + * Sets leaves and plants color for the biome. Color is in ARGB int format. + * @param color ARGB color as integer. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder foliageColor(int color) { + getEffects().foliageColorOverride(color); + return this; + } + + /** + * Sets leaves and plants color for the biome. Color represented as red, green and blue channel values. + * @param red red color component [0-255] + * @param green green color component [0-255] + * @param blue blue color component [0-255] + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder foliageColor(int red, int green, int blue) { + red = Mth.clamp(red, 0, 255); + green = Mth.clamp(green, 0, 255); + blue = Mth.clamp(blue, 0, 255); + return foliageColor(ColorUtil.color(red, green, blue)); + } + + /** + * Sets grass, leaves and all plants color for the biome. Color is in ARGB int format. + * @param color ARGB color as integer. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder plantsColor(int color) { + return grassColor(color).foliageColor(color); + } + + /** + * Sets grass, leaves and all plants color for the biome. Color represented as red, green and blue channel values. + * @param red red color component [0-255] + * @param green green color component [0-255] + * @param blue blue color component [0-255] + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder plantsColor(int red, int green, int blue) { + red = Mth.clamp(red, 0, 255); + green = Mth.clamp(green, 0, 255); + blue = Mth.clamp(blue, 0, 255); + return plantsColor(ColorUtil.color(red, green, blue)); + } + + /** + * Sets biome music, used for biomes in the Nether and End. + * @param music {@link Music} to use. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder music(Music music) { + getEffects().backgroundMusic(music); + return this; + } + + /** + * Sets biome music, used for biomes in the Nether and End. + * @param music {@link SoundEvent} to use. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder music(SoundEvent music) { + return music(new Music(music, 600, 2400, true)); + } + + /** + * Sets biome ambient loop sound. Can be used for biome environment. + * @param loopSound {@link SoundEvent} to use as a loop. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder loop(SoundEvent loopSound) { + getEffects().ambientLoopSound(loopSound); + return this; + } + + /** + * Sets biome mood sound. Can be used for biome environment. + * @param mood {@link SoundEvent} to use as a mood. + * @param tickDelay delay between sound events in ticks. + * @param blockSearchExtent block search radius (for area available for sound). + * @param soundPositionOffset offset in sound. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder mood(SoundEvent mood, int tickDelay, int blockSearchExtent, float soundPositionOffset) { + getEffects().ambientMoodSound(new AmbientMoodSettings(mood, tickDelay, blockSearchExtent, soundPositionOffset)); + return this; + } + + /** + * Sets biome mood sound. Can be used for biome environment. + * @param mood {@link SoundEvent} to use as a mood. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder mood(SoundEvent mood) { + return mood(mood, 6000, 8, 2.0F); + } + + /** + * Sets biome additionsl ambient sounds. + * @param additions {@link SoundEvent} to use. + * @param intensity sound intensity. Default is 0.0111F. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder additions(SoundEvent additions, float intensity) { + getEffects().ambientAdditionsSound(new AmbientAdditionsSettings(additions, intensity)); + return this; + } + + /** + * Sets biome additionsl ambient sounds. + * @param additions {@link SoundEvent} to use. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder additions(SoundEvent additions) { + return additions(additions, 0.0111F); + } + + /** + * Adds new feature to the biome. + * @param decoration {@link Decoration} feature step. + * @param feature {@link PlacedFeature}. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder feature(Decoration decoration, PlacedFeature feature) { + getGeneration().addFeature(decoration, feature); + return this; + } + + /** + * Adds vanilla Mushrooms. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder defaultMushrooms() { + return feature(BiomeDefaultFeatures::addDefaultMushrooms); + } + + /** + * Adds vanilla Nether Ores. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder netherDefaultOres() { + return feature(BiomeDefaultFeatures::addNetherDefaultOres); + } + + /** + * Will add features into biome, used for vanilla feature adding functions. + * @param featureAdd {@link Consumer} with {@link BiomeGenerationSettings.Builder}. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder feature(Consumer featureAdd) { + featureAdd.accept(getGeneration()); + return this; + } + + /** + * Adds new feature to the biome. + * @param feature {@link BCLFeature}. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder feature(BCLFeature feature) { + return feature(feature.getDecoration(), feature.getPlacedFeature()); + } + + /** + * Adds new structure feature into the biome. + * @param structure {@link ConfiguredStructureFeature} to add. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder structure(ConfiguredStructureFeature structure) { + structures.add(structure); + return this; + } + + /** + * Adds new structure feature into thr biome. Will add building biome into the structure list. + * @param structure {@link BCLStructureFeature} to add. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder structure(BCLStructureFeature structure) { + structure.addInternalBiome(biomeID); + return structure(structure.getFeatureConfigured()); + } + + /** + * Adds new world carver into the biome. + * @param carver {@link ConfiguredWorldCarver} to add. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder carver(GenerationStep.Carving step, ConfiguredWorldCarver carver) { + BuiltinRegistries.CONFIGURED_CARVER + .getResourceKey(carver) + .ifPresent(key -> BiomeModifications.addCarver(ctx -> ctx.getBiomeKey().location().equals(biomeID), step, key)); + return this; + } + + /** + * Adds new world surface rule for the given block + * @param surfaceBlock {@link Block} to use. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder surface(Block surfaceBlock) { + return surface(SurfaceRuleBuilder.start().surface(surfaceBlock.defaultBlockState()).build()); + } + + /** + * Adds blocks to the biome surface and below it (with specified depth). + * @param surfaceBlock {@link Block} that will cover biome. + * @param subterrainBlock {@link Block} below it with specified depth. + * @param depth thickness of bottom block layer. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder surface(Block surfaceBlock, Block subterrainBlock, int depth) { + return surface(SurfaceRuleBuilder + .start() + .surface(surfaceBlock.defaultBlockState()) + .subsurface(subterrainBlock.defaultBlockState(), depth) + .build()); + } + + /** + * Adds surface rule to this biome. + * @param surfaceRule {link SurfaceRules.RuleSource} surface rule. + * @return same {@link BCLBiomeBuilder} instance. + */ + public BCLBiomeBuilder surface(SurfaceRules.RuleSource surfaceRule) { + this.surfaceRule = surfaceRule; + return this; + } + + /** + * Finalize biome creation. + * @return created {@link BCLBiome} instance. + */ + public BCLBiome build() { + return build(BCLBiome::new); + } + + /** + * Finalize biome creation. + * @param biomeConstructor {@link BiFunction} biome constructor. + * @return created {@link BCLBiome} instance. + */ + public T build(BiFunction biomeConstructor) { + BiomeBuilder builder = new BiomeBuilder() + .precipitation(precipitation) + .biomeCategory(category) + .temperature(temperature) + .downfall(downfall); + + if (spawnSettings != null) { + builder.mobSpawnSettings(spawnSettings.build()); + } + + if (effectsBuilder != null) { + builder.specialEffects(effectsBuilder.build()); + } + + if (generationSettings != null) { + builder.generationSettings(generationSettings.build()); + } + + final T res = biomeConstructor.apply(biomeID, builder.build()); + res.attachStructures(structures); + res.setSurface(surfaceRule); + res.setFogDensity(fogDensity); + return res; + } + + /** + * Get or create {@link BiomeSpecialEffects.Builder} for biome visual effects. + * For internal usage only. + * For internal usage only. + * @return new or same {@link BiomeSpecialEffects.Builder} instance. + */ + private BiomeSpecialEffects.Builder getEffects() { + if (effectsBuilder == null) { + effectsBuilder = new BiomeSpecialEffects.Builder(); + } + return effectsBuilder; + } + + /** + * Get or create {@link MobSpawnSettings.Builder} for biome mob spawning. + * For internal usage only. + * @return new or same {@link MobSpawnSettings.Builder} instance. + */ + private MobSpawnSettings.Builder getSpawns() { + if (spawnSettings == null) { + spawnSettings = new MobSpawnSettings.Builder(); + } + return spawnSettings; + } + + /** + * Get or create {@link BiomeGenerationSettings.Builder} for biome features and generation. + * For internal usage only. + * @return new or same {@link BiomeGenerationSettings.Builder} instance. + */ + private BiomeGenerationSettings.Builder getGeneration() { + if (generationSettings == null) { + generationSettings = new BiomeGenerationSettings.Builder(); + } + return generationSettings; + } +} diff --git a/src/main/java/ru/bclib/api/BiomeAPI.java b/src/main/java/ru/bclib/api/biomes/BiomeAPI.java similarity index 54% rename from src/main/java/ru/bclib/api/BiomeAPI.java rename to src/main/java/ru/bclib/api/biomes/BiomeAPI.java index e03a53d1..9bad5eee 100644 --- a/src/main/java/ru/bclib/api/BiomeAPI.java +++ b/src/main/java/ru/bclib/api/biomes/BiomeAPI.java @@ -1,530 +1,728 @@ -package ru.bclib.api; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.fabricmc.fabric.impl.biome.InternalBiomeData; -import net.fabricmc.fabric.mixin.biome.modification.GenerationSettingsAccessor; -import net.fabricmc.fabric.mixin.biome.modification.SpawnSettingsAccessor; -import net.minecraft.client.Minecraft; -import net.minecraft.core.Registry; -import net.minecraft.data.BuiltinRegistries; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.random.WeightedRandomList; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.Mob; -import net.minecraft.world.entity.MobCategory; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.Biome.ClimateParameters; -import net.minecraft.world.level.biome.BiomeSource; -import net.minecraft.world.level.biome.Biomes; -import net.minecraft.world.level.biome.MobSpawnSettings.SpawnerData; -import net.minecraft.world.level.levelgen.GenerationStep.Decoration; -import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; -import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; -import org.jetbrains.annotations.Nullable; -import ru.bclib.util.MHelper; -import ru.bclib.world.biomes.BCLBiome; -import ru.bclib.world.biomes.FabricBiomesData; -import ru.bclib.world.features.BCLFeature; -import ru.bclib.world.generator.BiomePicker; -import ru.bclib.world.structures.BCLStructureFeature; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.Supplier; - -public class BiomeAPI { - /** - * Empty biome used as default value if requested biome doesn't exist or linked. Shouldn't be registered anywhere to prevent bugs. - * Have {@code Biomes.THE_VOID} as the reference biome. - */ - public static final BCLBiome EMPTY_BIOME = new BCLBiome(Biomes.THE_VOID.location(), BuiltinRegistries.BIOME.get(Biomes.THE_VOID), 1, 0); - - public static final BiomePicker NETHER_BIOME_PICKER = new BiomePicker(); - public static final BiomePicker END_LAND_BIOME_PICKER = new BiomePicker(); - public static final BiomePicker END_VOID_BIOME_PICKER = new BiomePicker(); - - private static final Map ID_MAP = Maps.newHashMap(); - private static final Map CLIENT = Maps.newHashMap(); - private static Registry biomeRegistry; - - private static final Map>> MODIFICATIONS = Maps.newHashMap(); - private static final Set MODIFIED_BIOMES = Sets.newHashSet(); - - public static final BCLBiome NETHER_WASTES_BIOME = registerNetherBiome(getFromRegistry(Biomes.NETHER_WASTES)); - public static final BCLBiome CRIMSON_FOREST_BIOME = registerNetherBiome(getFromRegistry(Biomes.CRIMSON_FOREST)); - public static final BCLBiome WARPED_FOREST_BIOME = registerNetherBiome(getFromRegistry(Biomes.WARPED_FOREST)); - public static final BCLBiome SOUL_SAND_VALLEY_BIOME = registerNetherBiome(getFromRegistry(Biomes.SOUL_SAND_VALLEY)); - public static final BCLBiome BASALT_DELTAS_BIOME = registerNetherBiome(getFromRegistry(Biomes.BASALT_DELTAS)); - - public static final BCLBiome THE_END = registerEndLandBiome(getFromRegistry(Biomes.THE_END)); - public static final BCLBiome END_MIDLANDS = registerSubBiome(THE_END, getFromRegistry(Biomes.END_MIDLANDS), 0.5F); - public static final BCLBiome END_HIGHLANDS = registerSubBiome(THE_END, getFromRegistry(Biomes.END_HIGHLANDS), 0.5F); - - public static final BCLBiome END_BARRENS = registerEndVoidBiome(getFromRegistry(new ResourceLocation("end_barrens"))); - public static final BCLBiome SMALL_END_ISLANDS = registerEndVoidBiome(getFromRegistry(new ResourceLocation("small_end_islands"))); - - /** - * Initialize registry for current server. - * - * @param server - {@link MinecraftServer} - */ - public static void initRegistry(MinecraftServer server) { - biomeRegistry = server.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); - CLIENT.clear(); - } - - /** - * Register {@link BCLBiome} instance and its {@link Biome} if necessary. - * @param biome {@link BCLBiome} - * @return {@link BCLBiome} - */ - public static BCLBiome registerBiome(BCLBiome biome) { - if (BuiltinRegistries.BIOME.get(biome.getID()) == null) { - Registry.register(BuiltinRegistries.BIOME, biome.getID(), biome.getBiome()); - } - ID_MAP.put(biome.getID(), biome); - return biome; - } - - public static BCLBiome registerSubBiome(BCLBiome parent, BCLBiome subBiome) { - registerBiome(subBiome); - parent.addSubBiome(subBiome); - return subBiome; - } - - public static BCLBiome registerSubBiome(BCLBiome parent, Biome biome, float chance) { - ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome).get(); - BCLBiome subBiome = new BCLBiome(key.location(), biome, 1, chance); - return registerSubBiome(parent, subBiome); - } - - /** - * Register {@link BCLBiome} instance and its {@link Biome} if necessary. - * After that biome will be added to BCLib Nether Biome Generator and into Fabric Biome API. - * @param biome {@link BCLBiome} - * @return {@link BCLBiome} - */ - public static BCLBiome registerNetherBiome(BCLBiome biome) { - registerBiome(biome); - NETHER_BIOME_PICKER.addBiome(biome); - Random random = new Random(biome.getID().hashCode()); - ClimateParameters parameters = new ClimateParameters( - MHelper.randRange(-1.5F, 1.5F, random), - MHelper.randRange(-1.5F, 1.5F, random), - MHelper.randRange(-1.5F, 1.5F, random), - MHelper.randRange(-1.5F, 1.5F, random), - random.nextFloat() - ); - ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome.getBiome()).get(); - InternalBiomeData.addNetherBiome(key, parameters); - return biome; - } - - /** - * Register {@link BCLBiome} instance and its {@link Biome} if necessary. - * After that biome will be added to BCLib Nether Biome Generator and into Fabric Biome API. - * @param biome {@link BCLBiome} - * @return {@link BCLBiome} - */ - public static BCLBiome registerNetherBiome(Biome biome) { - ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome).get(); - BCLBiome bclBiome = new BCLBiome(key.location(), biome, 1, 1); - NETHER_BIOME_PICKER.addBiome(bclBiome); - registerBiome(bclBiome); - return bclBiome; - } - - /** - * Register {@link BCLBiome} instance and its {@link Biome} if necessary. - * After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a land biome (will generate only on islands). - * @param biome {@link BCLBiome} - * @return {@link BCLBiome} - */ - public static BCLBiome registerEndLandBiome(BCLBiome biome) { - registerBiome(biome); - END_LAND_BIOME_PICKER.addBiome(biome); - float weight = biome.getGenChance(); - ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome.getBiome()).get(); - InternalBiomeData.addEndBiomeReplacement(Biomes.END_HIGHLANDS, key, weight); - InternalBiomeData.addEndBiomeReplacement(Biomes.END_MIDLANDS, key, weight); - return biome; - } - - /** - * Register {@link BCLBiome} wrapper for {@link Biome}. - * After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a land biome (will generate only on islands). - * @param biome {@link BCLBiome} - * @return {@link BCLBiome} - */ - public static BCLBiome registerEndLandBiome(Biome biome) { - ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome).get(); - BCLBiome bclBiome = new BCLBiome(key.location(), biome, 1, 1); - END_LAND_BIOME_PICKER.addBiome(bclBiome); - registerBiome(bclBiome); - return bclBiome; - } - - /** - * Register {@link BCLBiome} wrapper for {@link Biome}. - * After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a land biome (will generate only on islands). - * @param biome {@link BCLBiome}; - * @param weight float generation chance. - * @return {@link BCLBiome} - */ - public static BCLBiome registerEndLandBiome(Biome biome, float weight) { - ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome).get(); - BCLBiome bclBiome = new BCLBiome(key.location(), biome, 1, weight); - END_LAND_BIOME_PICKER.addBiome(bclBiome); - registerBiome(bclBiome); - return bclBiome; - } - - /** - * Register {@link BCLBiome} instance and its {@link Biome} if necessary. - * After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a void biome (will generate only in the End void - between islands). - * @param biome {@link BCLBiome} - * @return {@link BCLBiome} - */ - public static BCLBiome registerEndVoidBiome(BCLBiome biome) { - registerBiome(biome); - END_VOID_BIOME_PICKER.addBiome(biome); - float weight = biome.getGenChance(); - ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome.getBiome()).get(); - InternalBiomeData.addEndBiomeReplacement(Biomes.SMALL_END_ISLANDS, key, weight); - return biome; - } - - /** - * Register {@link BCLBiome} instance and its {@link Biome} if necessary. - * After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a void biome (will generate only in the End void - between islands). - * @param biome {@link BCLBiome} - * @return {@link BCLBiome} - */ - public static BCLBiome registerEndVoidBiome(Biome biome) { - ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome).get(); - BCLBiome bclBiome = new BCLBiome(key.location(), biome, 1, 1); - END_VOID_BIOME_PICKER.addBiome(bclBiome); - registerBiome(bclBiome); - return bclBiome; - } - - /** - * Register {@link BCLBiome} instance and its {@link Biome} if necessary. - * After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a void biome (will generate only in the End void - between islands). - * @param biome {@link BCLBiome}; - * @param weight float generation chance. - * @return {@link BCLBiome} - */ - public static BCLBiome registerEndVoidBiome(Biome biome, float weight) { - ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome).get(); - BCLBiome bclBiome = new BCLBiome(key.location(), biome, 1, weight); - END_VOID_BIOME_PICKER.addBiome(bclBiome); - registerBiome(bclBiome); - return bclBiome; - } - - /** - * Get {@link BCLBiome} from {@link Biome} instance on server. Used to convert world biomes to BCLBiomes. - * - * @param biome - {@link Biome} from world. - * @return {@link BCLBiome} or {@code BiomeAPI.EMPTY_BIOME}. - */ - public static BCLBiome getFromBiome(Biome biome) { - if (biomeRegistry == null) { - return EMPTY_BIOME; - } - return ID_MAP.getOrDefault(biomeRegistry.getKey(biome), EMPTY_BIOME); - } - - /** - * Get {@link BCLBiome} from biome on client. Used in fog rendering. - * - * @param biome - {@link Biome} from client world. - * @return {@link BCLBiome} or {@code BiomeAPI.EMPTY_BIOME}. - */ - @Environment(EnvType.CLIENT) - public static BCLBiome getRenderBiome(Biome biome) { - BCLBiome endBiome = CLIENT.get(biome); - if (endBiome == null) { - Minecraft minecraft = Minecraft.getInstance(); - ResourceLocation id = minecraft.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY).getKey(biome); - endBiome = id == null ? EMPTY_BIOME : ID_MAP.getOrDefault(id, EMPTY_BIOME); - CLIENT.put(biome, endBiome); - } - return endBiome; - } - - /** - * Get biome {@link ResourceLocation} from given {@link Biome}. - * - * @param biome - {@link Biome} from server world. - * @return biome {@link ResourceLocation}. - */ - public static ResourceLocation getBiomeID(Biome biome) { - ResourceLocation id = biomeRegistry.getKey(biome); - return id == null ? EMPTY_BIOME.getID() : id; - } - - /** - * Get {@link BCLBiome} from given {@link ResourceLocation}. - * - * @param biomeID - biome {@link ResourceLocation}. - * @return {@link BCLBiome} or {@code BiomeAPI.EMPTY_BIOME}. - */ - public static BCLBiome getBiome(ResourceLocation biomeID) { - return ID_MAP.getOrDefault(biomeID, EMPTY_BIOME); - } - - /** - * Check if biome with {@link ResourceLocation} exists in API registry. - * - * @param biomeID - biome {@link ResourceLocation}. - * @return {@code true} if biome exists in API registry and {@code false} if not. - */ - public static boolean hasBiome(ResourceLocation biomeID) { - return ID_MAP.containsKey(biomeID); - } - - /** - * Load biomes from Fabric API. For internal usage only. - */ - public static void loadFabricAPIBiomes() { - FabricBiomesData.NETHER_BIOMES.forEach((key) -> { - if (!hasBiome(key.location())) { - registerNetherBiome(BuiltinRegistries.BIOME.get(key.location())); - } - }); - - FabricBiomesData.END_LAND_BIOMES.forEach((key, weight) -> { - if (!hasBiome(key.location())) { - registerEndLandBiome(BuiltinRegistries.BIOME.get(key.location()), weight); - } - }); - - FabricBiomesData.END_VOID_BIOMES.forEach((key, weight) -> { - if (!hasBiome(key.location())) { - registerEndVoidBiome(BuiltinRegistries.BIOME.get(key.location()), weight); - } - }); - } - - @Nullable - public static Biome getFromRegistry(ResourceLocation key) { - return BuiltinRegistries.BIOME.get(key); - } - - @Nullable - public static Biome getFromRegistry(ResourceKey key) { - return BuiltinRegistries.BIOME.get(key); - } - - public static boolean isDatapackBiome(ResourceLocation biomeID) { - return getFromRegistry(biomeID) == null; - } - - public static boolean isNetherBiome(ResourceLocation biomeID) { - return pickerHasBiome(NETHER_BIOME_PICKER, biomeID); - } - - public static boolean isEndBiome(ResourceLocation biomeID) { - return pickerHasBiome(END_LAND_BIOME_PICKER, biomeID) || pickerHasBiome(END_VOID_BIOME_PICKER, biomeID); - } - - private static boolean pickerHasBiome(BiomePicker picker, ResourceLocation key) { - return picker.getBiomes().stream().filter(biome -> biome.getID().equals(key)).findFirst().isPresent(); - } - - /** - * Registers new biome modification for specified dimension. Will work both for mod and datapack biomes. - * @param dimensionID {@link ResourceLocation} dimension ID, example: Level.OVERWORLD or "minecraft:overworld". - * @param modification {@link BiConsumer} with {@link ResourceKey} biome ID and {@link Biome} parameters. - */ - public static void registerBiomeModification(ResourceKey dimensionID, BiConsumer modification) { - List> modifications = MODIFICATIONS.get(dimensionID); - if (modifications == null) { - modifications = Lists.newArrayList(); - MODIFICATIONS.put(dimensionID, modifications); - } - modifications.add(modification); - } - - /** - * Registers new biome modification for the Overworld. Will work both for mod and datapack biomes. - * @param modification {@link BiConsumer} with {@link ResourceLocation} biome ID and {@link Biome} parameters. - */ - public static void registerOverworldBiomeModification(BiConsumer modification) { - registerBiomeModification(Level.OVERWORLD, modification); - } - - /** - * Registers new biome modification for the Nether. Will work both for mod and datapack biomes. - * @param modification {@link BiConsumer} with {@link ResourceLocation} biome ID and {@link Biome} parameters. - */ - public static void registerNetherBiomeModification(BiConsumer modification) { - registerBiomeModification(Level.NETHER, modification); - } - - /** - * Registers new biome modification for the End. Will work both for mod and datapack biomes. - * @param modification {@link BiConsumer} with {@link ResourceLocation} biome ID and {@link Biome} parameters. - */ - public static void registerEndBiomeModification(BiConsumer modification) { - registerBiomeModification(Level.END, modification); - } - - /** - * Will apply biome modifications to world, internal usage only. - * @param level - */ - public static void applyModifications(ServerLevel level) { - List> modifications = MODIFICATIONS.get(level.dimension()); - if (modifications == null) { - return; - } - BiomeSource source = level.getChunkSource().getGenerator().getBiomeSource(); - List biomes = source.possibleBiomes(); - - biomes.forEach(biome -> { - ResourceLocation biomeID = getBiomeID(biome); - boolean modify = isDatapackBiome(biomeID); - if (biome != BuiltinRegistries.BIOME.get(biomeID)) { - modify = true; - } - else if (!modify && !MODIFIED_BIOMES.contains(biomeID)) { - MODIFIED_BIOMES.add(biomeID); - modify = true; - } - if (modify) { - modifications.forEach(consumer -> { - consumer.accept(biomeID, biome); - }); - } - }); - } - - /** - * Adds new features to existing biome. - * @param biome {@link Biome} to add features in. - * @param feature {@link ConfiguredFeature} to add. - * @param step a {@link Decoration} step for the feature. - */ - public static void addBiomeFeature(Biome biome, ConfiguredFeature feature, Decoration step) { - GenerationSettingsAccessor accessor = (GenerationSettingsAccessor) biome.getGenerationSettings(); - List>>> biomeFeatures = getMutableList(accessor.fabric_getFeatures()); - List>> list = getList(step, biomeFeatures); - list.add(() -> feature); - accessor.fabric_setFeatures(biomeFeatures); - } - - /** - * Adds new features to existing biome. - * @param biome {@link Biome} to add features in. - * @param features array of {@link BCLFeature} to add. - */ - public static void addBiomeFeatures(Biome biome, BCLFeature... features) { - GenerationSettingsAccessor accessor = (GenerationSettingsAccessor) biome.getGenerationSettings(); - List>>> biomeFeatures = getMutableList(accessor.fabric_getFeatures()); - for (BCLFeature feature: features) { - List>> list = getList(feature.getFeatureStep(), biomeFeatures); - list.add(feature::getFeatureConfigured); - } - accessor.fabric_setFeatures(biomeFeatures); - } - - /** - * Getter for correct feature list from all biome feature list of lists. - * @param step feature {@link Decoration} step. - * @param lists biome accessor lists. - * @return mutable {@link ConfiguredFeature} list. - */ - private static List>> getList(Decoration step, List>>> lists) { - int index = step.ordinal(); - if (lists.size() <= index) { - for (int i = lists.size(); i <= index; i++) { - lists.add(Lists.newArrayList()); - } - } - List>> list = getMutableList(lists.get(index)); - lists.set(index, list); - return list; - } - - /** - * Adds new structure feature to existing biome. - * @param biome {@link Biome} to add structure feature in. - * @param structure {@link ConfiguredStructureFeature} to add. - */ - public static void addBiomeStructure(Biome biome, ConfiguredStructureFeature structure) { - GenerationSettingsAccessor accessor = (GenerationSettingsAccessor) biome.getGenerationSettings(); - List>> biomeStructures = getMutableList(accessor.fabric_getStructureFeatures()); - biomeStructures.add(() -> structure); - accessor.fabric_setStructureFeatures(biomeStructures); - } - - /** - * Adds new structure features to existing biome. - * @param biome {@link Biome} to add structure features in. - * @param structures array of {@link BCLStructureFeature} to add. - */ - public static void addBiomeStructures(Biome biome, BCLStructureFeature... structures) { - GenerationSettingsAccessor accessor = (GenerationSettingsAccessor) biome.getGenerationSettings(); - List>> biomeStructures = getMutableList(accessor.fabric_getStructureFeatures()); - for (BCLStructureFeature structure: structures) { - biomeStructures.add(structure::getFeatureConfigured); - } - accessor.fabric_setStructureFeatures(biomeStructures); - } - - /** - * Adds mob spawning to specified biome. - * @param biome {@link Biome} to add mob spawning. - * @param entityType {@link EntityType} mob type. - * @param weight spawn weight. - * @param minGroupCount minimum mobs in group. - * @param maxGroupCount maximum mobs in group. - */ - public static void addBiomeMobSpawn(Biome biome, EntityType entityType, int weight, int minGroupCount, int maxGroupCount) { - MobCategory category = entityType.getCategory(); - SpawnSettingsAccessor accessor = (SpawnSettingsAccessor) biome.getMobSettings(); - Map> spawners = getMutableMap(accessor.fabric_getSpawners()); - List mobs = spawners.containsKey(category) ? getMutableList(spawners.get(category).unwrap()) : Lists.newArrayList(); - mobs.add(new SpawnerData(entityType, weight, minGroupCount, maxGroupCount)); - spawners.put(category, WeightedRandomList.create(mobs)); - accessor.fabric_setSpawners(spawners); - } - - private static List getMutableList(List input) { - if (input!=null) { - System.out.println("getMutableList: " + input.getClass().getName()); - for (Class cl : input.getClass().getInterfaces()){ - System.out.println(" - " + cl.getName()); - } - } - if (/*input instanceof ImmutableList ||*/ !(input instanceof ArrayList || input instanceof LinkedList)) { - return Lists.newArrayList(input); - } - return input; - } - - private static Map getMutableMap(Map input) { - if (input instanceof ImmutableMap) { - return Maps.newHashMap(input); - } - return input; - } -} +package ru.bclib.api.biomes; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.impl.biome.NetherBiomeData; +import net.fabricmc.fabric.impl.biome.TheEndBiomeData; +import net.minecraft.client.Minecraft; +import net.minecraft.core.Registry; +import net.minecraft.data.BuiltinRegistries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.biome.Climate; +import net.minecraft.world.level.biome.MobSpawnSettings.SpawnerData; +import net.minecraft.world.level.levelgen.GenerationStep.Carving; +import net.minecraft.world.level.levelgen.GenerationStep.Decoration; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.levelgen.SurfaceRules; +import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; +import net.minecraft.world.level.levelgen.feature.StructureFeature; +import net.minecraft.world.level.levelgen.placement.PlacedFeature; +import org.jetbrains.annotations.Nullable; +import ru.bclib.BCLib; +import ru.bclib.config.Configs; +import ru.bclib.interfaces.SurfaceRuleProvider; +import ru.bclib.mixin.common.BiomeGenerationSettingsAccessor; +import ru.bclib.mixin.common.MobSpawnSettingsAccessor; +import ru.bclib.mixin.common.StructureSettingsAccessor; +import ru.bclib.util.CollectionsUtil; +import ru.bclib.util.MHelper; +import ru.bclib.world.biomes.BCLBiome; +import ru.bclib.world.biomes.FabricBiomesData; +import ru.bclib.world.features.BCLFeature; +import ru.bclib.world.generator.BiomePicker; +import ru.bclib.world.structures.BCLStructureFeature; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public class BiomeAPI { + /** + * Empty biome used as default value if requested biome doesn't exist or linked. Shouldn't be registered anywhere to prevent bugs. + * Have {@code Biomes.THE_VOID} as the reference biome. + */ + public static final BCLBiome EMPTY_BIOME = new BCLBiome(Biomes.THE_VOID.location()); + + public static final BiomePicker NETHER_BIOME_PICKER = new BiomePicker(); + public static final BiomePicker END_LAND_BIOME_PICKER = new BiomePicker(); + public static final BiomePicker END_VOID_BIOME_PICKER = new BiomePicker(); + + private static final Map ID_MAP = Maps.newHashMap(); + private static final Map CLIENT = Maps.newHashMap(); + private static Registry biomeRegistry; + + private static final Map>> MODIFICATIONS = Maps.newHashMap(); + private static final Map SURFACE_RULES = Maps.newHashMap(); + private static final Set MODIFIED_BIOMES = Sets.newHashSet(); + + public static final BCLBiome NETHER_WASTES_BIOME = registerNetherBiome(getFromRegistry(Biomes.NETHER_WASTES)); + public static final BCLBiome CRIMSON_FOREST_BIOME = registerNetherBiome(getFromRegistry(Biomes.CRIMSON_FOREST)); + public static final BCLBiome WARPED_FOREST_BIOME = registerNetherBiome(getFromRegistry(Biomes.WARPED_FOREST)); + public static final BCLBiome SOUL_SAND_VALLEY_BIOME = registerNetherBiome(getFromRegistry(Biomes.SOUL_SAND_VALLEY)); + public static final BCLBiome BASALT_DELTAS_BIOME = registerNetherBiome(getFromRegistry(Biomes.BASALT_DELTAS)); + + public static final BCLBiome THE_END = registerEndLandBiome(getFromRegistry(Biomes.THE_END)); + public static final BCLBiome END_MIDLANDS = registerSubBiome(THE_END, getFromRegistry(Biomes.END_MIDLANDS), 0.5F); + public static final BCLBiome END_HIGHLANDS = registerSubBiome(THE_END, getFromRegistry(Biomes.END_HIGHLANDS), 0.5F); + + public static final BCLBiome END_BARRENS = registerEndVoidBiome(getFromRegistry(new ResourceLocation("end_barrens"))); + public static final BCLBiome SMALL_END_ISLANDS = registerEndVoidBiome(getFromRegistry(new ResourceLocation("small_end_islands"))); + + /** + * Initialize registry for current server. + * @param biomeRegistry - {@link Registry} for {@link Biome}. + */ + public static void initRegistry(Registry biomeRegistry) { + BiomeAPI.biomeRegistry = biomeRegistry; + CLIENT.clear(); + } + + /** + * Register {@link BCLBiome} instance and its {@link Biome} if necessary. + * @param biome {@link BCLBiome} + * @return {@link BCLBiome} + */ + public static BCLBiome registerBiome(BCLBiome biome) { + if (BuiltinRegistries.BIOME.get(biome.getID()) == null) { + Registry.register(BuiltinRegistries.BIOME, biome.getID(), biome.getBiome()); + } + ID_MAP.put(biome.getID(), biome); + return biome; + } + + public static BCLBiome registerSubBiome(BCLBiome parent, BCLBiome subBiome) { + registerBiome(subBiome); + parent.addSubBiome(subBiome); + return subBiome; + } + + public static BCLBiome registerSubBiome(BCLBiome parent, Biome biome, float genChance) { + BCLBiome subBiome = new BCLBiome(biome).setGenChance(genChance); + return registerSubBiome(parent, subBiome); + } + + /** + * Register {@link BCLBiome} instance and its {@link Biome} if necessary. + * After that biome will be added to BCLib Nether Biome Generator and into Fabric Biome API. + * @param biome {@link BCLBiome} + * @return {@link BCLBiome} + */ + public static BCLBiome registerNetherBiome(BCLBiome biome) { + registerBiome(biome); + NETHER_BIOME_PICKER.addBiome(biome); + Random random = new Random(biome.getID().hashCode()); + + //TODO: 1.18 Check parameters, depth was previously called altitude + //temperature, humidity, continentalness, erosion, depth, weirdness, offset + Climate.ParameterPoint parameters = Climate.parameters( + MHelper.randRange(-1.5F, 1.5F, random), + MHelper.randRange(-1.5F, 1.5F, random), + MHelper.randRange(-1.5F, 1.5F, random), //new in 1.18 + MHelper.randRange(-1.5F, 1.5F, random), //new in 1.18 + MHelper.randRange(-1.5F, 1.5F, random), + MHelper.randRange(-1.5F, 1.5F, random), + random.nextFloat() + ); + ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome.getBiome()).get(); + NetherBiomeData.addNetherBiome(key, parameters); + return biome; + } + + /** + * Register {@link BCLBiome} instance and its {@link Biome} if necessary. + * After that biome will be added to BCLib Nether Biome Generator and into Fabric Biome API. + * @param biome {@link BCLBiome} + * @return {@link BCLBiome} + */ + public static BCLBiome registerNetherBiome(Biome biome) { + BCLBiome bclBiome = new BCLBiome(biome); + configureBiome(bclBiome, 1.0F, 1.0F); + NETHER_BIOME_PICKER.addBiome(bclBiome); + registerBiome(bclBiome); + return bclBiome; + } + + /** + * Register {@link BCLBiome} instance and its {@link Biome} if necessary. + * After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a land biome (will generate only on islands). + * @param biome {@link BCLBiome} + * @return {@link BCLBiome} + */ + public static BCLBiome registerEndLandBiome(BCLBiome biome) { + registerBiome(biome); + configureBiome(biome, 1.0F, 1.0F); + END_LAND_BIOME_PICKER.addBiome(biome); + float weight = biome.getGenChance(); + ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome.getBiome()).get(); + TheEndBiomeData.addEndBiomeReplacement(Biomes.END_HIGHLANDS, key, weight); + TheEndBiomeData.addEndBiomeReplacement(Biomes.END_MIDLANDS, key, weight); + return biome; + } + + /** + * Register {@link BCLBiome} wrapper for {@link Biome}. + * After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a land biome (will generate only on islands). + * @param biome {@link BCLBiome} + * @return {@link BCLBiome} + */ + public static BCLBiome registerEndLandBiome(Biome biome) { + BCLBiome bclBiome = new BCLBiome(biome); + configureBiome(bclBiome, 1.0F, 1.0F); + END_LAND_BIOME_PICKER.addBiome(bclBiome); + registerBiome(bclBiome); + return bclBiome; + } + + /** + * Register {@link BCLBiome} wrapper for {@link Biome}. + * After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a land biome (will generate only on islands). + * @param biome {@link BCLBiome}; + * @param genChance float generation chance. + * @return {@link BCLBiome} + */ + public static BCLBiome registerEndLandBiome(Biome biome, float genChance) { + BCLBiome bclBiome = new BCLBiome(biome); + configureBiome(bclBiome, genChance, 1.0F); + END_LAND_BIOME_PICKER.addBiome(bclBiome); + registerBiome(bclBiome); + return bclBiome; + } + + /** + * Register {@link BCLBiome} instance and its {@link Biome} if necessary. + * After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a void biome (will generate only in the End void - between islands). + * @param biome {@link BCLBiome} + * @return {@link BCLBiome} + */ + public static BCLBiome registerEndVoidBiome(BCLBiome biome) { + registerBiome(biome); + configureBiome(biome, 1.0F, 1.0F); + END_VOID_BIOME_PICKER.addBiome(biome); + float weight = biome.getGenChance(); + ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome.getBiome()).get(); + TheEndBiomeData.addEndBiomeReplacement(Biomes.SMALL_END_ISLANDS, key, weight); + return biome; + } + + /** + * Register {@link BCLBiome} instance and its {@link Biome} if necessary. + * After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a void biome (will generate only in the End void - between islands). + * @param biome {@link BCLBiome} + * @return {@link BCLBiome} + */ + public static BCLBiome registerEndVoidBiome(Biome biome) { + BCLBiome bclBiome = new BCLBiome(biome); + configureBiome(bclBiome, 1.0F, 1.0F); + END_VOID_BIOME_PICKER.addBiome(bclBiome); + registerBiome(bclBiome); + return bclBiome; + } + + /** + * Register {@link BCLBiome} instance and its {@link Biome} if necessary. + * After that biome will be added to BCLib End Biome Generator and into Fabric Biome API as a void biome (will generate only in the End void - between islands). + * @param biome {@link BCLBiome}. + * @param genChance float generation chance. + * @return {@link BCLBiome} + */ + public static BCLBiome registerEndVoidBiome(Biome biome, float genChance) { + ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome).get(); + BCLBiome bclBiome = new BCLBiome(biome); + configureBiome(bclBiome, genChance, 1.0F); + END_VOID_BIOME_PICKER.addBiome(bclBiome); + registerBiome(bclBiome); + return bclBiome; + } + + /** + * Get {@link BCLBiome} from {@link Biome} instance on server. Used to convert world biomes to BCLBiomes. + * @param biome - {@link Biome} from world. + * @return {@link BCLBiome} or {@code BiomeAPI.EMPTY_BIOME}. + */ + public static BCLBiome getFromBiome(Biome biome) { + if (biomeRegistry == null) { + return EMPTY_BIOME; + } + return ID_MAP.getOrDefault(biomeRegistry.getKey(biome), EMPTY_BIOME); + } + + /** + * Get {@link BCLBiome} from biome on client. Used in fog rendering. + * @param biome - {@link Biome} from client world. + * @return {@link BCLBiome} or {@code BiomeAPI.EMPTY_BIOME}. + */ + @Environment(EnvType.CLIENT) + public static BCLBiome getRenderBiome(Biome biome) { + BCLBiome endBiome = CLIENT.get(biome); + if (endBiome == null) { + Minecraft minecraft = Minecraft.getInstance(); + ResourceLocation id = minecraft.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY).getKey(biome); + endBiome = id == null ? EMPTY_BIOME : ID_MAP.getOrDefault(id, EMPTY_BIOME); + CLIENT.put(biome, endBiome); + } + return endBiome; + } + + /** + * Get biome {@link ResourceKey} from given {@link Biome}. + * @param biome - {@link Biome} from server world. + * @return biome {@link ResourceKey} or {@code null}. + */ + @Nullable + public static ResourceKey getBiomeKey(Biome biome) { + ResourceKey key = BuiltinRegistries.BIOME.getResourceKey(biome).orElse(null); + return key != null ? key : biomeRegistry != null ? biomeRegistry.getResourceKey(biome).orElse(null) : null; + } + + /** + * Get biome {@link ResourceLocation} from given {@link Biome}. + * @param biome - {@link Biome} from server world. + * @return biome {@link ResourceLocation}. + */ + public static ResourceLocation getBiomeID(Biome biome) { + ResourceLocation id = BuiltinRegistries.BIOME.getKey(biome); + if (id == null && biomeRegistry != null) { + id = biomeRegistry.getKey(biome); + } + return id == null ? EMPTY_BIOME.getID() : id; + } + + /** + * Get {@link BCLBiome} from given {@link ResourceLocation}. + * @param biomeID - biome {@link ResourceLocation}. + * @return {@link BCLBiome} or {@code BiomeAPI.EMPTY_BIOME}. + */ + public static BCLBiome getBiome(ResourceLocation biomeID) { + return ID_MAP.getOrDefault(biomeID, EMPTY_BIOME); + } + + /** + * Check if biome with {@link ResourceLocation} exists in API registry. + * @param biomeID - biome {@link ResourceLocation}. + * @return {@code true} if biome exists in API registry and {@code false} if not. + */ + public static boolean hasBiome(ResourceLocation biomeID) { + return ID_MAP.containsKey(biomeID); + } + + /** + * Load biomes from Fabric API. For internal usage only. + */ + public static void loadFabricAPIBiomes() { + FabricBiomesData.NETHER_BIOMES.forEach((key) -> { + if (!hasBiome(key.location())) { + registerNetherBiome(BuiltinRegistries.BIOME.get(key.location())); + } + }); + + FabricBiomesData.END_LAND_BIOMES.forEach((key, weight) -> { + if (!hasBiome(key.location())) { + registerEndLandBiome(BuiltinRegistries.BIOME.get(key.location()), weight); + } + }); + + FabricBiomesData.END_VOID_BIOMES.forEach((key, weight) -> { + if (!hasBiome(key.location())) { + registerEndVoidBiome(BuiltinRegistries.BIOME.get(key.location()), weight); + } + }); + } + + @Nullable + public static Biome getFromRegistry(ResourceLocation key) { + return BuiltinRegistries.BIOME.get(key); + } + + @Nullable + public static Biome getFromRegistry(ResourceKey key) { + return BuiltinRegistries.BIOME.get(key); + } + + public static boolean isDatapackBiome(ResourceLocation biomeID) { + return getFromRegistry(biomeID) == null; + } + + public static boolean isNetherBiome(ResourceLocation biomeID) { + return pickerHasBiome(NETHER_BIOME_PICKER, biomeID); + } + + public static boolean isEndBiome(ResourceLocation biomeID) { + return pickerHasBiome(END_LAND_BIOME_PICKER, biomeID) || pickerHasBiome(END_VOID_BIOME_PICKER, biomeID); + } + + private static boolean pickerHasBiome(BiomePicker picker, ResourceLocation key) { + return picker.getBiomes().stream().filter(biome -> biome.getID().equals(key)).findFirst().isPresent(); + } + + /** + * Registers new biome modification for specified dimension. Will work both for mod and datapack biomes. + * @param dimensionID {@link ResourceLocation} dimension ID, example: Level.OVERWORLD or "minecraft:overworld". + * @param modification {@link BiConsumer} with {@link ResourceKey} biome ID and {@link Biome} parameters. + */ + public static void registerBiomeModification(ResourceKey dimensionID, BiConsumer modification) { + List> modifications = MODIFICATIONS.get(dimensionID); + if (modifications == null) { + modifications = Lists.newArrayList(); + MODIFICATIONS.put(dimensionID, modifications); + } + modifications.add(modification); + } + + /** + * Registers new biome modification for the Overworld. Will work both for mod and datapack biomes. + * @param modification {@link BiConsumer} with {@link ResourceLocation} biome ID and {@link Biome} parameters. + */ + public static void registerOverworldBiomeModification(BiConsumer modification) { + registerBiomeModification(Level.OVERWORLD, modification); + } + + /** + * Registers new biome modification for the Nether. Will work both for mod and datapack biomes. + * @param modification {@link BiConsumer} with {@link ResourceLocation} biome ID and {@link Biome} parameters. + */ + public static void registerNetherBiomeModification(BiConsumer modification) { + registerBiomeModification(Level.NETHER, modification); + } + + /** + * Registers new biome modification for the End. Will work both for mod and datapack biomes. + * @param modification {@link BiConsumer} with {@link ResourceLocation} biome ID and {@link Biome} parameters. + */ + public static void registerEndBiomeModification(BiConsumer modification) { + registerBiomeModification(Level.END, modification); + } + + /** + * Will apply biome modifications to world, internal usage only. + * @param level + */ + public static void applyModifications(ServerLevel level) { + BiomeSource source = level.getChunkSource().getGenerator().getBiomeSource(); + Set biomes = source.possibleBiomes(); + + NoiseGeneratorSettings generator = null; + if (level.dimension() == Level.NETHER) { + generator = BuiltinRegistries.NOISE_GENERATOR_SETTINGS.get(NoiseGeneratorSettings.NETHER); + } + else if (level.dimension() == Level.END) { + generator = BuiltinRegistries.NOISE_GENERATOR_SETTINGS.get(NoiseGeneratorSettings.END); + } + + if (generator != null) { + List rules = getRuleSources(biomes, level.dimension()); + SurfaceRuleProvider provider = SurfaceRuleProvider.class.cast(generator); + if (rules.size() > 0) { + rules.add(provider.getSurfaceRule()); + provider.setSurfaceRule(SurfaceRules.sequence(rules.toArray(new SurfaceRules.RuleSource[rules.size()]))); + } + else { + provider.setSurfaceRule(null); + } + } + + List> modifications = MODIFICATIONS.get(level.dimension()); + if (modifications == null) { + return; + } + + biomes.forEach(biome -> { + ResourceLocation biomeID = getBiomeID(biome); + boolean modify = isDatapackBiome(biomeID); + if (biome != BuiltinRegistries.BIOME.get(biomeID)) { + modify = true; + } + else if (!modify && !MODIFIED_BIOMES.contains(biomeID)) { + MODIFIED_BIOMES.add(biomeID); + modify = true; + } + if (modify) { + modifications.forEach(consumer -> { + consumer.accept(biomeID, biome); + }); + } + }); + } + + private static List getRuleSources(Set biomes, ResourceKey dimensionType) { + Set biomeIDs = biomes.stream().map(biome -> getBiomeID(biome)).collect(Collectors.toSet()); + List rules = Lists.newArrayList(); + SURFACE_RULES.forEach((biomeID, rule) -> { + if (biomeIDs.contains(biomeID)) { + rules.add(rule); + } + }); + + // Try handle biomes from other dimension, may work not as expected + // Will not work + /*Optional optional = biomes + .stream() + .filter(biome -> biome.getBiomeCategory() != BiomeCategory.THEEND && biome.getBiomeCategory() != BiomeCategory.NETHER) + .findAny(); + if (optional.isPresent()) { + rules.add(SurfaceRuleData.overworld()); + } + + if (dimensionType == Level.NETHER) { + optional = biomes.stream().filter(biome -> biome.getBiomeCategory() != BiomeCategory.THEEND).findAny(); + if (optional.isPresent()) { + rules.add(SurfaceRuleData.end()); + } + } + else if (dimensionType == Level.END) { + optional = biomes.stream().filter(biome -> biome.getBiomeCategory() != BiomeCategory.NETHER).findAny(); + if (optional.isPresent()) { + rules.add(SurfaceRuleData.end()); + } + }*/ + + return rules; + } + + /** + * Adds new features to existing biome. + * @param biome {@link Biome} to add features in. + * @param feature {@link ConfiguredFeature} to add. + * + */ + public static void addBiomeFeature(Biome biome, BCLFeature feature) { + addBiomeFeature(biome, feature.getPlacedFeature(), feature.getDecoration()); + } + + /** + * Adds new features to existing biome. + * @param biome {@link Biome} to add features in. + * @param feature {@link ConfiguredFeature} to add. + * @param step a {@link Decoration} step for the feature. + */ + public static void addBiomeFeature(Biome biome, PlacedFeature feature, Decoration step) { + BiomeGenerationSettingsAccessor accessor = (BiomeGenerationSettingsAccessor) biome.getGenerationSettings(); + List>> allFeatures = CollectionsUtil.getMutable(accessor.bclib_getFeatures()); + Set set = CollectionsUtil.getMutable(accessor.bclib_getFeatureSet()); + List> features = getFeaturesList(allFeatures, step); + features.add(() -> feature); + set.add(feature); + accessor.bclib_setFeatures(allFeatures); + accessor.bclib_setFeatureSet(set); + } + + /** + * Adds new features to existing biome. + * @param biomeID {@link ResourceLocation} of the {@link Biome} to add features in. + * @param feature {@link ConfiguredFeature} to add. + * @param step a {@link Decoration} step for the feature. + */ + private static void addBiomeFeature(ResourceLocation biomeID, PlacedFeature feature, Decoration step) { + addBiomeFeature(BuiltinRegistries.BIOME.get(biomeID), feature, step); + } + + /** + * Adds new features to existing biome. + * @param biome {@link Biome} to add features in. + * @param features array of {@link BCLFeature} to add. + */ + public static void addBiomeFeatures(Biome biome, BCLFeature... features) { + BiomeGenerationSettingsAccessor accessor = (BiomeGenerationSettingsAccessor) biome.getGenerationSettings(); + List>> allFeatures = CollectionsUtil.getMutable(accessor.bclib_getFeatures()); + Set set = CollectionsUtil.getMutable(accessor.bclib_getFeatureSet()); + for (BCLFeature feature: features) { + List> featureList = getFeaturesList(allFeatures, feature.getDecoration()); + featureList.add(() -> feature.getPlacedFeature()); + set.add(feature.getPlacedFeature()); + } + accessor.bclib_setFeatures(allFeatures); + accessor.bclib_setFeatureSet(set); + } + + /** + * Adds new structure feature to existing biome. + * @param biomeKey {@link ResourceKey} for the {@link Biome} to add structure feature in. + * @param structure {@link ConfiguredStructureFeature} to add. + */ + public static void addBiomeStructure(ResourceKey biomeKey, ConfiguredStructureFeature structure) { + changeStructureStarts(structureMap -> { + Multimap, ResourceKey> configuredMap = structureMap.computeIfAbsent(structure.feature, k -> HashMultimap.create()); + + configuredMap.put(structure, biomeKey); + }); + } + + public static void addBiomeStructure(Biome biome, ConfiguredStructureFeature structure) { + changeStructureStarts(structureMap -> { + Multimap, ResourceKey> configuredMap = structureMap.computeIfAbsent(structure.feature, k -> HashMultimap.create()); + var key = getBiomeKey(biome); + if (key!=null) { + configuredMap.put(structure, key); + } else { + BCLib.LOGGER.error("Unable to find Biome " + getBiomeID(biome)); + } + }); + } + + private static void changeStructureStarts(Consumer, Multimap, ResourceKey>>> modifier) { + Registry chunkGenSettingsRegistry = BuiltinRegistries.NOISE_GENERATOR_SETTINGS; + + for (Map.Entry, NoiseGeneratorSettings> entry : chunkGenSettingsRegistry.entrySet()) { + Map, Multimap, ResourceKey>> structureMap = getMutableStructureConfig(entry.getValue()); + + modifier.accept(structureMap); + setMutableStructureConfig(entry.getValue(), structureMap); + } + } + + /** + * Adds new structure feature to existing biome. + * @param biomeKey {@link ResourceKey} for the {@link Biome} to add structure feature in. + * @param structure {@link BCLStructureFeature} to add. + */ + public static void addBiomeStructure(ResourceKey biomeKey, BCLStructureFeature structure) { + addBiomeStructure(biomeKey, structure.getFeatureConfigured()); + } + + /** + * Adds new structure features to existing biome. + * @param biomeKey {@link ResourceKey} for the {@link Biome} to add structure features in. + * @param structures array of {@link BCLStructureFeature} to add. + */ + public static void addBiomeStructures(ResourceKey biomeKey, BCLStructureFeature... structures) { + for (BCLStructureFeature structure: structures) { + addBiomeStructure(biomeKey, structure.getFeatureConfigured()); + } + } + + /** + * Adds new carver into existing biome. + * @param biome {@link Biome} to add carver in. + * @param carver {@link ConfiguredWorldCarver} to add. + * @param stage {@link Carving} stage. + */ + public static void addBiomeCarver(Biome biome, ConfiguredWorldCarver carver, Carving stage) { + BiomeGenerationSettingsAccessor accessor = (BiomeGenerationSettingsAccessor) biome.getGenerationSettings(); + Map>>> carvers = CollectionsUtil.getMutable(accessor.bclib_getCarvers()); + List>> carverList = CollectionsUtil.getMutable(carvers.getOrDefault(stage, new ArrayList<>())); + carvers.put(stage, carverList); + carverList.add(() -> carver); + accessor.bclib_setCarvers(carvers); + } + + /** + * Adds surface rule to specified biome. + * @param biomeID biome {@link ResourceLocation}. + * @param source {@link SurfaceRules.RuleSource}. + */ + public static void addSurfaceRule(ResourceLocation biomeID, SurfaceRules.RuleSource source) { + SURFACE_RULES.put(biomeID, source); + } + + /** + * Get surface rule for the biome using its {@link ResourceLocation} ID as a key. + * @param biomeID {@link ResourceLocation} biome ID. + * @return {@link SurfaceRules.RuleSource}. + */ + @Nullable + public static SurfaceRules.RuleSource getSurfaceRule(ResourceLocation biomeID) { + return SURFACE_RULES.get(biomeID); + } + + /** + * Adds mob spawning to specified biome. + * @param biome {@link Biome} to add mob spawning. + * @param entityType {@link EntityType} mob type. + * @param weight spawn weight. + * @param minGroupCount minimum mobs in group. + * @param maxGroupCount maximum mobs in group. + */ + public static void addBiomeMobSpawn(Biome biome, EntityType entityType, int weight, int minGroupCount, int maxGroupCount) { + final MobCategory category = entityType.getCategory(); + MobSpawnSettingsAccessor accessor = (MobSpawnSettingsAccessor) biome.getMobSettings(); + Map> spawners = CollectionsUtil.getMutable(accessor.bcl_getSpawners()); + List mobs = spawners.containsKey(category) ? CollectionsUtil.getMutable(spawners.get(category).unwrap()) : Lists.newArrayList(); + mobs.add(new SpawnerData(entityType, weight, minGroupCount, maxGroupCount)); + spawners.put(category, WeightedRandomList.create(mobs)); + accessor.bcl_setSpawners(spawners); + } + + private static void configureBiome(BCLBiome biome, float chance, float fog) { + String group = biome.getID().getNamespace() + "." + biome.getID().getPath(); + chance = Configs.BIOMES_CONFIG.getFloat(group, "generation_chance", chance); + fog = Configs.BIOMES_CONFIG.getFloat(group, "fog_density", fog); + biome.setGenChance(chance).setFogDensity(fog); + } + + /** + * Getter for correct feature list from all biome feature list of lists. + * @param step feature {@link Decoration} step. + * @param lists biome accessor lists. + * @return mutable {@link ConfiguredFeature} list. + */ + private static List> getList(Decoration step, List>> lists) { + int index = step.ordinal(); + if (lists.size() <= index) { + for (int i = lists.size(); i <= index; i++) { + lists.add(Lists.newArrayList()); + } + } + List> list = CollectionsUtil.getMutable(lists.get(index)); + lists.set(index, list); + return list; + } + + private static List> getFeaturesList(List>> features, Decoration step) { + int index = step.ordinal(); + while (features.size() <= index) { + features.add(Lists.newArrayList()); + } + List> mutable = CollectionsUtil.getMutable(features.get(index)); + features.set(index, mutable); + return mutable; + } + + //inspired by net.fabricmc.fabric.impl.biome.modification.BiomeStructureStartsImpl + private static Map, Multimap, ResourceKey>> getMutableStructureConfig(NoiseGeneratorSettings settings) { + final StructureSettingsAccessor access = (StructureSettingsAccessor)settings.structureSettings(); + ImmutableMap, ImmutableMultimap, ResourceKey>> immutableMap = access.bcl_getStructureConfig(); + Map, Multimap, ResourceKey>> result = new HashMap<>(immutableMap.size()); + + for (Map.Entry, ImmutableMultimap, ResourceKey>> entry : immutableMap.entrySet()) { + result.put(entry.getKey(), HashMultimap.create(entry.getValue())); + } + + return result; + } + + //inspired by net.fabricmc.fabric.impl.biome.modification.BiomeStructureStartsImpl + private static void setMutableStructureConfig(NoiseGeneratorSettings settings, Map, Multimap, ResourceKey>> structureStarts) { + final StructureSettingsAccessor access = (StructureSettingsAccessor) settings.structureSettings(); + access.bcl_setStructureConfig( + structureStarts + .entrySet() + .stream() + .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, e -> ImmutableMultimap.copyOf(e.getValue()))) + ); + } +} diff --git a/src/main/java/ru/bclib/api/biomes/SurfaceRuleBuilder.java b/src/main/java/ru/bclib/api/biomes/SurfaceRuleBuilder.java new file mode 100644 index 00000000..13082e90 --- /dev/null +++ b/src/main/java/ru/bclib/api/biomes/SurfaceRuleBuilder.java @@ -0,0 +1,190 @@ +package ru.bclib.api.biomes; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.SurfaceRules; +import net.minecraft.world.level.levelgen.SurfaceRules.RuleSource; +import net.minecraft.world.level.levelgen.placement.CaveSurface; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +public class SurfaceRuleBuilder { + private static final Map RULES_CACHE = Maps.newHashMap(); + private static final SurfaceRuleBuilder INSTANCE = new SurfaceRuleBuilder(); + private List rules = Lists.newArrayList(); + private SurfaceRuleEntry entryInstance; + private ResourceKey biomeKey; + + private SurfaceRuleBuilder() {} + + public static SurfaceRuleBuilder start() { + INSTANCE.biomeKey = null; + INSTANCE.rules.clear(); + return INSTANCE; + } + + /** + * Restricts surface to only one biome. + * @param biomeKey {@link ResourceKey} for the {@link Biome}. + * @return same {@link SurfaceRuleBuilder} instance. + */ + public SurfaceRuleBuilder biome(ResourceKey biomeKey) { + this.biomeKey = biomeKey; + return this; + } + + /** + * Restricts surface to only one biome. + * @param biome {@link Biome}. + * @return same {@link SurfaceRuleBuilder} instance. + */ + public SurfaceRuleBuilder biome(Biome biome) { + return biome(BiomeAPI.getBiomeKey(biome)); + } + + /** + * Set biome surface with specified {@link BlockState}. Example - block of grass in the Overworld biomes + * @param state {@link BlockState} for the ground cover. + * @return same {@link SurfaceRuleBuilder} instance. + */ + public SurfaceRuleBuilder surface(BlockState state) { + entryInstance = getFromCache("surface_" + state.toString(), () -> { + RuleSource rule = SurfaceRules.state(state); + rule = SurfaceRules.ifTrue(SurfaceRules.ON_FLOOR, rule); + return new SurfaceRuleEntry(2, rule); + }); + rules.add(entryInstance); + return this; + } + + /** + * Set biome subsurface with specified {@link BlockState}. Example - dirt in the Overworld biomes. + * @param state {@link BlockState} for the subterrain layer. + * @param depth block layer depth. + * @return same {@link SurfaceRuleBuilder} instance. + */ + public SurfaceRuleBuilder subsurface(BlockState state, int depth) { + entryInstance = getFromCache("subsurface_" + depth + "_" + state.toString(), () -> { + RuleSource rule = SurfaceRules.state(state); + rule = SurfaceRules.ifTrue(SurfaceRules.stoneDepthCheck(depth, false, false, CaveSurface.FLOOR), rule); + return new SurfaceRuleEntry(3, rule); + }); + rules.add(entryInstance); + return this; + } + + /** + * Set biome filler with specified {@link BlockState}. Example - stone in the Overworld biomes. + * @param state {@link BlockState} for filling. + * @return same {@link SurfaceRuleBuilder} instance. + */ + public SurfaceRuleBuilder filler(BlockState state) { + entryInstance = getFromCache("fill_" + state.toString(), () -> new SurfaceRuleEntry(3, SurfaceRules.state(state))); + rules.add(entryInstance); + return this; + } + + /** + * Set biome ceiling with specified {@link BlockState}. Example - block of sandstone in the Overworld desert in air pockets. + * @param state {@link BlockState} for the ground cover. + * @return same {@link SurfaceRuleBuilder} instance. + */ + public SurfaceRuleBuilder ceil(BlockState state) { + entryInstance = getFromCache("ceil_" + state.toString(), () -> { + RuleSource rule = SurfaceRules.state(state); + return new SurfaceRuleEntry(2, SurfaceRules.ifTrue(SurfaceRules.ON_CEILING, rule)); + }); + rules.add(entryInstance); + return this; + } + + /** + * Set biome ceiling material with specified {@link BlockState} and height. Example - sandstone in the Overworld deserts. + * @param state {@link BlockState} for the subterrain layer. + * @param height block layer height. + * @return same {@link SurfaceRuleBuilder} instance. + */ + public SurfaceRuleBuilder aboveCeil(BlockState state, int height) { + entryInstance = getFromCache("above_ceil_" + height + "_" + state.toString(), () -> { + RuleSource rule = SurfaceRules.state(state); + rule = SurfaceRules.ifTrue(SurfaceRules.stoneDepthCheck(height, false, false, CaveSurface.CEILING), rule); + return new SurfaceRuleEntry(3, rule); + }); + rules.add(entryInstance); + return this; + } + + /** + * Will cover steep areas (with large terrain angle). Example - Overworld mountains. + * @param state {@link BlockState} for the steep layer. + * @param depth layer depth + * @return + */ + public SurfaceRuleBuilder steep(BlockState state, int depth) { + entryInstance = getFromCache("steep_" + depth + "_" + state.toString(), () -> { + RuleSource rule = SurfaceRules.state(state); + rule = SurfaceRules.ifTrue(SurfaceRules.stoneDepthCheck(depth, false, false, CaveSurface.FLOOR), rule); + rule = SurfaceRules.ifTrue(SurfaceRules.steep(), rule); + int priority = depth < 1 ? 0 : 1; + return new SurfaceRuleEntry(priority, rule); + }); + rules.add(entryInstance); + return this; + } + + /** + * Allows to add custom rule. + * @param priority rule priority, lower values = higher priority (rule will be applied before others). + * @param rule custom {@link SurfaceRules.RuleSource}. + * @return same {@link SurfaceRuleBuilder} instance. + */ + public SurfaceRuleBuilder rule(int priority, SurfaceRules.RuleSource rule) { + rules.add(new SurfaceRuleEntry(priority, rule)); + return this; + } + + /** + * Allows to add custom rule. + * @param rule custom {@link SurfaceRules.RuleSource}. + * @return same {@link SurfaceRuleBuilder} instance. + */ + public SurfaceRuleBuilder rule(SurfaceRules.RuleSource rule) { + return rule(7, rule); + } + + /** + * Finalise rule building process. + * @return {@link SurfaceRules.RuleSource}. + */ + public SurfaceRules.RuleSource build() { + Collections.sort(rules); + List ruleList = rules.stream().map(entry -> entry.getRule()).toList(); + SurfaceRules.RuleSource[] ruleArray = ruleList.toArray(new SurfaceRules.RuleSource[ruleList.size()]); + SurfaceRules.RuleSource rule = SurfaceRules.sequence(ruleArray); + if (biomeKey != null) { + rule = SurfaceRules.ifTrue(SurfaceRules.isBiome(biomeKey), rule); + } + return rule; + } + + /** + * Internal function, will take entry from cache or create it if necessary. + * @param name {@link String} entry internal name. + * @param supplier {@link Supplier} for {@link SurfaceRuleEntry}. + * @return new or existing {@link SurfaceRuleEntry}. + */ + private static SurfaceRuleEntry getFromCache(String name, Supplier supplier) { + SurfaceRuleEntry entry = RULES_CACHE.get(name); + if (entry == null) { + entry = supplier.get(); + RULES_CACHE.put(name, entry); + } + return entry; + } +} diff --git a/src/main/java/ru/bclib/api/biomes/SurfaceRuleEntry.java b/src/main/java/ru/bclib/api/biomes/SurfaceRuleEntry.java new file mode 100644 index 00000000..348dbbfb --- /dev/null +++ b/src/main/java/ru/bclib/api/biomes/SurfaceRuleEntry.java @@ -0,0 +1,24 @@ +package ru.bclib.api.biomes; + +import net.minecraft.world.entity.Mob; +import net.minecraft.world.level.levelgen.SurfaceRules; +import org.jetbrains.annotations.NotNull; + +public class SurfaceRuleEntry implements Comparable { + private final SurfaceRules.RuleSource rule; + private final byte priority; + + public SurfaceRuleEntry(int priority, SurfaceRules.RuleSource rule) { + this.priority = (byte) priority; + this.rule = rule; + } + + protected SurfaceRules.RuleSource getRule() { + return rule; + } + + @Override + public int compareTo(@NotNull SurfaceRuleEntry entry) { + return Integer.compare(priority, entry.priority); + } +} diff --git a/src/main/java/ru/bclib/api/dataexchange/handler/autosync/Chunker.java b/src/main/java/ru/bclib/api/dataexchange/handler/autosync/Chunker.java index 33a16719..bc669f3b 100644 --- a/src/main/java/ru/bclib/api/dataexchange/handler/autosync/Chunker.java +++ b/src/main/java/ru/bclib/api/dataexchange/handler/autosync/Chunker.java @@ -189,7 +189,7 @@ public class Chunker extends DataHandler.FromServer { public static final int MAX_PACKET_SIZE = 1024*1024; private static final int MAX_PAYLOAD_SIZE = MAX_PACKET_SIZE - HEADER_SIZE; - public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "chunker"), Chunker::new, false, false); + public static final DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "chunker"), Chunker::new, false, false); private int serialNo; private UUID uuid; diff --git a/src/main/java/ru/bclib/api/dataexchange/handler/autosync/HelloClient.java b/src/main/java/ru/bclib/api/dataexchange/handler/autosync/HelloClient.java index 83762718..206735d4 100644 --- a/src/main/java/ru/bclib/api/dataexchange/handler/autosync/HelloClient.java +++ b/src/main/java/ru/bclib/api/dataexchange/handler/autosync/HelloClient.java @@ -48,7 +48,7 @@ public class HelloClient extends DataHandler.FromServer { public interface IServerModMap extends Map {} public static class ServerModMap extends HashMap implements IServerModMap {} - public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "hello_client"), HelloClient::new, false, false); + public static final DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "hello_client"), HelloClient::new, false, false); public HelloClient() { super(DESCRIPTOR.IDENTIFIER); diff --git a/src/main/java/ru/bclib/api/dataexchange/handler/autosync/HelloServer.java b/src/main/java/ru/bclib/api/dataexchange/handler/autosync/HelloServer.java index a3abd668..300f8ba6 100644 --- a/src/main/java/ru/bclib/api/dataexchange/handler/autosync/HelloServer.java +++ b/src/main/java/ru/bclib/api/dataexchange/handler/autosync/HelloServer.java @@ -57,7 +57,7 @@ import java.io.File; * */ public class HelloServer extends DataHandler.FromClient { - public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "hello_server"), HelloServer::new, true, false); + public static final DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "hello_server"), HelloServer::new, true, false); protected String bclibVersion = "0.0.0"; diff --git a/src/main/java/ru/bclib/api/dataexchange/handler/autosync/RequestFiles.java b/src/main/java/ru/bclib/api/dataexchange/handler/autosync/RequestFiles.java index 45579906..6e69dd8a 100644 --- a/src/main/java/ru/bclib/api/dataexchange/handler/autosync/RequestFiles.java +++ b/src/main/java/ru/bclib/api/dataexchange/handler/autosync/RequestFiles.java @@ -17,7 +17,7 @@ import java.util.UUID; import java.util.stream.Collectors; public class RequestFiles extends DataHandler.FromClient { - public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "request_files"), RequestFiles::new, false, false); + public static final DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "request_files"), RequestFiles::new, false, false); static String currentToken = ""; protected List files; diff --git a/src/main/java/ru/bclib/api/dataexchange/handler/autosync/SendFiles.java b/src/main/java/ru/bclib/api/dataexchange/handler/autosync/SendFiles.java index 000be5c0..2b3e419a 100644 --- a/src/main/java/ru/bclib/api/dataexchange/handler/autosync/SendFiles.java +++ b/src/main/java/ru/bclib/api/dataexchange/handler/autosync/SendFiles.java @@ -24,7 +24,7 @@ import java.util.List; import java.util.stream.Collectors; public class SendFiles extends DataHandler.FromServer { - public static DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "send_files"), SendFiles::new, false, false); + public static final DataHandlerDescriptor DESCRIPTOR = new DataHandlerDescriptor(new ResourceLocation(BCLib.MOD_ID, "send_files"), SendFiles::new, false, false); protected List files; private String token; diff --git a/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java b/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java index 1a832f6f..c6f23694 100644 --- a/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java +++ b/src/main/java/ru/bclib/api/datafixer/DataFixerAPI.java @@ -35,6 +35,7 @@ import java.io.DataOutputStream; import java.io.EOFException; import java.io.File; import java.io.IOException; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -459,9 +460,10 @@ public class DataFixerAPI { private static void fixRegion(MigrationProfile data, State state, File file) { try { - LOGGER.info("Inspecting " + file); + Path path = file.toPath(); + LOGGER.info("Inspecting " + path); boolean[] changed = new boolean[1]; - RegionFile region = new RegionFile(file, file.getParentFile(), true); + RegionFile region = new RegionFile(path, path.getParent(), true); for (int x = 0; x < 32; x++) { for (int z = 0; z < 32; z++) { diff --git a/src/main/java/ru/bclib/api/datafixer/Patch.java b/src/main/java/ru/bclib/api/datafixer/Patch.java index 30a26ce7..4fcb48be 100644 --- a/src/main/java/ru/bclib/api/datafixer/Patch.java +++ b/src/main/java/ru/bclib/api/datafixer/Patch.java @@ -13,8 +13,7 @@ import java.util.List; import java.util.Map; public abstract class Patch { - - private static List ALL = new ArrayList<>(10); + private static final List ALL = new ArrayList<>(10); /** * The Patch-Level derived from {@link #version} @@ -50,12 +49,7 @@ public abstract class Patch { * @return The highest Patch-Version that was found */ public static String maxPatchVersion(@NotNull String modID) { - return ALL.stream() - .filter(p -> p.modID - .equals(modID)) - .map(p -> p.version) - .reduce((p, c) -> c) - .orElse("0.0.0"); + return ALL.stream().filter(p -> p.modID.equals(modID)).map(p -> p.version).reduce((p, c) -> c).orElse("0.0.0"); } /** @@ -66,12 +60,7 @@ public abstract class Patch { * @return The highest Patch-Level that was found */ public static int maxPatchLevel(@NotNull String modID) { - return ALL.stream() - .filter(p -> p.modID - .equals(modID)) - .mapToInt(p -> p.level) - .max() - .orElse(0); + return ALL.stream().filter(p -> p.modID.equals(modID)).mapToInt(p -> p.level).max().orElse(0); } /** @@ -103,21 +92,18 @@ public abstract class Patch { */ Patch(@NotNull String modID, String version, boolean alwaysApply) { //Patchlevels need to be unique and registered in ascending order - if (modID == null || "".equals(modID)) { + if (modID == null || modID.isEmpty()) { throw new RuntimeException("[INTERNAL ERROR] Patches need a valid modID!"); } - if (version == null || "".equals(version)) { + if (version == null || version.isEmpty()) { throw new RuntimeException("Invalid Mod-Version"); } this.version = version; this.alwaysApply = alwaysApply; this.level = ModUtil.convertModVersion(version); - if (!ALL.stream() - .filter(p -> p.modID - .equals(modID)) - .noneMatch(p -> p.level >= this.level) || this.level <= 0) { + if (!ALL.stream().filter(p -> p.modID.equals(modID)).noneMatch(p -> p.level >= this.level) || this.level <= 0) { throw new RuntimeException("[INTERNAL ERROR] Patch-levels need to be created in ascending order beginning with 1."); } @@ -239,5 +225,4 @@ public abstract class Patch { public List getWorldDataIDPaths() { return null; } - } diff --git a/src/main/java/ru/bclib/api/spawning/SpawnRuleEntry.java b/src/main/java/ru/bclib/api/spawning/SpawnRuleEntry.java index 710860c6..08461e44 100644 --- a/src/main/java/ru/bclib/api/spawning/SpawnRuleEntry.java +++ b/src/main/java/ru/bclib/api/spawning/SpawnRuleEntry.java @@ -19,7 +19,7 @@ public class SpawnRuleEntry implements Comparable this.rule = rule; } - boolean canSpawn(EntityType type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, Random random) { + protected boolean canSpawn(EntityType type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, Random random) { return rule.canSpawn(type, world, spawnReason, pos, random); } diff --git a/src/main/java/ru/bclib/blockentities/BaseBarrelBlockEntity.java b/src/main/java/ru/bclib/blockentities/BaseBarrelBlockEntity.java index 314503d4..d4badf53 100644 --- a/src/main/java/ru/bclib/blockentities/BaseBarrelBlockEntity.java +++ b/src/main/java/ru/bclib/blockentities/BaseBarrelBlockEntity.java @@ -35,14 +35,15 @@ public class BaseBarrelBlockEntity extends RandomizableContainerBlockEntity { public BaseBarrelBlockEntity(BlockPos blockPos, BlockState blockState) { this(BaseBlockEntities.BARREL, blockPos, blockState); } - - public CompoundTag save(CompoundTag tag) { - super.save(tag); + + @Override + public void saveAdditional(CompoundTag tag) { + super.saveAdditional(tag); if (!this.trySaveLootTable(tag)) { ContainerHelper.saveAllItems(tag, this.inventory); } - return tag; + //return tag; } public void load(CompoundTag tag) { @@ -93,7 +94,7 @@ public class BaseBarrelBlockEntity extends RandomizableContainerBlockEntity { } private void scheduleUpdate() { - level.getBlockTicks().scheduleTick(getBlockPos(), getBlockState().getBlock(), 5); + level.scheduleTick(getBlockPos(), getBlockState().getBlock(), 5); } public void tick() { diff --git a/src/main/java/ru/bclib/blocks/BaseAnvilBlock.java b/src/main/java/ru/bclib/blocks/BaseAnvilBlock.java index 9aca2c1d..5eae1c38 100644 --- a/src/main/java/ru/bclib/blocks/BaseAnvilBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseAnvilBlock.java @@ -15,6 +15,7 @@ import net.minecraft.world.item.PickaxeItem; import net.minecraft.world.level.block.AnvilBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.IntegerProperty; @@ -40,7 +41,11 @@ public abstract class BaseAnvilBlock extends AnvilBlock implements BlockModelPro public IntegerProperty durability; public BaseAnvilBlock(MaterialColor color) { - super(FabricBlockSettings.copyOf(Blocks.ANVIL).mapColor(color)); + this(FabricBlockSettings.copyOf(Blocks.ANVIL).color(color)); + } + + public BaseAnvilBlock(BlockBehaviour.Properties properties) { + super(properties); } @Override diff --git a/src/main/java/ru/bclib/blocks/BaseBarrelBlock.java b/src/main/java/ru/bclib/blocks/BaseBarrelBlock.java index c5d8dd8b..adfff85a 100644 --- a/src/main/java/ru/bclib/blocks/BaseBarrelBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseBarrelBlock.java @@ -22,6 +22,7 @@ import net.minecraft.world.level.block.BarrelBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.phys.BlockHitResult; @@ -40,7 +41,11 @@ import java.util.Random; public class BaseBarrelBlock extends BarrelBlock implements BlockModelProvider { public BaseBarrelBlock(Block source) { - super(FabricBlockSettings.copyOf(source).noOcclusion()); + this(FabricBlockSettings.copyOf(source).noOcclusion()); + } + + public BaseBarrelBlock(BlockBehaviour.Properties properties) { + super(properties); } @Override diff --git a/src/main/java/ru/bclib/blocks/BaseBlockNotFull.java b/src/main/java/ru/bclib/blocks/BaseBlockNotFull.java index 0ddc700c..d483ea4f 100644 --- a/src/main/java/ru/bclib/blocks/BaseBlockNotFull.java +++ b/src/main/java/ru/bclib/blocks/BaseBlockNotFull.java @@ -6,7 +6,6 @@ import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.block.state.BlockState; public class BaseBlockNotFull extends BaseBlock { - public BaseBlockNotFull(Properties settings) { super(settings); } diff --git a/src/main/java/ru/bclib/blocks/BaseBookshelfBlock.java b/src/main/java/ru/bclib/blocks/BaseBookshelfBlock.java index 68999421..0a6e570f 100644 --- a/src/main/java/ru/bclib/blocks/BaseBookshelfBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseBookshelfBlock.java @@ -10,6 +10,7 @@ import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; @@ -24,7 +25,11 @@ import java.util.Optional; public class BaseBookshelfBlock extends BaseBlock { public BaseBookshelfBlock(Block source) { - super(FabricBlockSettings.copyOf(source)); + this(FabricBlockSettings.copyOf(source)); + } + + public BaseBookshelfBlock(BlockBehaviour.Properties properties) { + super(properties); } @Override diff --git a/src/main/java/ru/bclib/blocks/BaseButtonBlock.java b/src/main/java/ru/bclib/blocks/BaseButtonBlock.java index 289eef21..e60f2ba0 100644 --- a/src/main/java/ru/bclib/blocks/BaseButtonBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseButtonBlock.java @@ -25,7 +25,6 @@ import java.util.Map; import java.util.Optional; public abstract class BaseButtonBlock extends ButtonBlock implements BlockModelProvider { - private final Block parent; protected BaseButtonBlock(Block parent, Properties properties, boolean sensitive) { diff --git a/src/main/java/ru/bclib/blocks/BaseChainBlock.java b/src/main/java/ru/bclib/blocks/BaseChainBlock.java index 9abdb58e..4af5392b 100644 --- a/src/main/java/ru/bclib/blocks/BaseChainBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseChainBlock.java @@ -10,6 +10,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.ChainBlock; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.MaterialColor; import net.minecraft.world.level.storage.loot.LootContext; @@ -28,7 +29,11 @@ import java.util.Optional; public class BaseChainBlock extends ChainBlock implements BlockModelProvider, RenderLayerProvider { public BaseChainBlock(MaterialColor color) { - super(FabricBlockSettings.copyOf(Blocks.CHAIN).mapColor(color)); + this(FabricBlockSettings.copyOf(Blocks.CHAIN).color(color)); + } + + public BaseChainBlock(BlockBehaviour.Properties properties) { + super(properties); } @Override diff --git a/src/main/java/ru/bclib/blocks/BaseCraftingTableBlock.java b/src/main/java/ru/bclib/blocks/BaseCraftingTableBlock.java index 6be8cbb9..a161d979 100644 --- a/src/main/java/ru/bclib/blocks/BaseCraftingTableBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseCraftingTableBlock.java @@ -8,6 +8,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.CraftingTableBlock; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.storage.loot.LootContext; import org.jetbrains.annotations.Nullable; @@ -23,7 +24,11 @@ import java.util.Optional; public class BaseCraftingTableBlock extends CraftingTableBlock implements BlockModelProvider { public BaseCraftingTableBlock(Block source) { - super(FabricBlockSettings.copyOf(source)); + this(FabricBlockSettings.copyOf(source)); + } + + public BaseCraftingTableBlock(BlockBehaviour.Properties properties) { + super(properties); } @Override diff --git a/src/main/java/ru/bclib/blocks/BaseCropBlock.java b/src/main/java/ru/bclib/blocks/BaseCropBlock.java index 18a16c06..72f7f20a 100644 --- a/src/main/java/ru/bclib/blocks/BaseCropBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseCropBlock.java @@ -2,7 +2,6 @@ package ru.bclib.blocks; import com.google.common.collect.Lists; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; -import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.Mth; @@ -31,19 +30,25 @@ import java.util.List; import java.util.Random; public class BaseCropBlock extends BasePlantBlock { - private static final VoxelShape SHAPE = Block.box(2, 0, 2, 14, 14, 14); public static final IntegerProperty AGE = IntegerProperty.create("age", 0, 3); + private static final VoxelShape SHAPE = Block.box(2, 0, 2, 14, 14, 14); private final Block[] terrain; private final Item drop; public BaseCropBlock(Item drop, Block... terrain) { - super(FabricBlockSettings.of(Material.PLANT) - .breakByTool(FabricToolTags.HOES) - .breakByHand(true) - .sound(SoundType.GRASS) - .randomTicks() - .noCollission()); + this( + FabricBlockSettings.of(Material.PLANT) + .breakByHand(true) + .sound(SoundType.GRASS) + .randomTicks() + .noCollission(), + drop, terrain + ); + } + + public BaseCropBlock(BlockBehaviour.Properties properties, Item drop, Block... terrain) { + super(properties); this.drop = drop; this.terrain = terrain; this.registerDefaultState(defaultBlockState().setValue(AGE, 0)); diff --git a/src/main/java/ru/bclib/blocks/BaseDoorBlock.java b/src/main/java/ru/bclib/blocks/BaseDoorBlock.java index 2e8f8d8b..881085a9 100644 --- a/src/main/java/ru/bclib/blocks/BaseDoorBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseDoorBlock.java @@ -12,6 +12,7 @@ import net.minecraft.util.StringRepresentable; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.DoorBlock; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.DoorHingeSide; import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; @@ -31,7 +32,11 @@ import java.util.Optional; public class BaseDoorBlock extends DoorBlock implements RenderLayerProvider, BlockModelProvider { public BaseDoorBlock(Block source) { - super(FabricBlockSettings.copyOf(source).strength(3F, 3F).noOcclusion()); + this(FabricBlockSettings.copyOf(source).strength(3F, 3F).noOcclusion()); + } + + public BaseDoorBlock(BlockBehaviour.Properties properties) { + super(properties); } @Override diff --git a/src/main/java/ru/bclib/blocks/BaseDoublePlantBlock.java b/src/main/java/ru/bclib/blocks/BaseDoublePlantBlock.java index ad065758..7c80d49e 100644 --- a/src/main/java/ru/bclib/blocks/BaseDoublePlantBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseDoublePlantBlock.java @@ -37,28 +37,32 @@ import ru.bclib.util.BlocksHelper; import java.util.List; import java.util.Random; -@SuppressWarnings("deprecation") public abstract class BaseDoublePlantBlock extends BaseBlockNotFull implements RenderLayerProvider, BonemealableBlock { private static final VoxelShape SHAPE = Block.box(4, 2, 4, 12, 16, 12); public static final IntegerProperty ROTATION = BlockProperties.ROTATION; public static final BooleanProperty TOP = BooleanProperty.create("top"); public BaseDoublePlantBlock() { - super(FabricBlockSettings.of(Material.PLANT) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .sound(SoundType.WET_GRASS) - .noCollission()); - this.registerDefaultState(this.stateDefinition.any().setValue(TOP, false)); + this( + FabricBlockSettings.of(Material.PLANT) + .breakByHand(true) + .sound(SoundType.GRASS) + .noCollission() + ); } public BaseDoublePlantBlock(int light) { - super(FabricBlockSettings.of(Material.PLANT) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .sound(SoundType.WET_GRASS) - .lightLevel((state) -> state.getValue(TOP) ? light : 0) - .noCollission()); + this( + FabricBlockSettings.of(Material.PLANT) + .breakByHand(true) + .sound(SoundType.GRASS) + .lightLevel((state) -> state.getValue(TOP) ? light : 0) + .noCollission() + ); + } + + public BaseDoublePlantBlock(BlockBehaviour.Properties properties) { + super(properties); this.registerDefaultState(this.stateDefinition.any().setValue(TOP, false)); } @@ -68,6 +72,7 @@ public abstract class BaseDoublePlantBlock extends BaseBlockNotFull implements R } @Override + @SuppressWarnings("deprecation") public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) { Vec3 vec3d = state.getOffset(view, pos); return SHAPE.move(vec3d.x, vec3d.y, vec3d.z); @@ -79,6 +84,7 @@ public abstract class BaseDoublePlantBlock extends BaseBlockNotFull implements R } @Override + @SuppressWarnings("deprecation") public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { BlockState down = world.getBlockState(pos.below()); BlockState up = world.getBlockState(pos.above()); @@ -94,6 +100,7 @@ public abstract class BaseDoublePlantBlock extends BaseBlockNotFull implements R protected abstract boolean isTerrain(BlockState state); @Override + @SuppressWarnings("deprecation") public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) { if (!canStayAt(state, world, pos)) { return Blocks.AIR.defaultBlockState(); diff --git a/src/main/java/ru/bclib/blocks/BaseFurnaceBlock.java b/src/main/java/ru/bclib/blocks/BaseFurnaceBlock.java index 09958ec8..52844196 100644 --- a/src/main/java/ru/bclib/blocks/BaseFurnaceBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseFurnaceBlock.java @@ -20,6 +20,7 @@ import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; @@ -39,7 +40,11 @@ import java.util.Optional; public class BaseFurnaceBlock extends FurnaceBlock implements BlockModelProvider, RenderLayerProvider { public BaseFurnaceBlock(Block source) { - super(FabricBlockSettings.copyOf(source).luminance(state -> state.getValue(LIT) ? 13 : 0)); + this(FabricBlockSettings.copyOf(source).lightLevel(state -> state.getValue(LIT) ? 13 : 0)); + } + + public BaseFurnaceBlock(BlockBehaviour.Properties properties) { + super(properties); } @Override diff --git a/src/main/java/ru/bclib/blocks/BaseLadderBlock.java b/src/main/java/ru/bclib/blocks/BaseLadderBlock.java index d43d8fdf..2128a780 100644 --- a/src/main/java/ru/bclib/blocks/BaseLadderBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseLadderBlock.java @@ -9,6 +9,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.LadderBlock; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.storage.loot.LootContext; import org.jetbrains.annotations.Nullable; @@ -26,7 +27,11 @@ import java.util.Optional; public class BaseLadderBlock extends LadderBlock implements RenderLayerProvider, BlockModelProvider { public BaseLadderBlock(Block block) { - super(FabricBlockSettings.copyOf(block).noOcclusion()); + this(FabricBlockSettings.copyOf(block).noOcclusion()); + } + + public BaseLadderBlock(BlockBehaviour.Properties properties) { + super(properties); } @Override diff --git a/src/main/java/ru/bclib/blocks/BaseLeavesBlock.java b/src/main/java/ru/bclib/blocks/BaseLeavesBlock.java index 3dd32197..6e538ef3 100644 --- a/src/main/java/ru/bclib/blocks/BaseLeavesBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseLeavesBlock.java @@ -1,10 +1,13 @@ package ru.bclib.blocks; import com.google.common.collect.Lists; +import net.fabricmc.fabric.api.mininglevel.v1.FabricMineableTags; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; -import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.BlockTags; +import net.minecraft.tags.Tag.Named; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.item.enchantment.Enchantments; @@ -15,34 +18,35 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.MaterialColor; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import ru.bclib.api.TagAPI; import ru.bclib.client.render.BCLRenderLayer; import ru.bclib.interfaces.BlockModelProvider; import ru.bclib.interfaces.RenderLayerProvider; +import ru.bclib.interfaces.TagProvider; import ru.bclib.util.MHelper; import java.util.Collections; import java.util.List; import java.util.function.Consumer; -public class BaseLeavesBlock extends LeavesBlock implements BlockModelProvider, RenderLayerProvider { +public class BaseLeavesBlock extends LeavesBlock implements BlockModelProvider, RenderLayerProvider, TagProvider { protected final Block sapling; private static FabricBlockSettings makeLeaves(MaterialColor color) { - return FabricBlockSettings.copyOf(Blocks.OAK_LEAVES) - .mapColor(color) - .breakByTool(FabricToolTags.HOES) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .allowsSpawning((state, world, pos, type) -> false) - .suffocates((state, world, pos) -> false) - .blockVision((state, world, pos) -> false); + return FabricBlockSettings + .copyOf(Blocks.OAK_LEAVES) + .mapColor(color) + .requiresTool() + .allowsSpawning((state, world, pos, type) -> false) + .suffocates((state, world, pos) -> false) + .blockVision((state, world, pos) -> false); } public BaseLeavesBlock(Block sapling, MaterialColor color, Consumer customizeProperties) { super(BaseBlock.acceptAndReturn(customizeProperties, makeLeaves(color))); this.sapling = sapling; } - + public BaseLeavesBlock(Block sapling, MaterialColor color, int light, Consumer customizeProperties) { super(BaseBlock.acceptAndReturn(customizeProperties, makeLeaves(color).luminance(light))); this.sapling = sapling; @@ -68,7 +72,7 @@ public class BaseLeavesBlock extends LeavesBlock implements BlockModelProvider, public List getDrops(BlockState state, LootContext.Builder builder) { ItemStack tool = builder.getParameter(LootContextParams.TOOL); if (tool != null) { - if (FabricToolTags.SHEARS.contains(tool.getItem()) || EnchantmentHelper.getItemEnchantmentLevel( + if (tool.isCorrectToolForDrops(state) || EnchantmentHelper.getItemEnchantmentLevel( Enchantments.SILK_TOUCH, tool ) > 0) { @@ -87,4 +91,11 @@ public class BaseLeavesBlock extends LeavesBlock implements BlockModelProvider, public BlockModel getItemModel(ResourceLocation resourceLocation) { return getBlockModel(resourceLocation, defaultBlockState()); } + + @Override + public void addTags(List> blockTags, List> itemTags) { + blockTags.add(FabricMineableTags.SHEARS_MINEABLE); + blockTags.add(TagAPI.MINEABLE_HOE); + blockTags.add(BlockTags.LEAVES); + } } diff --git a/src/main/java/ru/bclib/blocks/BaseMetalBarsBlock.java b/src/main/java/ru/bclib/blocks/BaseMetalBarsBlock.java index 5c64bf7f..895ff38e 100644 --- a/src/main/java/ru/bclib/blocks/BaseMetalBarsBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseMetalBarsBlock.java @@ -12,6 +12,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.IronBarsBlock; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.storage.loot.LootContext; import org.jetbrains.annotations.Nullable; @@ -29,7 +30,11 @@ import java.util.Optional; public class BaseMetalBarsBlock extends IronBarsBlock implements BlockModelProvider, RenderLayerProvider { public BaseMetalBarsBlock(Block source) { - super(FabricBlockSettings.copyOf(source).strength(5.0F, 6.0F).noOcclusion()); + this(FabricBlockSettings.copyOf(source).strength(5.0F, 6.0F).noOcclusion()); + } + + public BaseMetalBarsBlock(BlockBehaviour.Properties properties) { + super(properties); } @Override diff --git a/src/main/java/ru/bclib/blocks/BaseOreBlock.java b/src/main/java/ru/bclib/blocks/BaseOreBlock.java index f529c082..c899efcf 100644 --- a/src/main/java/ru/bclib/blocks/BaseOreBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseOreBlock.java @@ -1,6 +1,8 @@ package ru.bclib.blocks; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; +import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; +import net.fabricmc.fabric.impl.object.builder.FabricBlockInternals; import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; @@ -22,32 +24,49 @@ import ru.bclib.util.MHelper; import java.util.Collections; import java.util.List; +import java.util.function.Supplier; public class BaseOreBlock extends OreBlock implements BlockModelProvider { - private final Item dropItem; + private final Supplier dropItem; private final int minCount; private final int maxCount; - public BaseOreBlock(Item drop, int minCount, int maxCount, int experience) { - this(drop, minCount, maxCount, experience, FabricBlockSettings.of(Material.STONE, MaterialColor.SAND) - .hardness(3F) - .resistance(9F) - .requiresCorrectToolForDrops() - .sound(SoundType.STONE)); - + public BaseOreBlock(Supplier drop, int minCount, int maxCount, int experience) { + this(drop, minCount, maxCount, experience, 0); } - public BaseOreBlock(Item drop, int minCount, int maxCount, int experience, Properties properties) { - super(properties, UniformInt.of(experience>0?1:0, experience)); + public BaseOreBlock(Supplier drop, int minCount, int maxCount, int experience, int miningLevel) { + this( + FabricBlockSettings + .of(Material.STONE, MaterialColor.SAND) + .requiresTool() + .destroyTime(3F) + .explosionResistance(9F) + .sound(SoundType.STONE), + drop, minCount, maxCount, experience, miningLevel + ); + } + + public BaseOreBlock(Properties properties, Supplier drop, int minCount, int maxCount, int experience) { + this(properties, drop, minCount, maxCount, experience, 0); + } + + public BaseOreBlock(Properties properties, Supplier drop, int minCount, int maxCount, int experience, int miningLevel) { + super(makeProps(properties, miningLevel), UniformInt.of(experience>0?1:0, experience)); this.dropItem = drop; this.minCount = minCount; this.maxCount = maxCount; } + private static Properties makeProps(Properties properties, int level){ + FabricBlockInternals.computeExtraData(properties).addMiningLevel(FabricToolTags.PICKAXES, level); + return properties; + } + @Override @SuppressWarnings("deprecation") public List getDrops(BlockState state, LootContext.Builder builder) { - return getDroppedItems(this, dropItem, maxCount, minCount, state, builder); + return getDroppedItems(this, dropItem.get(), maxCount, minCount, state, builder); } public static List getDroppedItems(ItemLike block, Item dropItem, int maxCount, int minCount, BlockState state, LootContext.Builder builder) { diff --git a/src/main/java/ru/bclib/blocks/BasePathBlock.java b/src/main/java/ru/bclib/blocks/BasePathBlock.java index d39e1891..c0f212ef 100644 --- a/src/main/java/ru/bclib/blocks/BasePathBlock.java +++ b/src/main/java/ru/bclib/blocks/BasePathBlock.java @@ -30,7 +30,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -@SuppressWarnings("deprecation") public class BasePathBlock extends BaseBlockNotFull { private static final VoxelShape SHAPE = Block.box(0, 0, 0, 16, 15, 16); @@ -56,11 +55,13 @@ public class BasePathBlock extends BaseBlockNotFull { } @Override + @SuppressWarnings("deprecation") public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) { return SHAPE; } @Override + @SuppressWarnings("deprecation") public VoxelShape getCollisionShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) { return SHAPE; } diff --git a/src/main/java/ru/bclib/blocks/BasePlantBlock.java b/src/main/java/ru/bclib/blocks/BasePlantBlock.java index 23114bfb..04474e2b 100644 --- a/src/main/java/ru/bclib/blocks/BasePlantBlock.java +++ b/src/main/java/ru/bclib/blocks/BasePlantBlock.java @@ -3,6 +3,7 @@ package ru.bclib.blocks; import com.google.common.collect.Lists; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.mininglevel.v1.FabricMineableTags; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; import net.minecraft.client.renderer.block.model.BlockModel; @@ -10,7 +11,9 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.Tag.Named; import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.item.enchantment.Enchantments; @@ -31,18 +34,19 @@ import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import org.jetbrains.annotations.Nullable; +import ru.bclib.api.TagAPI; import ru.bclib.client.models.BasePatterns; import ru.bclib.client.models.ModelsHelper; import ru.bclib.client.models.PatternsHelper; import ru.bclib.client.render.BCLRenderLayer; import ru.bclib.interfaces.RenderLayerProvider; +import ru.bclib.interfaces.TagProvider; import java.util.List; import java.util.Optional; import java.util.Random; -@SuppressWarnings("deprecation") -public abstract class BasePlantBlock extends BaseBlockNotFull implements RenderLayerProvider, BonemealableBlock { +public abstract class BasePlantBlock extends BaseBlockNotFull implements RenderLayerProvider, BonemealableBlock, TagProvider { private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 14, 12); public BasePlantBlock() { @@ -54,20 +58,24 @@ public abstract class BasePlantBlock extends BaseBlockNotFull implements RenderL } public BasePlantBlock(boolean replaceable) { - super(FabricBlockSettings.of(replaceable ? Material.REPLACEABLE_PLANT : Material.PLANT) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .sound(SoundType.GRASS) - .noCollission()); + this( + FabricBlockSettings + .of(replaceable ? Material.REPLACEABLE_PLANT : Material.PLANT) + .breakByHand(true) + .sound(SoundType.GRASS) + .noCollission() + ); } public BasePlantBlock(boolean replaceable, int light) { - super(FabricBlockSettings.of(replaceable ? Material.REPLACEABLE_PLANT : Material.PLANT) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .luminance(light) - .sound(SoundType.GRASS) - .noCollission()); + this( + FabricBlockSettings + .of(replaceable ? Material.REPLACEABLE_PLANT : Material.PLANT) + .breakByHand(true) + .luminance(light) + .sound(SoundType.GRASS) + .noCollission() + ); } public BasePlantBlock(Properties settings) { @@ -77,6 +85,7 @@ public abstract class BasePlantBlock extends BaseBlockNotFull implements RenderL protected abstract boolean isTerrain(BlockState state); @Override + @SuppressWarnings("deprecation") public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) { Vec3 vec3d = state.getOffset(view, pos); return SHAPE.move(vec3d.x, vec3d.y, vec3d.z); @@ -88,12 +97,14 @@ public abstract class BasePlantBlock extends BaseBlockNotFull implements RenderL } @Override + @SuppressWarnings("deprecation") public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { BlockState down = world.getBlockState(pos.below()); return isTerrain(down); } @Override + @SuppressWarnings("deprecation") public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) { if (!canSurvive(state, world, pos)) { return Blocks.AIR.defaultBlockState(); @@ -157,4 +168,10 @@ public abstract class BasePlantBlock extends BaseBlockNotFull implements RenderL Optional pattern = PatternsHelper.createJson(BasePatterns.BLOCK_CROSS, resourceLocation); return ModelsHelper.fromPattern(pattern); } + + @Override + public void addTags(List> blockTags, List> itemTags) { + blockTags.add(FabricMineableTags.SHEARS_MINEABLE); + blockTags.add(TagAPI.MINEABLE_HOE); + } } diff --git a/src/main/java/ru/bclib/blocks/BasePlantWithAgeBlock.java b/src/main/java/ru/bclib/blocks/BasePlantWithAgeBlock.java index 4d8ce1b0..3beb20d8 100644 --- a/src/main/java/ru/bclib/blocks/BasePlantWithAgeBlock.java +++ b/src/main/java/ru/bclib/blocks/BasePlantWithAgeBlock.java @@ -1,7 +1,6 @@ package ru.bclib.blocks; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; -import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; @@ -19,12 +18,13 @@ public abstract class BasePlantWithAgeBlock extends BasePlantBlock { public static final IntegerProperty AGE = BlockProperties.AGE; public BasePlantWithAgeBlock() { - this(FabricBlockSettings.of(Material.PLANT) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .sound(SoundType.GRASS) - .randomTicks() - .noCollission()); + this( + FabricBlockSettings.of(Material.PLANT) + .breakByHand(true) + .sound(SoundType.GRASS) + .randomTicks() + .noCollission() + ); } public BasePlantWithAgeBlock(Properties settings) { diff --git a/src/main/java/ru/bclib/blocks/BaseRotatedPillarBlock.java b/src/main/java/ru/bclib/blocks/BaseRotatedPillarBlock.java index dc1560fa..1b4f14e7 100644 --- a/src/main/java/ru/bclib/blocks/BaseRotatedPillarBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseRotatedPillarBlock.java @@ -27,7 +27,7 @@ public class BaseRotatedPillarBlock extends RotatedPillarBlock implements BlockM } public BaseRotatedPillarBlock(Block block) { - super(FabricBlockSettings.copyOf(block)); + this(FabricBlockSettings.copyOf(block)); } @Override diff --git a/src/main/java/ru/bclib/blocks/BaseSignBlock.java b/src/main/java/ru/bclib/blocks/BaseSignBlock.java index 655dff5a..1a2620a1 100644 --- a/src/main/java/ru/bclib/blocks/BaseSignBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseSignBlock.java @@ -64,10 +64,7 @@ public class BaseSignBlock extends SignBlock implements BlockModelProvider, Cust public BaseSignBlock(Block source) { super(FabricBlockSettings.copyOf(source).strength(1.0F, 1.0F).noCollission().noOcclusion(), WoodType.OAK); - this.registerDefaultState(this.stateDefinition.any() - .setValue(ROTATION, 0) - .setValue(FLOOR, false) - .setValue(WATERLOGGED, false)); + this.registerDefaultState(this.stateDefinition.any().setValue(ROTATION, 0).setValue(FLOOR, false).setValue(WATERLOGGED, false)); this.parent = source; } @@ -105,7 +102,7 @@ public class BaseSignBlock extends SignBlock implements BlockModelProvider, Cust @Override public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) { if (state.getValue(WATERLOGGED)) { - world.getLiquidTicks().scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world)); + world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world)); } if (!canSurvive(state, world, pos)) { return state.getValue(WATERLOGGED) ? state.getFluidState() @@ -181,18 +178,16 @@ public class BaseSignBlock extends SignBlock implements BlockModelProvider, Cust @Override public boolean canPlaceLiquid(BlockGetter world, BlockPos pos, BlockState state, Fluid fluid) { - // TODO Auto-generated method stub return super.canPlaceLiquid(world, pos, state, fluid); } @Override public boolean placeLiquid(LevelAccessor world, BlockPos pos, BlockState state, FluidState fluidState) { - // TODO Auto-generated method stub return super.placeLiquid(world, pos, state, fluidState); } @Override public BlockItem getCustomItem(ResourceLocation blockID, FabricItemSettings settings) { - return new BlockItem(this, settings.maxCount(16)); + return new BlockItem(this, settings.stacksTo(16)); } } \ No newline at end of file diff --git a/src/main/java/ru/bclib/blocks/BaseStairsBlock.java b/src/main/java/ru/bclib/blocks/BaseStairsBlock.java index 7e9de0a0..6074ff55 100644 --- a/src/main/java/ru/bclib/blocks/BaseStairsBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseStairsBlock.java @@ -27,7 +27,6 @@ import java.util.Map; import java.util.Optional; public class BaseStairsBlock extends StairBlock implements BlockModelProvider { - private final Block parent; public BaseStairsBlock(Block source) { diff --git a/src/main/java/ru/bclib/blocks/BaseStoneButtonBlock.java b/src/main/java/ru/bclib/blocks/BaseStoneButtonBlock.java index 6c6bf59b..ed10c5a5 100644 --- a/src/main/java/ru/bclib/blocks/BaseStoneButtonBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseStoneButtonBlock.java @@ -6,7 +6,6 @@ import net.minecraft.sounds.SoundEvents; import net.minecraft.world.level.block.Block; public class BaseStoneButtonBlock extends BaseButtonBlock { - public BaseStoneButtonBlock(Block source) { super(source, FabricBlockSettings.copyOf(source).noOcclusion(), false); } diff --git a/src/main/java/ru/bclib/blocks/BaseStripableLogBlock.java b/src/main/java/ru/bclib/blocks/BaseStripableLogBlock.java index eb82ebbe..28127de4 100644 --- a/src/main/java/ru/bclib/blocks/BaseStripableLogBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseStripableLogBlock.java @@ -20,7 +20,7 @@ public class BaseStripableLogBlock extends BaseRotatedPillarBlock { private final Block striped; public BaseStripableLogBlock(MaterialColor color, Block striped) { - super(FabricBlockSettings.copyOf(striped).mapColor(color)); + super(FabricBlockSettings.copyOf(striped).color(color)); this.striped = striped; } diff --git a/src/main/java/ru/bclib/blocks/BaseTrapdoorBlock.java b/src/main/java/ru/bclib/blocks/BaseTrapdoorBlock.java index 7e4c0ba7..7f09fee6 100644 --- a/src/main/java/ru/bclib/blocks/BaseTrapdoorBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseTrapdoorBlock.java @@ -10,6 +10,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.TrapDoorBlock; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Half; import net.minecraft.world.level.storage.loot.LootContext; @@ -29,7 +30,11 @@ import java.util.Optional; public class BaseTrapdoorBlock extends TrapDoorBlock implements RenderLayerProvider, BlockModelProvider { public BaseTrapdoorBlock(Block source) { - super(FabricBlockSettings.copyOf(source).strength(3.0F, 3.0F).noOcclusion()); + this(FabricBlockSettings.copyOf(source).strength(3.0F, 3.0F).noOcclusion()); + } + + public BaseTrapdoorBlock(BlockBehaviour.Properties properties) { + super(properties); } @Override diff --git a/src/main/java/ru/bclib/blocks/BaseUnderwaterWallPlantBlock.java b/src/main/java/ru/bclib/blocks/BaseUnderwaterWallPlantBlock.java index 2c226cf4..e8fc1233 100644 --- a/src/main/java/ru/bclib/blocks/BaseUnderwaterWallPlantBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseUnderwaterWallPlantBlock.java @@ -1,7 +1,6 @@ package ru.bclib.blocks; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; -import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; import net.minecraft.core.BlockPos; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.LevelAccessor; @@ -15,22 +14,25 @@ import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.material.Material; public abstract class BaseUnderwaterWallPlantBlock extends BaseWallPlantBlock implements LiquidBlockContainer { - public BaseUnderwaterWallPlantBlock() { - super(FabricBlockSettings.of(Material.WATER_PLANT) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .sound(SoundType.WET_GRASS) - .noCollission()); + this( + FabricBlockSettings + .of(Material.WATER_PLANT) + .breakByHand(true) + .sound(SoundType.WET_GRASS) + .noCollission() + ); } public BaseUnderwaterWallPlantBlock(int light) { - super(FabricBlockSettings.of(Material.WATER_PLANT) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .luminance(light) - .sound(SoundType.WET_GRASS) - .noCollission()); + this( + FabricBlockSettings + .of(Material.WATER_PLANT) + .breakByHand(true) + .luminance(light) + .sound(SoundType.WET_GRASS) + .noCollission() + ); } public BaseUnderwaterWallPlantBlock(Properties settings) { diff --git a/src/main/java/ru/bclib/blocks/BaseVineBlock.java b/src/main/java/ru/bclib/blocks/BaseVineBlock.java index 67688cba..6e156b43 100644 --- a/src/main/java/ru/bclib/blocks/BaseVineBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseVineBlock.java @@ -50,12 +50,18 @@ public class BaseVineBlock extends BaseBlockNotFull implements RenderLayerProvid } public BaseVineBlock(int light, boolean bottomOnly) { - super(FabricBlockSettings.of(Material.PLANT) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .sound(SoundType.GRASS) - .lightLevel((state) -> bottomOnly ? state.getValue(SHAPE) == TripleShape.BOTTOM ? light : 0 : light) - .noCollission()); + this( + FabricBlockSettings + .of(Material.PLANT) + .breakByHand(true) + .sound(SoundType.GRASS) + .lightLevel((state) -> bottomOnly ? state.getValue(SHAPE) == TripleShape.BOTTOM ? light : 0 : light) + .noCollission() + ); + } + + public BaseVineBlock(BlockBehaviour.Properties properties) { + super(properties); this.registerDefaultState(this.stateDefinition.any().setValue(SHAPE, TripleShape.BOTTOM)); } diff --git a/src/main/java/ru/bclib/blocks/BaseWallBlock.java b/src/main/java/ru/bclib/blocks/BaseWallBlock.java index 3f0eea73..2081d5f6 100644 --- a/src/main/java/ru/bclib/blocks/BaseWallBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseWallBlock.java @@ -26,7 +26,6 @@ import java.util.Map; import java.util.Optional; public class BaseWallBlock extends WallBlock implements BlockModelProvider { - private final Block parent; public BaseWallBlock(Block source) { diff --git a/src/main/java/ru/bclib/blocks/BaseWallPlantBlock.java b/src/main/java/ru/bclib/blocks/BaseWallPlantBlock.java index ee022070..54e8dbd3 100644 --- a/src/main/java/ru/bclib/blocks/BaseWallPlantBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseWallPlantBlock.java @@ -3,7 +3,6 @@ package ru.bclib.blocks; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; -import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.item.context.BlockPlaceContext; @@ -29,32 +28,32 @@ import java.util.EnumMap; public abstract class BaseWallPlantBlock extends BasePlantBlock { private static final EnumMap SHAPES = Maps.newEnumMap(ImmutableMap.of( - Direction.NORTH, - Block.box(1, 1, 8, 15, 15, 16), - Direction.SOUTH, - Block.box(1, 1, 0, 15, 15, 8), - Direction.WEST, - Block.box(8, 1, 1, 16, 15, 15), - Direction.EAST, - Block.box(0, 1, 1, 8, 15, 15) + Direction.NORTH, Block.box(1, 1, 8, 15, 15, 16), + Direction.SOUTH, Block.box(1, 1, 0, 15, 15, 8), + Direction.WEST, Block.box(8, 1, 1, 16, 15, 15), + Direction.EAST, Block.box(0, 1, 1, 8, 15, 15) )); public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING; public BaseWallPlantBlock() { - this(FabricBlockSettings.of(Material.PLANT) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .sound(SoundType.GRASS) - .noCollission()); + this( + FabricBlockSettings + .of(Material.PLANT) + .breakByHand(true) + .sound(SoundType.GRASS) + .noCollission() + ); } public BaseWallPlantBlock(int light) { - this(FabricBlockSettings.of(Material.PLANT) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .luminance(light) - .sound(SoundType.GRASS) - .noCollission()); + this( + FabricBlockSettings + .of(Material.PLANT) + .breakByHand(true) + .luminance(light) + .sound(SoundType.GRASS) + .noCollission() + ); } public BaseWallPlantBlock(Properties settings) { diff --git a/src/main/java/ru/bclib/blocks/BaseWoodenButtonBlock.java b/src/main/java/ru/bclib/blocks/BaseWoodenButtonBlock.java index 3d92013b..d6f34264 100644 --- a/src/main/java/ru/bclib/blocks/BaseWoodenButtonBlock.java +++ b/src/main/java/ru/bclib/blocks/BaseWoodenButtonBlock.java @@ -6,7 +6,6 @@ import net.minecraft.sounds.SoundEvents; import net.minecraft.world.level.block.Block; public class BaseWoodenButtonBlock extends BaseButtonBlock { - public BaseWoodenButtonBlock(Block source) { super(source, FabricBlockSettings.copyOf(source).strength(0.5F, 0.5F).noOcclusion(), true); } diff --git a/src/main/java/ru/bclib/blocks/FeatureHangingSaplingBlock.java b/src/main/java/ru/bclib/blocks/FeatureHangingSaplingBlock.java index 049f8c10..d75b5e07 100644 --- a/src/main/java/ru/bclib/blocks/FeatureHangingSaplingBlock.java +++ b/src/main/java/ru/bclib/blocks/FeatureHangingSaplingBlock.java @@ -4,18 +4,27 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.feature.Feature; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -public abstract class FeatureHangingSaplingBlock extends FeatureSaplingBlockCommon{ +import java.util.function.Function; + +public abstract class FeatureHangingSaplingBlock extends FeatureSaplingBlock { private static final VoxelShape SHAPE = Block.box(4, 2, 4, 12, 16, 12); - public FeatureHangingSaplingBlock() { - super(); + + public FeatureHangingSaplingBlock(Function> featureSupplier) { + super(featureSupplier); } - public FeatureHangingSaplingBlock(int light) { - super(light); + public FeatureHangingSaplingBlock(Function> featureSupplier, int light) { + super(light, featureSupplier); + } + + public FeatureHangingSaplingBlock(BlockBehaviour.Properties properties, Function> featureSupplier) { + super(properties, featureSupplier); } @Override diff --git a/src/main/java/ru/bclib/blocks/FeatureSaplingBlock.java b/src/main/java/ru/bclib/blocks/FeatureSaplingBlock.java index f0045a0e..dfee5df8 100644 --- a/src/main/java/ru/bclib/blocks/FeatureSaplingBlock.java +++ b/src/main/java/ru/bclib/blocks/FeatureSaplingBlock.java @@ -1,22 +1,137 @@ package ru.bclib.blocks; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; +import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SaplingBlock; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.feature.Feature; +import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; +import net.minecraft.world.level.material.Material; +import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.Nullable; +import ru.bclib.client.models.BasePatterns; +import ru.bclib.client.models.ModelsHelper; +import ru.bclib.client.models.PatternsHelper; +import ru.bclib.client.render.BCLRenderLayer; +import ru.bclib.interfaces.BlockModelProvider; +import ru.bclib.interfaces.RenderLayerProvider; -@SuppressWarnings("deprecation") -public abstract class FeatureSaplingBlock extends FeatureSaplingBlockCommon { +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Random; +import java.util.function.Function; + +public class FeatureSaplingBlock extends SaplingBlock implements RenderLayerProvider, BlockModelProvider { private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 14, 12); + private final Function> feature; - public FeatureSaplingBlock() { - super(); + public FeatureSaplingBlock(Function> featureSupplier) { + this(FabricBlockSettings.of(Material.PLANT) + .breakByHand(true) + .collidable(false) + .instabreak() + .sound(SoundType.GRASS) + .randomTicks(), + featureSupplier + ); } - public FeatureSaplingBlock(int light) { - super(light); + public FeatureSaplingBlock(int light, Function> featureSupplier) { + this(FabricBlockSettings.of(Material.PLANT) + .breakByHand(true) + .collidable(false) + .luminance(light) + .instabreak() + .sound(SoundType.GRASS) + .randomTicks(), + featureSupplier + ); + } + + public FeatureSaplingBlock(BlockBehaviour.Properties properties, Function> featureSupplier) { + super(null, properties); + this.feature = featureSupplier; + } + + protected Feature getFeature(BlockState state) { + return feature.apply(state); + } + + @Override + public List getDrops(BlockState state, LootContext.Builder builder) { + return Collections.singletonList(new ItemStack(this)); + } + + @Override + public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) { + if (!canSurvive(state, world, pos)) return Blocks.AIR.defaultBlockState(); + else return state; + } + + @Override + public boolean isBonemealSuccess(Level world, Random random, BlockPos pos, BlockState state) { + return random.nextInt(16) == 0; + } + + @Override + public void advanceTree(ServerLevel world, BlockPos pos, BlockState blockState, Random random) { + FeaturePlaceContext context = new FeaturePlaceContext( + Optional.empty(), + world, + world.getChunkSource().getGenerator(), + random, + pos, + null + ); + getFeature(blockState).place(context); + } + + @Override + public void randomTick(BlockState state, ServerLevel world, BlockPos pos, Random random) { + this.tick(state, world, pos, random); + } + + @Override + public void tick(BlockState state, ServerLevel world, BlockPos pos, Random random) { + super.tick(state, world, pos, random); + if (isBonemealSuccess(world, random, pos, state)) { + performBonemeal(world, random, pos, state); + } + } + + @Override + public BCLRenderLayer getRenderLayer() { + return BCLRenderLayer.CUTOUT; + } + + @Override + @Environment(EnvType.CLIENT) + public BlockModel getItemModel(ResourceLocation resourceLocation) { + return ModelsHelper.createBlockItem(resourceLocation); + } + + @Override + @Environment(EnvType.CLIENT) + public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) { + Optional pattern = PatternsHelper.createJson(BasePatterns.BLOCK_CROSS, resourceLocation); + return ModelsHelper.fromPattern(pattern); } @Override diff --git a/src/main/java/ru/bclib/blocks/FeatureSaplingBlockCommon.java b/src/main/java/ru/bclib/blocks/FeatureSaplingBlockCommon.java deleted file mode 100644 index fcc7f3af..00000000 --- a/src/main/java/ru/bclib/blocks/FeatureSaplingBlockCommon.java +++ /dev/null @@ -1,129 +0,0 @@ -package ru.bclib.blocks; - -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; -import net.minecraft.client.renderer.block.model.BlockModel; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SaplingBlock; -import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.feature.Feature; -import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; -import net.minecraft.world.level.material.Material; -import net.minecraft.world.level.storage.loot.LootContext; -import org.jetbrains.annotations.Nullable; -import ru.bclib.client.models.BasePatterns; -import ru.bclib.client.models.ModelsHelper; -import ru.bclib.client.models.PatternsHelper; -import ru.bclib.client.render.BCLRenderLayer; -import ru.bclib.interfaces.BlockModelProvider; -import ru.bclib.interfaces.RenderLayerProvider; - -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.Random; - -abstract class FeatureSaplingBlockCommon extends SaplingBlock implements RenderLayerProvider, BlockModelProvider { - public FeatureSaplingBlockCommon() { - super( - null, - FabricBlockSettings.of(Material.PLANT) - .breakByHand(true) - .collidable(false) - .instabreak() - .sound(SoundType.GRASS) - .randomTicks() - ); - } - - public FeatureSaplingBlockCommon(int light) { - super( - null, - FabricBlockSettings.of(Material.PLANT) - .breakByHand(true) - .collidable(false) - .luminance(light) - .instabreak() - .sound(SoundType.GRASS) - .randomTicks() - ); - } - - @Deprecated - /** - * Override {@link #getFeature(BlockState)} directly. Will be removed in 5.x - */ - protected Feature getFeature() { return null; } - - protected Feature getFeature(BlockState state){ - return getFeature(); - } - - @Override - public List getDrops(BlockState state, LootContext.Builder builder) { - return Collections.singletonList(new ItemStack(this)); - } - - @Override - public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) { - if (!canSurvive(state, world, pos)) return Blocks.AIR.defaultBlockState(); - else return state; - } - - @Override - public boolean isBonemealSuccess(Level world, Random random, BlockPos pos, BlockState state) { - return random.nextInt(16) == 0; - } - - @Override - public void advanceTree(ServerLevel world, BlockPos pos, BlockState blockState, Random random) { - FeaturePlaceContext context = new FeaturePlaceContext( - world, - world.getChunkSource().getGenerator(), - random, - pos, - null - ); - getFeature(blockState).place(context); - } - - @Override - public void randomTick(BlockState state, ServerLevel world, BlockPos pos, Random random) { - this.tick(state, world, pos, random); - } - - @Override - public void tick(BlockState state, ServerLevel world, BlockPos pos, Random random) { - super.tick(state, world, pos, random); - if (isBonemealSuccess(world, random, pos, state)) { - performBonemeal(world, random, pos, state); - } - } - - @Override - public BCLRenderLayer getRenderLayer() { - return BCLRenderLayer.CUTOUT; - } - - @Override - @Environment(EnvType.CLIENT) - public BlockModel getItemModel(ResourceLocation resourceLocation) { - return ModelsHelper.createBlockItem(resourceLocation); - } - - @Override - @Environment(EnvType.CLIENT) - public @Nullable BlockModel getBlockModel(ResourceLocation resourceLocation, BlockState blockState) { - Optional pattern = PatternsHelper.createJson(BasePatterns.BLOCK_CROSS, resourceLocation); - return ModelsHelper.fromPattern(pattern); - } -} diff --git a/src/main/java/ru/bclib/blocks/SimpleLeavesBlock.java b/src/main/java/ru/bclib/blocks/SimpleLeavesBlock.java index 4f4d1128..2f9ac66e 100644 --- a/src/main/java/ru/bclib/blocks/SimpleLeavesBlock.java +++ b/src/main/java/ru/bclib/blocks/SimpleLeavesBlock.java @@ -1,38 +1,55 @@ package ru.bclib.blocks; +import net.fabricmc.fabric.api.mininglevel.v1.FabricMineableTags; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; +import net.minecraft.tags.BlockTags; +import net.minecraft.tags.Tag.Named; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.material.Material; import net.minecraft.world.level.material.MaterialColor; import ru.bclib.api.TagAPI; import ru.bclib.client.render.BCLRenderLayer; import ru.bclib.interfaces.RenderLayerProvider; +import ru.bclib.interfaces.TagProvider; -public class SimpleLeavesBlock extends BaseBlockNotFull implements RenderLayerProvider { +import java.util.List; + +public class SimpleLeavesBlock extends BaseBlockNotFull implements RenderLayerProvider, TagProvider { public SimpleLeavesBlock(MaterialColor color) { - super(FabricBlockSettings.of(Material.LEAVES) - .strength(0.2F) - .mapColor(color) - .sound(SoundType.GRASS) - .noOcclusion() - .isValidSpawn((state, world, pos, type) -> false) - .isSuffocating((state, world, pos) -> false) - .isViewBlocking((state, world, pos) -> false)); - - TagAPI.addTags(this, TagAPI.BLOCK_LEAVES); + this( + FabricBlockSettings + .of(Material.LEAVES) + .strength(0.2F) + .color(color) + .sound(SoundType.GRASS) + .noOcclusion() + .isValidSpawn((state, world, pos, type) -> false) + .isSuffocating((state, world, pos) -> false) + .isViewBlocking((state, world, pos) -> false) + ); } public SimpleLeavesBlock(MaterialColor color, int light) { - super(FabricBlockSettings.of(Material.LEAVES) - .luminance(light) - .mapColor(color) - .strength(0.2F) - .sound(SoundType.GRASS) - .noOcclusion() - .isValidSpawn((state, world, pos, type) -> false) - .isSuffocating((state, world, pos) -> false) - .isViewBlocking((state, world, pos) -> false)); - + this( + FabricBlockSettings + .of(Material.LEAVES) + .luminance(light) + .color(color) + .strength(0.2F) + .sound(SoundType.GRASS) + .noOcclusion() + .isValidSpawn((state, world, pos, type) -> false) + .isSuffocating((state, world, pos) -> false) + .isViewBlocking((state, world, pos) -> false) + ); + } + + public SimpleLeavesBlock(BlockBehaviour.Properties properties) { + super(properties); + // TODO handle all tags instead of adding them like this TagAPI.addTags(this, TagAPI.BLOCK_LEAVES); } @@ -40,4 +57,11 @@ public class SimpleLeavesBlock extends BaseBlockNotFull implements RenderLayerPr public BCLRenderLayer getRenderLayer() { return BCLRenderLayer.CUTOUT; } + + @Override + public void addTags(List> blockTags, List> itemTags) { + blockTags.add(FabricMineableTags.SHEARS_MINEABLE); + blockTags.add(TagAPI.MINEABLE_HOE); + blockTags.add(BlockTags.LEAVES); + } } \ No newline at end of file diff --git a/src/main/java/ru/bclib/blocks/StalactiteBlock.java b/src/main/java/ru/bclib/blocks/StalactiteBlock.java index be53dd4f..944b8b79 100644 --- a/src/main/java/ru/bclib/blocks/StalactiteBlock.java +++ b/src/main/java/ru/bclib/blocks/StalactiteBlock.java @@ -22,6 +22,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.LiquidBlockContainer; import net.minecraft.world.level.block.SimpleWaterloggedBlock; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.BlockStateProperties; @@ -50,11 +51,12 @@ public class StalactiteBlock extends BaseBlockNotFull implements SimpleWaterlogg private static final VoxelShape[] SHAPES; public StalactiteBlock(Block source) { - super(FabricBlockSettings.copy(source).noOcclusion()); - this.registerDefaultState(getStateDefinition().any() - .setValue(SIZE, 0) - .setValue(IS_FLOOR, true) - .setValue(WATERLOGGED, false)); + this(FabricBlockSettings.copy(source).noOcclusion()); + } + + public StalactiteBlock(BlockBehaviour.Properties properties) { + super(properties); + this.registerDefaultState(getStateDefinition().any().setValue(SIZE, 0).setValue(IS_FLOOR, true).setValue(WATERLOGGED, false)); } @Override diff --git a/src/main/java/ru/bclib/blocks/StripableBarkBlock.java b/src/main/java/ru/bclib/blocks/StripableBarkBlock.java index d87f973a..328c6f1d 100644 --- a/src/main/java/ru/bclib/blocks/StripableBarkBlock.java +++ b/src/main/java/ru/bclib/blocks/StripableBarkBlock.java @@ -20,7 +20,7 @@ public class StripableBarkBlock extends BaseBarkBlock { private final Block striped; public StripableBarkBlock(MaterialColor color, Block striped) { - super(FabricBlockSettings.copyOf(striped).mapColor(color)); + super(FabricBlockSettings.copyOf(striped).color(color)); this.striped = striped; } diff --git a/src/main/java/ru/bclib/blocks/UnderwaterPlantBlock.java b/src/main/java/ru/bclib/blocks/UnderwaterPlantBlock.java index 957ee59d..4a12e548 100644 --- a/src/main/java/ru/bclib/blocks/UnderwaterPlantBlock.java +++ b/src/main/java/ru/bclib/blocks/UnderwaterPlantBlock.java @@ -1,12 +1,15 @@ package ru.bclib.blocks; import com.google.common.collect.Lists; +import net.fabricmc.fabric.api.mininglevel.v1.FabricMineableTags; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.Tag.Named; import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.item.enchantment.Enchantments; @@ -30,31 +33,36 @@ import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; +import ru.bclib.api.TagAPI; import ru.bclib.client.render.BCLRenderLayer; import ru.bclib.interfaces.RenderLayerProvider; +import ru.bclib.interfaces.TagProvider; import java.util.List; import java.util.Random; -@SuppressWarnings("deprecation") -public abstract class UnderwaterPlantBlock extends BaseBlockNotFull implements RenderLayerProvider, BonemealableBlock, LiquidBlockContainer { +public abstract class UnderwaterPlantBlock extends BaseBlockNotFull implements RenderLayerProvider, BonemealableBlock, LiquidBlockContainer, TagProvider { private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 14, 12); public UnderwaterPlantBlock() { - super(FabricBlockSettings.of(Material.WATER_PLANT) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .sound(SoundType.WET_GRASS) - .noCollission()); + this( + FabricBlockSettings + .of(Material.WATER_PLANT) + .breakByHand(true) + .sound(SoundType.WET_GRASS) + .noCollission() + ); } public UnderwaterPlantBlock(int light) { - super(FabricBlockSettings.of(Material.WATER_PLANT) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .luminance(light) - .sound(SoundType.WET_GRASS) - .noCollission()); + this( + FabricBlockSettings + .of(Material.WATER_PLANT) + .breakByHand(true) + .luminance(light) + .sound(SoundType.WET_GRASS) + .noCollission() + ); } public UnderwaterPlantBlock(Properties settings) { @@ -62,6 +70,7 @@ public abstract class UnderwaterPlantBlock extends BaseBlockNotFull implements R } @Override + @SuppressWarnings("deprecation") public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) { Vec3 vec3d = state.getOffset(view, pos); return SHAPE.move(vec3d.x, vec3d.y, vec3d.z); @@ -73,6 +82,7 @@ public abstract class UnderwaterPlantBlock extends BaseBlockNotFull implements R } @Override + @SuppressWarnings("deprecation") public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { BlockState down = world.getBlockState(pos.below()); state = world.getBlockState(pos); @@ -82,6 +92,7 @@ public abstract class UnderwaterPlantBlock extends BaseBlockNotFull implements R protected abstract boolean isTerrain(BlockState state); @Override + @SuppressWarnings("deprecation") public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) { if (!canSurvive(state, world, pos)) { world.destroyBlock(pos, true); @@ -144,7 +155,14 @@ public abstract class UnderwaterPlantBlock extends BaseBlockNotFull implements R } @Override + @SuppressWarnings("deprecation") public FluidState getFluidState(BlockState state) { return Fluids.WATER.getSource(false); } + + @Override + public void addTags(List> blockTags, List> itemTags) { + blockTags.add(FabricMineableTags.SHEARS_MINEABLE); + blockTags.add(TagAPI.MINEABLE_HOE); + } } diff --git a/src/main/java/ru/bclib/blocks/UnderwaterPlantWithAgeBlock.java b/src/main/java/ru/bclib/blocks/UnderwaterPlantWithAgeBlock.java index a2ad3dd0..e5ba1b6b 100644 --- a/src/main/java/ru/bclib/blocks/UnderwaterPlantWithAgeBlock.java +++ b/src/main/java/ru/bclib/blocks/UnderwaterPlantWithAgeBlock.java @@ -1,7 +1,6 @@ package ru.bclib.blocks; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; -import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.WorldGenLevel; @@ -18,12 +17,14 @@ public abstract class UnderwaterPlantWithAgeBlock extends UnderwaterPlantBlock { public static final IntegerProperty AGE = BlockProperties.AGE; public UnderwaterPlantWithAgeBlock() { - super(FabricBlockSettings.of(Material.WATER_PLANT) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .sound(SoundType.WET_GRASS) - .randomTicks() - .noCollission()); + super( + FabricBlockSettings + .of(Material.WATER_PLANT) + .breakByHand(true) + .sound(SoundType.WET_GRASS) + .randomTicks() + .noCollission() + ); } @Override diff --git a/src/main/java/ru/bclib/blocks/UpDownPlantBlock.java b/src/main/java/ru/bclib/blocks/UpDownPlantBlock.java index 758f06e5..21f3cabe 100644 --- a/src/main/java/ru/bclib/blocks/UpDownPlantBlock.java +++ b/src/main/java/ru/bclib/blocks/UpDownPlantBlock.java @@ -1,11 +1,14 @@ package ru.bclib.blocks; import com.google.common.collect.Lists; +import net.fabricmc.fabric.api.mininglevel.v1.FabricMineableTags; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.tags.Tag.Named; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.item.enchantment.Enchantments; @@ -17,37 +20,46 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Material; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; +import ru.bclib.api.TagAPI; import ru.bclib.client.render.BCLRenderLayer; import ru.bclib.interfaces.RenderLayerProvider; +import ru.bclib.interfaces.TagProvider; import java.util.List; -@SuppressWarnings("deprecation") -public abstract class UpDownPlantBlock extends BaseBlockNotFull implements RenderLayerProvider { +public abstract class UpDownPlantBlock extends BaseBlockNotFull implements RenderLayerProvider, TagProvider { private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 16, 12); public UpDownPlantBlock() { - super(FabricBlockSettings.of(Material.PLANT) - .breakByTool(FabricToolTags.SHEARS) - .breakByHand(true) - .sound(SoundType.GRASS) - .noCollission()); + this(FabricBlockSettings + .of(Material.PLANT) + .breakByHand(true) + .sound(SoundType.GRASS) + .noCollission() + ); + } + + public UpDownPlantBlock(BlockBehaviour.Properties properties) { + super(properties); } protected abstract boolean isTerrain(BlockState state); @Override + @SuppressWarnings("deprecation") public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) { return SHAPE; } @Override + @SuppressWarnings("deprecation") public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { BlockState down = world.getBlockState(pos.below()); BlockState up = world.getBlockState(pos.above()); @@ -59,6 +71,7 @@ public abstract class UpDownPlantBlock extends BaseBlockNotFull implements Rende } @Override + @SuppressWarnings("deprecation") public BlockState updateShape(BlockState state, Direction facing, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) { if (!canSurvive(state, world, pos)) { return Blocks.AIR.defaultBlockState(); @@ -92,4 +105,10 @@ public abstract class UpDownPlantBlock extends BaseBlockNotFull implements Rende super.playerDestroy(world, player, pos, state, blockEntity, stack); world.neighborChanged(pos, Blocks.AIR, pos.below()); } + + @Override + public void addTags(List> blockTags, List> itemTags) { + blockTags.add(FabricMineableTags.SHEARS_MINEABLE); + blockTags.add(TagAPI.MINEABLE_HOE); + } } diff --git a/src/main/java/ru/bclib/blocks/WallMushroomBlock.java b/src/main/java/ru/bclib/blocks/WallMushroomBlock.java index a4aabaf3..6c3379a0 100644 --- a/src/main/java/ru/bclib/blocks/WallMushroomBlock.java +++ b/src/main/java/ru/bclib/blocks/WallMushroomBlock.java @@ -2,12 +2,12 @@ package ru.bclib.blocks; import com.google.common.collect.Lists; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; -import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Material; import net.minecraft.world.level.storage.loot.LootContext; @@ -16,14 +16,20 @@ import java.util.List; public abstract class WallMushroomBlock extends BaseWallPlantBlock { public WallMushroomBlock(int light) { - super(FabricBlockSettings.of(Material.PLANT) - .breakByTool(FabricToolTags.AXES) - .breakByHand(true) - .luminance(light) - .hardness(0.2F) - .sound(SoundType.GRASS) - .sound(SoundType.WOOD) - .noCollission()); + this( + FabricBlockSettings + .of(Material.PLANT) + .breakByHand(true) + .luminance(light) + .destroyTime(0.2F) + .sound(SoundType.GRASS) + .sound(SoundType.WOOD) + .noCollission() + ); + } + + public WallMushroomBlock(BlockBehaviour.Properties properties) { + super(properties); } @Override diff --git a/src/main/java/ru/bclib/blocks/properties/StringProperty.java b/src/main/java/ru/bclib/blocks/properties/StringProperty.java deleted file mode 100644 index 8aaff298..00000000 --- a/src/main/java/ru/bclib/blocks/properties/StringProperty.java +++ /dev/null @@ -1,61 +0,0 @@ -package ru.bclib.blocks.properties; - -import com.google.common.collect.Sets; -import net.minecraft.world.level.block.state.properties.Property; - -import java.util.Collection; -import java.util.Collections; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - -@Deprecated -public class StringProperty extends Property { - private final Set values; - - public static StringProperty create(String name, String... values) { - return new StringProperty(name, values); - } - - protected StringProperty(String string, String... values) { - super(string, String.class); - this.values = Sets.newHashSet(values); - } - - public void addValue(String name) { - values.add(name); - } - - @Override - public Collection getPossibleValues() { - return Collections.unmodifiableSet(values); - } - - @Override - public String getName(String comparable) { - return comparable; - } - - @Override - public Optional getValue(String string) { - if (values.contains(string)) { - return Optional.of(string); - } - else { - return Optional.empty(); - } - } - - @Override - public int generateHashCode() { - return super.generateHashCode() + Objects.hashCode(values); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof StringProperty that)) return false; - if (!super.equals(o)) return false; - return values.equals(that.values); - } -} diff --git a/src/main/java/ru/bclib/client/render/CustomBackgroundRenderer.java b/src/main/java/ru/bclib/client/render/CustomBackgroundRenderer.java index 1828ad51..c26d4e5a 100644 --- a/src/main/java/ru/bclib/client/render/CustomBackgroundRenderer.java +++ b/src/main/java/ru/bclib/client/render/CustomBackgroundRenderer.java @@ -13,7 +13,7 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.material.FogType; -import ru.bclib.api.BiomeAPI; +import ru.bclib.api.biomes.BiomeAPI; import ru.bclib.util.BackgroundInfo; import ru.bclib.util.MHelper; import ru.bclib.world.biomes.BCLBiome; diff --git a/src/main/java/ru/bclib/config/Configs.java b/src/main/java/ru/bclib/config/Configs.java index deac17d2..1e82f759 100644 --- a/src/main/java/ru/bclib/config/Configs.java +++ b/src/main/java/ru/bclib/config/Configs.java @@ -26,12 +26,12 @@ public class Configs { MAIN_CONFIG.saveChanges(); RECIPE_CONFIG.saveChanges(); GENERATOR_CONFIG.saveChanges(); - initForcedConfig(); - } - - private static void initForcedConfig() { - BIOMES_CONFIG.keeper.registerEntry(new ConfigKey("end_biomes", "force_include"), new StringArrayEntry(Collections.EMPTY_LIST)); - BIOMES_CONFIG.keeper.registerEntry(new ConfigKey("nether_biomes", "force_include"), new StringArrayEntry(Collections.EMPTY_LIST)); BIOMES_CONFIG.saveChanges(); } + + static { + BIOMES_CONFIG.keeper.registerEntry(new ConfigKey("end_land_biomes", "force_include"), new StringArrayEntry(Collections.EMPTY_LIST)); + BIOMES_CONFIG.keeper.registerEntry(new ConfigKey("end_void_biomes", "force_include"), new StringArrayEntry(Collections.EMPTY_LIST)); + BIOMES_CONFIG.keeper.registerEntry(new ConfigKey("nether_biomes", "force_include"), new StringArrayEntry(Collections.EMPTY_LIST)); + } } diff --git a/src/main/java/ru/bclib/integration/ModIntegration.java b/src/main/java/ru/bclib/integration/ModIntegration.java index 869edc61..1c26e8c7 100644 --- a/src/main/java/ru/bclib/integration/ModIntegration.java +++ b/src/main/java/ru/bclib/integration/ModIntegration.java @@ -1,6 +1,6 @@ package ru.bclib.integration; -import net.fabricmc.fabric.api.tag.TagRegistry; +import net.fabricmc.fabric.api.tag.TagFactory; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.core.Registry; import net.minecraft.data.BuiltinRegistries; @@ -17,6 +17,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.GenerationStep; import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; import net.minecraft.world.level.levelgen.feature.Feature; +import net.minecraft.world.level.levelgen.placement.PlacedFeature; import ru.bclib.BCLib; import ru.bclib.world.features.BCLFeature; @@ -58,9 +59,9 @@ public abstract class ModIntegration { return FabricLoader.getInstance().isModLoaded(modID); } - public BCLFeature getFeature(String featureID, String configuredFeatureID, GenerationStep.Decoration featureStep) { + public BCLFeature getFeature(String featureID, String placedFeatureID, GenerationStep.Decoration featureStep) { Feature feature = Registry.FEATURE.get(getID(featureID)); - ConfiguredFeature featureConfigured = BuiltinRegistries.CONFIGURED_FEATURE.get(getID(configuredFeatureID)); + PlacedFeature featureConfigured = BuiltinRegistries.PLACED_FEATURE.get(getID(placedFeatureID)); return new BCLFeature(feature, featureConfigured, featureStep); } @@ -198,12 +199,15 @@ public abstract class ModIntegration { public Tag.Named getItemTag(String name) { ResourceLocation id = getID(name); Tag tag = ItemTags.getAllTags().getTag(id); - return tag == null ? (Named) TagRegistry.item(id) : (Named) tag; + + //return tag == null ? (Named) TagRegistry.item(id) : (Named) tag; + return tag == null ? (Named) TagFactory.ITEM.create(id) : (Named) tag; } public Tag.Named getBlockTag(String name) { ResourceLocation id = getID(name); Tag tag = BlockTags.getAllTags().getTag(id); - return tag == null ? (Named) TagRegistry.block(id) : (Named) tag; + //return tag == null ? (Named) TagRegistry.block(id) : (Named) tag; + return tag == null ? (Named) TagFactory.BLOCK.create(id) : (Named) tag; } } diff --git a/src/main/java/ru/bclib/interfaces/BiomeMap.java b/src/main/java/ru/bclib/interfaces/BiomeMap.java new file mode 100644 index 00000000..89d79521 --- /dev/null +++ b/src/main/java/ru/bclib/interfaces/BiomeMap.java @@ -0,0 +1,9 @@ +package ru.bclib.interfaces; + +import ru.bclib.world.biomes.BCLBiome; + +public interface BiomeMap { + void clearCache(); + + BCLBiome getBiome(double x, double z); +} diff --git a/src/main/java/ru/bclib/interfaces/SurfaceRuleProvider.java b/src/main/java/ru/bclib/interfaces/SurfaceRuleProvider.java new file mode 100644 index 00000000..214fd851 --- /dev/null +++ b/src/main/java/ru/bclib/interfaces/SurfaceRuleProvider.java @@ -0,0 +1,9 @@ +package ru.bclib.interfaces; + +import net.minecraft.world.level.levelgen.SurfaceRules; + +public interface SurfaceRuleProvider { + void setSurfaceRule(SurfaceRules.RuleSource surfaceRule); + + SurfaceRules.RuleSource getSurfaceRule(); +} diff --git a/src/main/java/ru/bclib/interfaces/TagProvider.java b/src/main/java/ru/bclib/interfaces/TagProvider.java new file mode 100644 index 00000000..3f0ede66 --- /dev/null +++ b/src/main/java/ru/bclib/interfaces/TagProvider.java @@ -0,0 +1,12 @@ +package ru.bclib.interfaces; + +import net.minecraft.tags.Tag; +import net.minecraft.tags.Tag.Named; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; + +import java.util.List; + +public interface TagProvider { + void addTags(List> blockTags, List> itemTags); +} diff --git a/src/main/java/ru/bclib/mixin/client/MinecraftMixin.java b/src/main/java/ru/bclib/mixin/client/MinecraftMixin.java index f1cb2523..6c884bcf 100644 --- a/src/main/java/ru/bclib/mixin/client/MinecraftMixin.java +++ b/src/main/java/ru/bclib/mixin/client/MinecraftMixin.java @@ -22,6 +22,7 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import ru.bclib.api.LifeCycleAPI; import ru.bclib.api.dataexchange.DataExchangeAPI; import ru.bclib.api.datafixer.DataFixerAPI; import ru.bclib.interfaces.CustomColorProvider; @@ -61,14 +62,18 @@ public abstract class MinecraftMixin { DataExchangeAPI.prepareServerside(); if (DataFixerAPI.fixData(this.levelSource, levelID, true, (appliedFixes) -> { + LifeCycleAPI._runBeforeLevelLoad(); this.doLoadLevel(levelID, RegistryAccess.builtin(), Minecraft::loadDataPacks, Minecraft::loadWorldData, false, appliedFixes?ExperimentalDialogType.NONE:ExperimentalDialogType.BACKUP); })) { ci.cancel(); + } else { + LifeCycleAPI._runBeforeLevelLoad(); } } @Inject(method = "createLevel", at = @At("HEAD")) private void bclib_initPatchData(String levelID, LevelSettings levelSettings, RegistryHolder registryHolder, WorldGenSettings worldGenSettings, CallbackInfo ci) { DataFixerAPI.initializeWorldData(this.levelSource, levelID, true); + LifeCycleAPI._runBeforeLevelLoad(); } } diff --git a/src/main/java/ru/bclib/mixin/common/BiomeGenerationSettingsAccessor.java b/src/main/java/ru/bclib/mixin/common/BiomeGenerationSettingsAccessor.java new file mode 100644 index 00000000..fcb6ec6f --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/BiomeGenerationSettingsAccessor.java @@ -0,0 +1,37 @@ +package ru.bclib.mixin.common; + +import net.minecraft.world.level.biome.BiomeGenerationSettings; +import net.minecraft.world.level.levelgen.GenerationStep; +import net.minecraft.world.level.levelgen.GenerationStep.Carving; +import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver; +import net.minecraft.world.level.levelgen.placement.PlacedFeature; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +@Mixin(BiomeGenerationSettings.class) +public interface BiomeGenerationSettingsAccessor { + @Accessor("features") + List>> bclib_getFeatures(); + + @Accessor("features") + @Mutable + void bclib_setFeatures(List>> value); + + @Accessor("featureSet") + Set bclib_getFeatureSet(); + + @Accessor("featureSet") + void bclib_setFeatureSet(Set features); + + @Accessor("carvers") + Map>>> bclib_getCarvers(); + + @Accessor("carvers") + void bclib_setCarvers(Map>>> features); +} diff --git a/src/main/java/ru/bclib/mixin/common/BiomeMixin.java b/src/main/java/ru/bclib/mixin/common/BiomeMixin.java deleted file mode 100644 index 26f16bcb..00000000 --- a/src/main/java/ru/bclib/mixin/common/BiomeMixin.java +++ /dev/null @@ -1,28 +0,0 @@ -package ru.bclib.mixin.common; - -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.WorldGenRegion; -import net.minecraft.world.level.StructureFeatureManager; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.chunk.ChunkGenerator; -import net.minecraft.world.level.levelgen.WorldgenRandom; -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.ModifyArg; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(Biome.class) -public class BiomeMixin { - private int bclib_featureIteratorSeed; - - @ModifyArg(method = "generate", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/WorldgenRandom;setFeatureSeed(JII)J")) - private long bclib_updateFeatureSeed(long seed) { - return Long.rotateRight(seed, bclib_featureIteratorSeed++); - } - - @Inject(method = "generate", at = @At("HEAD")) - private void bclib_obBiomeGenerate(StructureFeatureManager structureFeatureManager, ChunkGenerator chunkGenerator, WorldGenRegion worldGenRegion, long l, WorldgenRandom worldgenRandom, BlockPos blockPos, CallbackInfo info) { - bclib_featureIteratorSeed = 0; - } -} diff --git a/src/main/java/ru/bclib/mixin/common/BoneMealItemMixin.java b/src/main/java/ru/bclib/mixin/common/BoneMealItemMixin.java index 52357c1a..1ad99193 100644 --- a/src/main/java/ru/bclib/mixin/common/BoneMealItemMixin.java +++ b/src/main/java/ru/bclib/mixin/common/BoneMealItemMixin.java @@ -15,8 +15,8 @@ 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 ru.bclib.api.BiomeAPI; import ru.bclib.api.BonemealAPI; +import ru.bclib.api.biomes.BiomeAPI; import ru.bclib.util.BlocksHelper; import ru.bclib.util.MHelper; diff --git a/src/main/java/ru/bclib/mixin/common/ChunkBiomeContainerMixin.java b/src/main/java/ru/bclib/mixin/common/ChunkBiomeContainerMixin.java deleted file mode 100644 index 3ad2c2a8..00000000 --- a/src/main/java/ru/bclib/mixin/common/ChunkBiomeContainerMixin.java +++ /dev/null @@ -1,134 +0,0 @@ -package ru.bclib.mixin.common; - -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.core.BlockPos; -import net.minecraft.util.BitStorage; -import net.minecraft.util.Mth; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.chunk.ChunkBiomeContainer; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import ru.bclib.BCLib; -import ru.bclib.interfaces.BiomeSetter; - -import java.lang.reflect.Field; - -@Mixin(ChunkBiomeContainer.class) -public class ChunkBiomeContainerMixin implements BiomeSetter { - private static boolean bclib_hasHydrogen = FabricLoader.getInstance().isModLoaded("hydrogen"); - - @Final - @Shadow - private Biome[] biomes; - - @Final - @Shadow - private static int WIDTH_BITS; - - @Final - @Shadow - private static int HORIZONTAL_MASK; - - @Override - public void bclib_setBiome(Biome biome, BlockPos pos) { - int biomeX = pos.getX() >> 2; - int biomeY = pos.getY() >> 2; - int biomeZ = pos.getZ() >> 2; - int index = be_getArrayIndex(biomeX, biomeY, biomeZ); - - if (bclib_hasHydrogen && be_shouldWriteToHydrogen()) { - try { - ChunkBiomeContainer self = (ChunkBiomeContainer) (Object) this; - BitStorage storage = be_getHydrogenStorage(self); - Biome[] palette = be_getHydrogenPalette(self); - int paletteIndex = be_getHydrogenPaletteIndex(biome, palette); - if (paletteIndex == -1) { - Biome[] newPalette = new Biome[palette.length + 1]; - System.arraycopy(palette, 0, newPalette, 0, palette.length); - paletteIndex = palette.length; - palette = newPalette; - palette[paletteIndex] = biome; - be_setHydrogenPalette(self, palette); - } - try { - storage.set(index, paletteIndex); - } - catch (Exception e) { - int size = storage.getSize(); - int bits = Mth.ceillog2(palette.length); - BitStorage newStorage = new BitStorage(bits, size); - for (int i = 0; i < size; i++) { - newStorage.set(i, storage.get(i)); - } - storage = newStorage; - storage.set(index, paletteIndex); - be_setHydrogenStorage(self, storage); - } - } - catch (Exception e) { - BCLib.LOGGER.warning(e.getLocalizedMessage()); - } - return; - } - - biomes[index] = biome; - } - - @Shadow - @Final - private int quartMinY; - @Shadow - @Final - private int quartHeight; - - private boolean be_shouldWriteToHydrogen() { - try { - Field field = ChunkBiomeContainer.class.getDeclaredField("intArray"); - return field != null; - } - catch (NoSuchFieldException e) { - return false; - } - } - - private int be_getArrayIndex(int biomeX, int biomeY, int biomeZ) { - int i = biomeX & HORIZONTAL_MASK; - int j = Mth.clamp(biomeY - this.quartMinY, 0, this.quartHeight); - int k = biomeZ & HORIZONTAL_MASK; - return j << WIDTH_BITS + WIDTH_BITS | k << WIDTH_BITS | i; - } - - private Field be_getField(String name) throws Exception { - Field field = ChunkBiomeContainer.class.getDeclaredField(name); - field.setAccessible(true); - return field; - } - - private BitStorage be_getHydrogenStorage(ChunkBiomeContainer container) throws Exception { - return (BitStorage) be_getField("intArray").get(container); - } - - private Biome[] be_getHydrogenPalette(ChunkBiomeContainer container) throws Exception { - return (Biome[]) be_getField("palette").get(container); - } - - private int be_getHydrogenPaletteIndex(Biome biome, Biome[] palette) { - int index = -1; - for (int i = 0; i < palette.length; i++) { - if (palette[i] == biome) { - index = i; - break; - } - } - return index; - } - - private void be_setHydrogenPalette(ChunkBiomeContainer container, Biome[] palette) throws Exception { - be_getField("palette").set(container, palette); - } - - private void be_setHydrogenStorage(ChunkBiomeContainer container, BitStorage storage) throws Exception { - be_getField("intArray").set(container, storage); - } -} diff --git a/src/main/java/ru/bclib/mixin/common/ChunkGeneratorMixin.java b/src/main/java/ru/bclib/mixin/common/ChunkGeneratorMixin.java new file mode 100644 index 00000000..9c6058ac --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/ChunkGeneratorMixin.java @@ -0,0 +1,26 @@ +package ru.bclib.mixin.common; + +import net.minecraft.world.level.StructureFeatureManager; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkGenerator; +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.ModifyArg; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ChunkGenerator.class) +public class ChunkGeneratorMixin { + private int bclib_featureIteratorSeed; + + @ModifyArg(method = "applyBiomeDecoration", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/WorldgenRandom;setFeatureSeed(JII)V")) + private long bclib_updateFeatureSeed(long seed) { + return Long.rotateRight(seed, bclib_featureIteratorSeed++); + } + + @Inject(method = "applyBiomeDecoration", at = @At("HEAD")) + private void bclib_obBiomeGenerate(WorldGenLevel worldGenLevel, ChunkAccess chunkAccess, StructureFeatureManager structureFeatureManager, CallbackInfo ci) { + bclib_featureIteratorSeed = 0; + } +} diff --git a/src/main/java/ru/bclib/mixin/common/DimensionTypeMixin.java b/src/main/java/ru/bclib/mixin/common/DimensionTypeMixin.java index 7772d7f9..3b73c4bf 100644 --- a/src/main/java/ru/bclib/mixin/common/DimensionTypeMixin.java +++ b/src/main/java/ru/bclib/mixin/common/DimensionTypeMixin.java @@ -1,40 +1,63 @@ package ru.bclib.mixin.common; +import com.mojang.serialization.Lifecycle; +import net.minecraft.core.MappedRegistry; import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.levelgen.synth.NormalNoise; 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 org.spongepowered.asm.mixin.injection.callback.LocalCapture; import ru.bclib.world.generator.BCLibEndBiomeSource; import ru.bclib.world.generator.BCLibNetherBiomeSource; -import ru.bclib.world.generator.GeneratorOptions; -@Mixin(value = DimensionType.class, priority = 10) +import java.util.OptionalInt; + +@Mixin(DimensionType.class) public class DimensionTypeMixin { - @Inject(method = "defaultNetherGenerator", at = @At("HEAD"), cancellable = true) - private static void be_replaceNetherBiomeSource(Registry biomeRegistry, Registry chunkGeneratorSettingsRegistry, long seed, CallbackInfoReturnable info) { - if (GeneratorOptions.customNetherBiomeSource()) { - info.setReturnValue(new NoiseBasedChunkGenerator( - new BCLibNetherBiomeSource(biomeRegistry, seed), - seed, - () -> chunkGeneratorSettingsRegistry.getOrThrow(NoiseGeneratorSettings.NETHER) - )); - } + @Inject( + method = "defaultDimensions(Lnet/minecraft/core/RegistryAccess;JZ)Lnet/minecraft/core/MappedRegistry;", + locals = LocalCapture.CAPTURE_FAILHARD, + at = @At("TAIL") + ) + private static void bclib_updateDimensions(RegistryAccess registryAccess, long seed, boolean bl, CallbackInfoReturnable> info, MappedRegistry mappedRegistry, Registry registry, Registry biomeRegistry, Registry noiseSettingsRegistry, Registry noiseParamRegistry) { + int id = mappedRegistry.getId(mappedRegistry.get(LevelStem.NETHER)); + mappedRegistry.registerOrOverride( + OptionalInt.of(id), + LevelStem.NETHER, + new LevelStem( + () -> registry.getOrThrow(DimensionType.NETHER_LOCATION), + new NoiseBasedChunkGenerator( + noiseParamRegistry, + new BCLibNetherBiomeSource(biomeRegistry, seed), + seed, + () -> noiseSettingsRegistry.getOrThrow(NoiseGeneratorSettings.NETHER) + ) + ), + Lifecycle.stable() + ); + + id = mappedRegistry.getId(mappedRegistry.get(LevelStem.END)); + mappedRegistry.registerOrOverride( + OptionalInt.of(id), + LevelStem.END, + new LevelStem( + () -> registry.getOrThrow(DimensionType.END_LOCATION), + new NoiseBasedChunkGenerator( + noiseParamRegistry, + new BCLibEndBiomeSource(biomeRegistry, seed), + seed, + () -> noiseSettingsRegistry.getOrThrow(NoiseGeneratorSettings.END) + ) + ), + Lifecycle.stable() + ); } - - @Inject(method = "defaultEndGenerator", at = @At("HEAD"), cancellable = true) - private static void be_replaceEndBiomeSource(Registry biomeRegistry, Registry chunkGeneratorSettingsRegistry, long seed, CallbackInfoReturnable info) { - if (GeneratorOptions.customEndBiomeSource()) { - info.setReturnValue(new NoiseBasedChunkGenerator( - new BCLibEndBiomeSource(biomeRegistry, seed), - seed, - () -> chunkGeneratorSettingsRegistry.getOrThrow(NoiseGeneratorSettings.END) - )); - } - } -} \ No newline at end of file +} diff --git a/src/main/java/ru/bclib/mixin/common/FeatureDecoratorsAccessor.java b/src/main/java/ru/bclib/mixin/common/FeatureDecoratorsAccessor.java deleted file mode 100644 index 5e6ed7ad..00000000 --- a/src/main/java/ru/bclib/mixin/common/FeatureDecoratorsAccessor.java +++ /dev/null @@ -1,11 +0,0 @@ -package ru.bclib.mixin.common; - -import net.minecraft.world.level.levelgen.placement.ConfiguredDecorator; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -@Mixin(targets = "net.minecraft.data.worldgen.Features$Decorators") -public interface FeatureDecoratorsAccessor { - @Accessor("HEIGHTMAP_SQUARE") - ConfiguredDecorator bclib_getHeightmapSquare(); -} diff --git a/src/main/java/ru/bclib/mixin/common/InternalBiomeDataMixin.java b/src/main/java/ru/bclib/mixin/common/InternalBiomeDataMixin.java deleted file mode 100644 index 3f0e7c37..00000000 --- a/src/main/java/ru/bclib/mixin/common/InternalBiomeDataMixin.java +++ /dev/null @@ -1,40 +0,0 @@ -package ru.bclib.mixin.common; - -import net.fabricmc.fabric.impl.biome.InternalBiomeData; -import net.minecraft.resources.ResourceKey; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.Biomes; -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; -import ru.bclib.world.biomes.FabricBiomesData; - -@Mixin(value = InternalBiomeData.class, remap = false) -public class InternalBiomeDataMixin { - @Inject(method = "addEndBiomeReplacement", at = @At(value = "HEAD")) - private static void bclib_addEndBiomeReplacement(ResourceKey replaced, ResourceKey variant, double weight, CallbackInfo info) { - if (replaced == Biomes.END_BARRENS || replaced == Biomes.SMALL_END_ISLANDS) { - FabricBiomesData.END_VOID_BIOMES.put(variant, (float) weight); - } - else { - FabricBiomesData.END_LAND_BIOMES.put(variant, (float) weight); - } - } - - @Inject(method = "addEndMidlandsReplacement", at = @At(value = "HEAD")) - private static void bclib_addEndMidlandsReplacement(ResourceKey highlands, ResourceKey midlands, double weight, CallbackInfo info) { - FabricBiomesData.END_LAND_BIOMES.put(midlands, (float) weight); - } - - @Inject(method = "addEndBarrensReplacement", at = @At(value = "HEAD")) - private static void bclib_addEndBarrensReplacement(ResourceKey highlands, ResourceKey barrens, double weight, CallbackInfo info) { - FabricBiomesData.END_LAND_BIOMES.put(barrens, (float) weight); - FabricBiomesData.END_VOID_BIOMES.put(barrens, (float) weight); - } - - @Inject(method = "addNetherBiome", at = @At(value = "HEAD")) - private static void bclib_addNetherBiome(ResourceKey biome, Biome.ClimateParameters spawnNoisePoint, CallbackInfo info) { - FabricBiomesData.NETHER_BIOMES.add(biome); - } -} diff --git a/src/main/java/ru/bclib/mixin/common/MainMixin.java b/src/main/java/ru/bclib/mixin/common/MainMixin.java index 142aada1..059129e0 100644 --- a/src/main/java/ru/bclib/mixin/common/MainMixin.java +++ b/src/main/java/ru/bclib/mixin/common/MainMixin.java @@ -5,13 +5,15 @@ import net.minecraft.world.level.storage.LevelStorageSource; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.ModifyArg; +import ru.bclib.api.LifeCycleAPI; import ru.bclib.api.datafixer.DataFixerAPI; @Mixin(Main.class) abstract public class MainMixin { - @ModifyArg(method="main", at=@At(value="INVOKE", target="Lnet/minecraft/server/MinecraftServer;convertFromRegionFormatIfNeeded(Lnet/minecraft/world/level/storage/LevelStorageSource$LevelStorageAccess;)V")) + @ModifyArg(method="main", at=@At(value="INVOKE_ASSIGN", target="Lnet/minecraft/world/level/storage/LevelStorageSource$LevelStorageAccess;getSummary()Lnet/minecraft/world/level/storage/LevelSummary;")) private static LevelStorageSource.LevelStorageAccess bclib_callServerFix(LevelStorageSource.LevelStorageAccess session){ DataFixerAPI.fixData(session, false, (didFix)->{/* not called when showUI==false */}); + LifeCycleAPI._runBeforeLevelLoad(); return session; } } diff --git a/src/main/java/ru/bclib/mixin/common/MinecraftServerMixin.java b/src/main/java/ru/bclib/mixin/common/MinecraftServerMixin.java index e494a05f..e337b2c6 100644 --- a/src/main/java/ru/bclib/mixin/common/MinecraftServerMixin.java +++ b/src/main/java/ru/bclib/mixin/common/MinecraftServerMixin.java @@ -12,7 +12,6 @@ import net.minecraft.server.level.progress.ChunkProgressListenerFactory; import net.minecraft.server.packs.repository.PackRepository; import net.minecraft.server.players.GameProfileCache; import net.minecraft.world.level.Level; -import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.LevelStorageSource.LevelStorageAccess; import net.minecraft.world.level.storage.WorldData; import org.spongepowered.asm.mixin.Final; @@ -22,7 +21,6 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import ru.bclib.api.BiomeAPI; import ru.bclib.api.dataexchange.DataExchangeAPI; import ru.bclib.recipes.BCLRecipeManager; @@ -49,15 +47,6 @@ public class MinecraftServerMixin { DataExchangeAPI.prepareServerside(); } - @Inject(method = "convertFromRegionFormatIfNeeded", at = @At("HEAD")) - private static void bclib_applyPatches(LevelStorageSource.LevelStorageAccess session, CallbackInfo ci) { - - /*File levelPath = session.getLevelPath(LevelResource.ROOT).toFile(); - WorldDataAPI.load(new File(levelPath, "data")); - DataFixerAPI.fixData(levelPath, session.getLevelId());*/ - } - - @Inject(method = "reloadResources", at = @At(value = "RETURN"), cancellable = true) private void bclib_reloadResources(Collection collection, CallbackInfoReturnable> info) { bclib_injectRecipes(); @@ -66,7 +55,7 @@ public class MinecraftServerMixin { @Inject(method = "loadLevel", at = @At(value = "RETURN"), cancellable = true) private void bclib_loadLevel(CallbackInfo info) { bclib_injectRecipes(); - BiomeAPI.initRegistry(MinecraftServer.class.cast(this)); + //BiomeAPI.initRegistry(MinecraftServer.class.cast(this)); } private void bclib_injectRecipes() { diff --git a/src/main/java/ru/bclib/mixin/common/MobSpawnSettingsAccessor.java b/src/main/java/ru/bclib/mixin/common/MobSpawnSettingsAccessor.java new file mode 100644 index 00000000..e3491b73 --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/MobSpawnSettingsAccessor.java @@ -0,0 +1,21 @@ +package ru.bclib.mixin.common; + +import net.minecraft.util.random.WeightedRandomList; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.biome.MobSpawnSettings.SpawnerData; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(MobSpawnSettings.class) +public interface MobSpawnSettingsAccessor { + @Accessor("spawners") + Map> bcl_getSpawners(); + + @Accessor("spawners") + @Mutable + void bcl_setSpawners(Map> spawners); +} diff --git a/src/main/java/ru/bclib/mixin/common/NetherBiomeDataMixin.java b/src/main/java/ru/bclib/mixin/common/NetherBiomeDataMixin.java new file mode 100644 index 00000000..1a941711 --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/NetherBiomeDataMixin.java @@ -0,0 +1,19 @@ +package ru.bclib.mixin.common; + +import net.fabricmc.fabric.impl.biome.NetherBiomeData; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Climate; +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; +import ru.bclib.world.biomes.FabricBiomesData; + +@Mixin(value = NetherBiomeData.class, remap = false) +public class NetherBiomeDataMixin { + @Inject(method = "addNetherBiome", at = @At(value = "HEAD")) + private static void bclib_addNetherBiome(ResourceKey biome, Climate.ParameterPoint spawnNoisePoint, CallbackInfo info) { + FabricBiomesData.NETHER_BIOMES.add(biome); + } +} diff --git a/src/main/java/ru/bclib/mixin/common/NoiseGeneratorSettingsMixin.java b/src/main/java/ru/bclib/mixin/common/NoiseGeneratorSettingsMixin.java new file mode 100644 index 00000000..267df1f6 --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/NoiseGeneratorSettingsMixin.java @@ -0,0 +1,38 @@ +package ru.bclib.mixin.common; + +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.levelgen.SurfaceRules; +import net.minecraft.world.level.levelgen.SurfaceRules.RuleSource; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import ru.bclib.interfaces.SurfaceRuleProvider; + +@Mixin(NoiseGeneratorSettings.class) +public class NoiseGeneratorSettingsMixin implements SurfaceRuleProvider { + @Final + @Shadow + private SurfaceRules.RuleSource surfaceRule; + + private SurfaceRules.RuleSource bclib_surfaceRule; + + @Override + public void setSurfaceRule(SurfaceRules.RuleSource surfaceRule) { + bclib_surfaceRule = surfaceRule; + } + + @Override + public RuleSource getSurfaceRule() { + return surfaceRule; + } + + @Inject(method = "surfaceRule", at = @At("HEAD"), cancellable = true) + private void bclib_surfaceRule(CallbackInfoReturnable info) { + if (bclib_surfaceRule != null) { + info.setReturnValue(bclib_surfaceRule); + } + } +} diff --git a/src/main/java/ru/bclib/mixin/common/ServerLevelMixin.java b/src/main/java/ru/bclib/mixin/common/ServerLevelMixin.java index 91c2c4d2..d405536a 100644 --- a/src/main/java/ru/bclib/mixin/common/ServerLevelMixin.java +++ b/src/main/java/ru/bclib/mixin/common/ServerLevelMixin.java @@ -1,9 +1,5 @@ package ru.bclib.mixin.common; -import java.util.List; -import java.util.concurrent.Executor; -import java.util.function.Supplier; - import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -13,15 +9,19 @@ import net.minecraft.world.level.CustomSpawner; import net.minecraft.world.level.Level; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.storage.LevelStorageSource; +import net.minecraft.world.level.storage.LevelStorageSource.LevelStorageAccess; import net.minecraft.world.level.storage.ServerLevelData; import net.minecraft.world.level.storage.WritableLevelData; 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; -import ru.bclib.api.BiomeAPI; import ru.bclib.api.LifeCycleAPI; +import ru.bclib.api.biomes.BiomeAPI; + +import java.util.List; +import java.util.concurrent.Executor; +import java.util.function.Supplier; @Mixin(ServerLevel.class) public abstract class ServerLevelMixin extends Level { @@ -32,18 +32,18 @@ public abstract class ServerLevelMixin extends Level { } @Inject(method = "*", at = @At("TAIL")) - private void bclib_onServerWorldInit(MinecraftServer server, Executor workerExecutor, LevelStorageSource.LevelStorageAccess session, ServerLevelData properties, ResourceKey registryKey, DimensionType dimensionType, ChunkProgressListener worldGenerationProgressListener, ChunkGenerator chunkGenerator, boolean debugWorld, long l, List list, boolean bl, CallbackInfo info) { + private void bclib_onServerWorldInit(MinecraftServer server, Executor executor, LevelStorageAccess levelStorageAccess, ServerLevelData serverLevelData, ResourceKey resourceKey, DimensionType dimensionType, ChunkProgressListener chunkProgressListener, ChunkGenerator chunkGenerator, boolean bl, long l, List list, boolean bl2, CallbackInfo info) { ServerLevel world = ServerLevel.class.cast(this); - LifeCycleAPI._runLevelLoad(world, server, workerExecutor, session, properties, registryKey, dimensionType, worldGenerationProgressListener, chunkGenerator, debugWorld, l, list, bl); + LifeCycleAPI._runLevelLoad(world, server, executor, levelStorageAccess, serverLevelData, resourceKey, dimensionType, chunkProgressListener, chunkGenerator, bl, l, list, bl2); - BiomeAPI.initRegistry(server); + //BiomeAPI.initRegistry(server); BiomeAPI.applyModifications(ServerLevel.class.cast(this)); - if (bclib_lastWorld != null && bclib_lastWorld.equals(session.getLevelId())) { + if (bclib_lastWorld != null && bclib_lastWorld.equals(levelStorageAccess.getLevelId())) { return; } - bclib_lastWorld = session.getLevelId(); + bclib_lastWorld = levelStorageAccess.getLevelId(); } diff --git a/src/main/java/ru/bclib/mixin/common/StructureSettingsAccessor.java b/src/main/java/ru/bclib/mixin/common/StructureSettingsAccessor.java new file mode 100644 index 00000000..cb323706 --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/StructureSettingsAccessor.java @@ -0,0 +1,22 @@ +package ru.bclib.mixin.common; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.levelgen.StructureSettings; +import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; +import net.minecraft.world.level.levelgen.feature.StructureFeature; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(StructureSettings.class) +public interface StructureSettingsAccessor { + @Accessor("configuredStructures") + ImmutableMap, ImmutableMultimap, ResourceKey>> bcl_getStructureConfig(); + + @Accessor("configuredStructures") + @Mutable + void bcl_setStructureConfig(ImmutableMap, ImmutableMultimap, ResourceKey>> structureConfig); +} diff --git a/src/main/java/ru/bclib/mixin/common/TheEndBiomeDataMixin.java b/src/main/java/ru/bclib/mixin/common/TheEndBiomeDataMixin.java new file mode 100644 index 00000000..93bca16f --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/TheEndBiomeDataMixin.java @@ -0,0 +1,35 @@ +package ru.bclib.mixin.common; + +import net.fabricmc.fabric.impl.biome.TheEndBiomeData; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; +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; +import ru.bclib.world.biomes.FabricBiomesData; + +@Mixin(value = TheEndBiomeData.class, remap = false) +public class TheEndBiomeDataMixin { + @Inject(method = "addEndBiomeReplacement", at = @At(value = "HEAD")) + private static void bclib_addEndBiomeReplacement(ResourceKey replaced, ResourceKey variant, double weight, CallbackInfo info) { + if (replaced == Biomes.END_BARRENS || replaced == Biomes.SMALL_END_ISLANDS) { + FabricBiomesData.END_VOID_BIOMES.put(variant, (float) weight); + } + else { + FabricBiomesData.END_LAND_BIOMES.put(variant, (float) weight); + } + } + + @Inject(method = "addEndMidlandsReplacement", at = @At(value = "HEAD")) + private static void bclib_addEndMidlandsReplacement(ResourceKey highlands, ResourceKey midlands, double weight, CallbackInfo info) { + FabricBiomesData.END_LAND_BIOMES.put(midlands, (float) weight); + } + + @Inject(method = "addEndBarrensReplacement", at = @At(value = "HEAD")) + private static void bclib_addEndBarrensReplacement(ResourceKey highlands, ResourceKey barrens, double weight, CallbackInfo info) { + FabricBiomesData.END_LAND_BIOMES.put(barrens, (float) weight); + FabricBiomesData.END_VOID_BIOMES.put(barrens, (float) weight); + } +} diff --git a/src/main/java/ru/bclib/mixin/common/WorldGenRegionMixin.java b/src/main/java/ru/bclib/mixin/common/WorldGenRegionMixin.java index a8866f3e..29a130c5 100644 --- a/src/main/java/ru/bclib/mixin/common/WorldGenRegionMixin.java +++ b/src/main/java/ru/bclib/mixin/common/WorldGenRegionMixin.java @@ -2,7 +2,7 @@ package ru.bclib.mixin.common; import net.minecraft.core.BlockPos; import net.minecraft.server.level.WorldGenRegion; -import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.ChunkAccess; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -14,13 +14,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; public class WorldGenRegionMixin { @Final @Shadow - private ChunkPos center; + private ChunkAccess center; @Inject(method = "ensureCanWrite", at = @At("HEAD"), cancellable = true) private void be_alterBlockCheck(BlockPos blockPos, CallbackInfoReturnable info) { int x = blockPos.getX() >> 4; int z = blockPos.getZ() >> 4; WorldGenRegion region = (WorldGenRegion) (Object) this; - info.setReturnValue(Math.abs(x - center.x) < 2 && Math.abs(z - center.z) < 2); + info.setReturnValue(Math.abs(x - center.getPos().x) < 2 && Math.abs(z - center.getPos().z) < 2); } } diff --git a/src/main/java/ru/bclib/mixin/common/WorldPresetMixin.java b/src/main/java/ru/bclib/mixin/common/WorldPresetMixin.java new file mode 100644 index 00000000..d5bfd443 --- /dev/null +++ b/src/main/java/ru/bclib/mixin/common/WorldPresetMixin.java @@ -0,0 +1,19 @@ +package ru.bclib.mixin.common; + +import net.minecraft.client.gui.screens.worldselection.WorldPreset; +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.world.level.levelgen.WorldGenSettings; +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 ru.bclib.api.biomes.BiomeAPI; + +@Mixin(WorldPreset.class) +public class WorldPresetMixin { + @Inject(method = "create", at = @At("HEAD")) + private void create(RegistryAccess.RegistryHolder registryHolder, long l, boolean bl, boolean bl2, CallbackInfoReturnable info) { + BiomeAPI.initRegistry(registryHolder.registryOrThrow(Registry.BIOME_REGISTRY)); + } +} diff --git a/src/main/java/ru/bclib/registry/BaseBlockEntityRenders.java b/src/main/java/ru/bclib/registry/BaseBlockEntityRenders.java index 5b8050ba..98994667 100644 --- a/src/main/java/ru/bclib/registry/BaseBlockEntityRenders.java +++ b/src/main/java/ru/bclib/registry/BaseBlockEntityRenders.java @@ -2,14 +2,14 @@ package ru.bclib.registry; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.fabricmc.fabric.api.client.rendereregistry.v1.BlockEntityRendererRegistry; +import net.fabricmc.fabric.api.client.rendering.v1.BlockEntityRendererRegistry; import ru.bclib.client.render.BaseChestBlockEntityRenderer; import ru.bclib.client.render.BaseSignBlockEntityRenderer; @Environment(EnvType.CLIENT) public class BaseBlockEntityRenders { public static void register() { - BlockEntityRendererRegistry.INSTANCE.register(BaseBlockEntities.CHEST, BaseChestBlockEntityRenderer::new); - BlockEntityRendererRegistry.INSTANCE.register(BaseBlockEntities.SIGN, BaseSignBlockEntityRenderer::new); + BlockEntityRendererRegistry.register(BaseBlockEntities.CHEST, BaseChestBlockEntityRenderer::new); + BlockEntityRendererRegistry.register(BaseBlockEntities.SIGN, BaseSignBlockEntityRenderer::new); } } diff --git a/src/main/java/ru/bclib/registry/BlockRegistry.java b/src/main/java/ru/bclib/registry/BlockRegistry.java index 608e9ca7..bf067f1e 100644 --- a/src/main/java/ru/bclib/registry/BlockRegistry.java +++ b/src/main/java/ru/bclib/registry/BlockRegistry.java @@ -1,5 +1,6 @@ package ru.bclib.registry; +import net.fabricmc.fabric.api.mininglevel.v1.FabricMineableTags; import net.fabricmc.fabric.api.registry.FlammableBlockRegistry; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; @@ -10,6 +11,7 @@ import net.minecraft.world.item.Items; import net.minecraft.world.level.block.Block; import ru.bclib.api.TagAPI; import ru.bclib.blocks.BaseLeavesBlock; +import ru.bclib.blocks.BaseOreBlock; import ru.bclib.blocks.FeatureSaplingBlock; import ru.bclib.config.PathConfig; import ru.bclib.interfaces.CustomItemProvider; @@ -41,10 +43,12 @@ public class BlockRegistry extends BaseRegistry { getModBlocks(id.getNamespace()).add(block); if (block instanceof BaseLeavesBlock){ - TagAPI.addTags(block, TagAPI.BLOCK_LEAVES); + TagAPI.addTags(block, TagAPI.BLOCK_LEAVES, TagAPI.MINEABLE_HOE, FabricMineableTags.SHEARS_MINEABLE); if (item != null){ TagAPI.addTags(item, TagAPI.ITEM_LEAVES); } + } else if (block instanceof BaseOreBlock){ + TagAPI.addTags(block, TagAPI.MINEABLE_PICKAXE); } else if (block instanceof FeatureSaplingBlock){ TagAPI.addTags(block, TagAPI.BLOCK_SAPLINGS); if (item != null){ diff --git a/src/main/java/ru/bclib/util/CollectionsUtil.java b/src/main/java/ru/bclib/util/CollectionsUtil.java new file mode 100644 index 00000000..e7b472c9 --- /dev/null +++ b/src/main/java/ru/bclib/util/CollectionsUtil.java @@ -0,0 +1,46 @@ +package ru.bclib.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class CollectionsUtil { + /** + * Will return mutable copy of list. + * @param list {@link List} to make mutable. + * @return {@link ArrayList} or original {@link List} if it is mutable. + */ + public static List getMutable(List list) { + if (list instanceof ArrayList) { + return list; + } + return new ArrayList<>(list); + } + + /** + * Will return mutable copy of set. + * @param set {@link Set} to make mutable. + * @return {@link HashSet} or original {@link Set} if it is mutable. + */ + public static Set getMutable(Set set) { + if (set instanceof HashSet) { + return set; + } + return new HashSet<>(set); + } + + /** + * Will return mutable copy of map. + * @param map {@link Map} to make mutable. + * @return {@link HashMap} or original {@link Map} if it is mutable. + */ + public static Map getMutable(Map map) { + if (map instanceof HashMap) { + return map; + } + return new HashMap<>(map); + } +} diff --git a/src/main/java/ru/bclib/util/StructureHelper.java b/src/main/java/ru/bclib/util/StructureHelper.java index 28494f48..0b0f3df2 100644 --- a/src/main/java/ru/bclib/util/StructureHelper.java +++ b/src/main/java/ru/bclib/util/StructureHelper.java @@ -378,7 +378,9 @@ public class StructureHelper { mut.setX(x); for (int z = bounds.minZ(); z <= bounds.maxZ(); z++) { mut.setZ(z); - BlockState top = world.getBiome(mut).getGenerationSettings().getSurfaceBuilderConfig().getTopMaterial(); + BlockState top = Blocks.PURPLE_CONCRETE.defaultBlockState(); + //TODO: 1.18 find another way to get the Top Materiel + //world.getBiome(mut).getGenerationSettings().getSurfaceBuilderConfig().getTopMaterial(); for (int y = bounds.maxY(); y >= bounds.minY(); y--) { mut.setY(y); BlockState state = world.getBlockState(mut); diff --git a/src/main/java/ru/bclib/world/biomes/BCLBiome.java b/src/main/java/ru/bclib/world/biomes/BCLBiome.java index ebdf2a73..4ac623eb 100644 --- a/src/main/java/ru/bclib/world/biomes/BCLBiome.java +++ b/src/main/java/ru/bclib/world/biomes/BCLBiome.java @@ -2,178 +2,218 @@ package ru.bclib.world.biomes; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; import net.minecraft.core.Registry; +import net.minecraft.data.BuiltinRegistries; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.Biomes; -import ru.bclib.config.Configs; -import ru.bclib.util.JsonFactory; -import ru.bclib.util.StructureHelper; +import net.minecraft.world.level.levelgen.SurfaceRules; +import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; +import org.jetbrains.annotations.Nullable; +import ru.bclib.api.biomes.BiomeAPI; import ru.bclib.util.WeightedList; -import ru.bclib.world.features.BCLFeature; -import ru.bclib.world.features.ListFeature; -import ru.bclib.world.features.ListFeature.StructureInfo; -import ru.bclib.world.features.NBTStructureFeature.TerrainMerge; -import java.io.InputStream; import java.util.List; import java.util.Map; import java.util.Random; public class BCLBiome { - protected WeightedList subbiomes = new WeightedList(); + private final List structures = Lists.newArrayList(); + private final WeightedList subbiomes = new WeightedList<>(); + private final Map customData = Maps.newHashMap(); + private final ResourceLocation biomeID; + private final Biome biome; - protected final Biome biome; - protected final ResourceLocation mcID; - protected BCLBiome edge; - protected int edgeSize; - - protected BCLBiome biomeParent; - protected float maxSubBiomeChance = 1; - protected final float genChance; - - private final Map customData; - private final float fogDensity; - private BCLFeature structuresFeature; + private SurfaceRules.RuleSource surface; + private BCLBiome biomeParent; private Biome actualBiome; + private BCLBiome edge; - public BCLBiome(BCLBiomeDef definition) { - definition.loadConfigValues(Configs.BIOMES_CONFIG); - this.mcID = definition.getID(); - this.readStructureList(); - if (structuresFeature != null) { - definition.addFeature(structuresFeature); - } - this.biome = definition.build(); - this.genChance = definition.getGenChance(); - this.fogDensity = definition.getFodDensity(); - this.customData = definition.getCustomData(); - subbiomes.add(this, 1); + private float terrainHeight = 0.1F; + private float fogDensity = 1.0F; + private float genChance = 1.0F; + private float edgeSize = 0.0F; + + /** + * Create wrapper for existing biome using its {@link ResourceLocation} identifier. + * @param biomeKey {@link ResourceKey} for the {@link Biome}. + */ + public BCLBiome(ResourceKey biomeKey) { + this(biomeKey.location()); } - public BCLBiome(ResourceLocation id, Biome biome, float fogDensity, float genChance) { - this.mcID = id; + /** + * Create wrapper for existing biome using its {@link ResourceLocation} identifier. + * @param biomeID {@link ResourceLocation} biome ID. + */ + public BCLBiome(ResourceLocation biomeID) { + this(biomeID, BuiltinRegistries.BIOME.get(biomeID)); + } + + /** + * Create wrapper for existing biome using biome instance from {@link BuiltinRegistries}. + * @param biome {@link Biome} to wrap. + */ + public BCLBiome(Biome biome) { + this(BuiltinRegistries.BIOME.getKey(biome), biome); + } + + public BCLBiome(ResourceLocation biomeID, Biome biome) { + this.subbiomes.add(this, 1.0F); + this.biomeID = biomeID; this.biome = biome; - if (id.equals(Biomes.THE_VOID.location())) { - this.genChance = fogDensity; - this.fogDensity = genChance; - } - else { - String biomePath = id.getNamespace() + "." + id.getPath(); - this.genChance = Configs.BIOMES_CONFIG.getFloat(biomePath, "generation_chance", genChance); - this.fogDensity = Configs.BIOMES_CONFIG.getFloat(biomePath, "fog_density", fogDensity); - } - this.readStructureList(); - this.customData = Maps.newHashMap(); - subbiomes.add(this, 1); } + /** + * Get current biome edge. + * @return {@link BCLBiome} edge. + */ + @Nullable public BCLBiome getEdge() { - return edge == null ? this : edge; + return edge; } - public void setEdge(BCLBiome edge) { + /** + * Set biome edge for this biome instance. + * @param edge {@link BCLBiome} as the edge biome. + * @return same {@link BCLBiome}. + */ + public BCLBiome setEdge(BCLBiome edge) { this.edge = edge; edge.biomeParent = this; + return this; } - public int getEdgeSize() { + /** + * Getter for biome edge size. + * @return edge size. + */ + public float getEdgeSize() { return edgeSize; } - public void setEdgeSize(int size) { + /** + * Set edges size for this biome. Size is in relative units to work fine with biome scale. + * @param size as a float value. + * @return same {@link BCLBiome}. + */ + public BCLBiome setEdgeSize(float size) { edgeSize = size; + return this; } - public void addSubBiome(BCLBiome biome) { + /** + * Adds sub-biome into this biome instance. Biome chance will be interpreted as a sub-biome generation chance. + * Biome itself has chance 1.0 compared to all its sub-biomes. + * @param biome {@link Random} to be added. + * @return same {@link BCLBiome}. + */ + public BCLBiome addSubBiome(BCLBiome biome) { biome.biomeParent = this; subbiomes.add(biome, biome.getGenChance()); + return this; } + /** + * Checks if specified biome is a sub-biome of this one. + * @param biome {@link Random}. + * @return true if this instance contains specified biome as a sub-biome. + */ public boolean containsSubBiome(BCLBiome biome) { return subbiomes.contains(biome); } + /** + * Getter for a random sub-biome from all existing sub-biomes. Will return biome itself if there are no sub-biomes. + * @param random {@link Random}. + * @return {@link BCLBiome}. + */ public BCLBiome getSubBiome(Random random) { return subbiomes.get(random); } + /** + * Getter for parent {@link BCLBiome} or null if there are no parent biome. + * @return {@link BCLBiome} or null. + */ + @Nullable public BCLBiome getParentBiome() { return this.biomeParent; } - public boolean hasEdge() { - return edge != null; - } - - public boolean hasParentBiome() { - return biomeParent != null; - } - + /** + * Compares biome instances (directly) and their parents. Used in custom world generator. + * @param biome {@link BCLBiome} + * @return true if biome or its parent is same. + */ public boolean isSame(BCLBiome biome) { - return biome == this || (biome.hasParentBiome() && biome.getParentBiome() == this); - } - - public Biome getBiome() { - return biome; - } - - @Override - public String toString() { - return mcID.toString(); + return biome == this || (biome.biomeParent != null && biome.biomeParent == this); } + /** + * Getter for biome identifier. + * @return {@link ResourceLocation} + */ public ResourceLocation getID() { - return mcID; + return biomeID; } + /** + * Getter for fog density, used in custom for renderer. + * @return fog density as a float. + */ public float getFogDensity() { return fogDensity; } - protected void readStructureList() { - String ns = mcID.getNamespace(); - String nm = mcID.getPath(); - - String path = "/data/" + ns + "/structures/biome/" + nm + "/"; - InputStream inputstream = StructureHelper.class.getResourceAsStream(path + "structures.json"); - if (inputstream != null) { - JsonObject obj = JsonFactory.getJsonObject(inputstream); - JsonArray enties = obj.getAsJsonArray("structures"); - if (enties != null) { - List list = Lists.newArrayList(); - enties.forEach((entry) -> { - JsonObject e = entry.getAsJsonObject(); - String structure = path + e.get("nbt").getAsString() + ".nbt"; - TerrainMerge terrainMerge = TerrainMerge.getFromString(e.get("terrainMerge").getAsString()); - int offsetY = e.get("offsetY").getAsInt(); - list.add(new StructureInfo(structure, offsetY, terrainMerge)); - }); - if (!list.isEmpty()) { - structuresFeature = BCLFeature.makeChansedFeature( - new ResourceLocation(ns, nm + "_structures"), - new ListFeature(list), - 10 - ); - } - } - } + /** + * Sets fog density for this biome. + * @param fogDensity + * @return same {@link BCLBiome}. + */ + public BCLBiome setFogDensity(float fogDensity) { + this.fogDensity = fogDensity; + return this; } - public BCLFeature getStructuresFeature() { - return structuresFeature; + /** + * Getter for biome from buil-in registry. For datapack biomes will be same as actual biome. + * @return {@link Biome}. + */ + public Biome getBiome() { + return biome; } + /** + * Getter for actual biome (biome from current world registry with same {@link ResourceLocation} id). + * @return {@link Biome}. + */ public Biome getActualBiome() { return this.actualBiome; } + /** + * Getter for biome generation chance, used in {@link ru.bclib.world.generator.BiomePicker} and in custom generators. + * @return biome generation chance as float. + */ public float getGenChance() { return this.genChance; } + /** + * Set gen chance for this biome, default value is 1.0. + * @param genChance chance of this biome to be generated. + * @return same {@link BCLBiome}. + */ + public BCLBiome setGenChance(float genChance) { + this.genChance = genChance; + return this; + } + + /** + * Recursively update biomes to correct world biome registry instances, for internal usage only. + * @param biomeRegistry {@link Registry} for {@link Biome}. + */ public void updateActualBiomes(Registry biomeRegistry) { subbiomes.forEach((sub) -> { if (sub != this) { @@ -183,7 +223,62 @@ public class BCLBiome { if (edge != null && edge != this) { edge.updateActualBiomes(biomeRegistry); } - this.actualBiome = biomeRegistry.get(mcID); + this.actualBiome = biomeRegistry.get(biomeID); + + if (!this.structures.isEmpty()) { + structures.forEach(s -> BiomeAPI.addBiomeStructure(BiomeAPI.getBiomeKey(actualBiome), s)); + } + } + + /** + * Getter for custom data. Will get custom data object or null if object doesn't exists. + * @param name {@link String} name of data object. + * @return object value or null. + */ + @Nullable + @SuppressWarnings("unchecked") + public T getCustomData(String name) { + return (T) customData.get(name); + } + + /** + * Getter for custom data. Will get custom data object or default value if object doesn't exists. + * @param name {@link String} name of data object. + * @param defaultValue object default value. + * @return object value or default value. + */ + @SuppressWarnings("unchecked") + public T getCustomData(String name, T defaultValue) { + return (T) customData.getOrDefault(name, defaultValue); + } + + /** + * Adds custom data object to this biome instance. + * @param name {@link String} name of data object. + * @param obj any data to add. + * @return same {@link BCLBiome}. + */ + public BCLBiome addCustomData(String name, Object obj) { + customData.put(name, obj); + return this; + } + + /** + * Adds custom data object to this biome instance. + * @param data a {@link Map} with custom data. + * @return same {@link BCLBiome}. + */ + public BCLBiome addCustomData(Map data) { + customData.putAll(data); + return this; + } + + /** + * Getter for terrain height, can be used in custom terrain generator. + * @return terrain height. + */ + public float getTerrainHeight() { + return terrainHeight; } @Override @@ -192,20 +287,34 @@ public class BCLBiome { return true; } BCLBiome biome = (BCLBiome) obj; - return biome == null ? false : biome.mcID.equals(mcID); + return biome == null ? false : biomeID.equals(biome.biomeID); } @Override public int hashCode() { - return mcID.hashCode(); + return biomeID.hashCode(); } - @SuppressWarnings("unchecked") - public T getCustomData(String name, T defaultValue) { - return (T) customData.getOrDefault(name, defaultValue); + @Override + public String toString() { + return biomeID.toString(); } - public void addCustomData(String name, Object obj) { - customData.put(name, obj); + /** + * Adds structures to this biome. For internal use only. + * Used inside {@link ru.bclib.api.biomes.BCLBiomeBuilder}. + */ + public void attachStructures(List structures) { + this.structures.addAll(structures); + } + + /** + * Sets biome surface rule. + * @param surface {@link SurfaceRules.RuleSource} rule. + */ + public void setSurface(SurfaceRules.RuleSource surface) { + ResourceKey key = BiomeAPI.getBiomeKey(biome); + BiomeAPI.addSurfaceRule(biomeID, SurfaceRules.ifTrue(SurfaceRules.isBiome(key), surface)); + this.surface = surface; } } diff --git a/src/main/java/ru/bclib/world/biomes/BCLBiomeDef.java b/src/main/java/ru/bclib/world/biomes/BCLBiomeDef.java deleted file mode 100644 index 1130112b..00000000 --- a/src/main/java/ru/bclib/world/biomes/BCLBiomeDef.java +++ /dev/null @@ -1,435 +0,0 @@ -package ru.bclib.world.biomes; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import net.minecraft.core.Registry; -import net.minecraft.core.particles.ParticleOptions; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.sounds.Music; -import net.minecraft.sounds.Musics; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.level.biome.AmbientAdditionsSettings; -import net.minecraft.world.level.biome.AmbientMoodSettings; -import net.minecraft.world.level.biome.AmbientParticleSettings; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.Biome.BiomeCategory; -import net.minecraft.world.level.biome.Biome.Precipitation; -import net.minecraft.world.level.biome.BiomeGenerationSettings; -import net.minecraft.world.level.biome.BiomeSpecialEffects.Builder; -import net.minecraft.world.level.biome.MobSpawnSettings; -import net.minecraft.world.level.biome.MobSpawnSettings.SpawnerData; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.levelgen.GenerationStep.Carving; -import net.minecraft.world.level.levelgen.GenerationStep.Decoration; -import net.minecraft.world.level.levelgen.carver.CarverConfiguration; -import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver; -import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; -import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; -import net.minecraft.world.level.levelgen.surfacebuilders.ConfiguredSurfaceBuilder; -import net.minecraft.world.level.levelgen.surfacebuilders.SurfaceBuilder; -import net.minecraft.world.level.levelgen.surfacebuilders.SurfaceBuilderBaseConfiguration; -import ru.bclib.config.IdConfig; -import ru.bclib.config.PathConfig; -import ru.bclib.util.ColorUtil; -import ru.bclib.world.features.BCLFeature; -import ru.bclib.world.structures.BCLStructureFeature; -import ru.bclib.world.surface.DoubleBlockSurfaceBuilder; - -import java.util.List; -import java.util.Map; - -public class BCLBiomeDef { - public static final int DEF_FOLIAGE_OVERWORLD = ColorUtil.color(110, 143, 64); - public static final int DEF_FOLIAGE_NETHER = ColorUtil.color(117, 10, 10); - public static final int DEF_FOLIAGE_END = ColorUtil.color(197, 210, 112); - - private final List> structures = Lists.newArrayList(); - private final List features = Lists.newArrayList(); - private final List carvers = Lists.newArrayList(); - private final List mobs = Lists.newArrayList(); - private final List spawns = Lists.newArrayList(); - private final Map customData = Maps.newHashMap(); - - private final ResourceLocation id; - - private AmbientParticleSettings particleConfig; - private AmbientAdditionsSettings additions; - private AmbientMoodSettings mood; - private SoundEvent music; - private SoundEvent loop; - - private int foliageColor = DEF_FOLIAGE_OVERWORLD; - private int grassColor = DEF_FOLIAGE_OVERWORLD; - private int waterFogColor = 329011; - private int waterColor = 4159204; - private int fogColor = 10518688; - private int skyColor = 0; - private float fogDensity = 1F; - private float depth = 0.1F; - - private Precipitation precipitation = Precipitation.NONE; - private BiomeCategory category = BiomeCategory.NONE; - private float temperature = 1F; - private float genChance = 1F; - private float downfall = 0F; - private int edgeSize = 32; - - private ConfiguredSurfaceBuilder surface; - - /** - * Custom biome definition. Can be extended with new parameters. - * - * @param id - Biome {@link ResourceLocation} (identifier). - */ - public BCLBiomeDef(ResourceLocation id) { - this.id = id; - } - - /** - * Create default definition for The Nether biome. - * - * @return {@link BCLBiomeDef}. - */ - public BCLBiomeDef netherBiome() { - this.foliageColor = DEF_FOLIAGE_NETHER; - this.grassColor = DEF_FOLIAGE_NETHER; - this.setCategory(BiomeCategory.NETHER); - return this; - } - - /** - * Create default definition for The End biome. - * - * @return {@link BCLBiomeDef}. - */ - public BCLBiomeDef endBiome() { - this.foliageColor = DEF_FOLIAGE_END; - this.grassColor = DEF_FOLIAGE_END; - this.setCategory(BiomeCategory.THEEND); - return this; - } - - /** - * Used to load biome settings from config. - * @param config - {@link IdConfig}. - * @return this {@link BCLBiomeDef}. - */ - public BCLBiomeDef loadConfigValues(IdConfig config) { - this.fogDensity = config.getFloat(id, "fog_density", this.fogDensity); - this.genChance = config.getFloat(id, "generation_chance", this.genChance); - this.edgeSize = config.getInt(id, "edge_size", this.edgeSize); - return this; - } - - /** - * Used to load biome settings from config. - * @param config - {@link PathConfig}. - * @return this {@link BCLBiomeDef}. - */ - public BCLBiomeDef loadConfigValues(PathConfig config) { - String biomePath = id.getNamespace() + "." + id.getPath(); - this.fogDensity = config.getFloat(biomePath, "fog_density", this.fogDensity); - this.genChance = config.getFloat(biomePath, "generation_chance", this.genChance); - this.edgeSize = config.getInt(biomePath, "edge_size", this.edgeSize); - return this; - } - - /** - * Set category of the biome. - * @param category - {@link BiomeCategory}. - * @return this {@link BCLBiomeDef}. - */ - public BCLBiomeDef setCategory(BiomeCategory category) { - this.category = category; - return this; - } - - public BCLBiomeDef setPrecipitation(Precipitation precipitation) { - this.precipitation = precipitation; - return this; - } - - public BCLBiomeDef setSurface(Block block) { - setSurface(SurfaceBuilder.DEFAULT.configured(new SurfaceBuilderBaseConfiguration( - block.defaultBlockState(), - Blocks.END_STONE.defaultBlockState(), - Blocks.END_STONE.defaultBlockState() - ))); - return this; - } - - public BCLBiomeDef setSurface(Block block1, Block block2) { - setSurface(DoubleBlockSurfaceBuilder.register("bclib_" + id.getPath() + "_surface") - .setBlock1(block1) - .setBlock2(block2) - .configured()); - return this; - } - - public BCLBiomeDef setSurface(ConfiguredSurfaceBuilder builder) { - this.surface = builder; - return this; - } - - public BCLBiomeDef setParticles(ParticleOptions particle, float probability) { - this.particleConfig = new AmbientParticleSettings(particle, probability); - return this; - } - - public BCLBiomeDef setGenChance(float genChance) { - this.genChance = genChance; - return this; - } - - public BCLBiomeDef setDepth(float depth) { - this.depth = depth; - return this; - } - - public BCLBiomeDef setTemperature(float temperature) { - this.temperature = temperature; - return this; - } - - public BCLBiomeDef setDownfall(float downfall) { - this.downfall = downfall; - return this; - } - - public BCLBiomeDef setEdgeSize(int edgeSize) { - this.edgeSize = edgeSize; - return this; - } - - public BCLBiomeDef addMobSpawn(EntityType type, int weight, int minGroupSize, int maxGroupSize) { - ResourceLocation eID = Registry.ENTITY_TYPE.getKey(type); - if (eID != Registry.ENTITY_TYPE.getDefaultKey()) { - SpawnInfo info = new SpawnInfo(); - info.type = type; - info.weight = weight; - info.minGroupSize = minGroupSize; - info.maxGroupSize = maxGroupSize; - mobs.add(info); - } - return this; - } - - public BCLBiomeDef addMobSpawn(SpawnerData entry) { - spawns.add(entry); - return this; - } - - public BCLBiomeDef addStructureFeature(ConfiguredStructureFeature feature) { - structures.add(feature); - return this; - } - - public BCLBiomeDef addStructureFeature(BCLStructureFeature feature) { - structures.add(feature.getFeatureConfigured()); - return this; - } - - public BCLBiomeDef addFeature(BCLFeature feature) { - FeatureInfo info = new FeatureInfo(); - info.featureStep = feature.getFeatureStep(); - info.feature = feature.getFeatureConfigured(); - features.add(info); - return this; - } - - public BCLBiomeDef addFeature(Decoration featureStep, ConfiguredFeature feature) { - FeatureInfo info = new FeatureInfo(); - info.featureStep = featureStep; - info.feature = feature; - features.add(info); - return this; - } - - private int getColor(int r, int g, int b) { - r = Mth.clamp(r, 0, 255); - g = Mth.clamp(g, 0, 255); - b = Mth.clamp(b, 0, 255); - return ColorUtil.color(r, g, b); - } - - public BCLBiomeDef setSkyColor(int rgb) { - this.skyColor = rgb; - return this; - } - - public BCLBiomeDef setSkyColor(int r, int g, int b) { - return setSkyColor(getColor(r, g, b)); - } - - public BCLBiomeDef setFogColor(int rgb) { - this.fogColor = rgb; - return this; - } - - public BCLBiomeDef setFogColor(int r, int g, int b) { - return setFogColor(getColor(r, g, b)); - } - - public BCLBiomeDef setFogDensity(float density) { - this.fogDensity = density; - return this; - } - - public BCLBiomeDef setWaterColor(int r, int g, int b) { - this.waterColor = getColor(r, g, b); - return this; - } - - public BCLBiomeDef setWaterFogColor(int r, int g, int b) { - this.waterFogColor = getColor(r, g, b); - return this; - } - - public BCLBiomeDef setWaterAndFogColor(int r, int g, int b) { - return setWaterColor(r, g, b).setWaterFogColor(r, g, b); - } - - public BCLBiomeDef setFoliageColor(int r, int g, int b) { - this.foliageColor = getColor(r, g, b); - return this; - } - - public BCLBiomeDef setGrassColor(int r, int g, int b) { - this.grassColor = getColor(r, g, b); - return this; - } - - public BCLBiomeDef setPlantsColor(int r, int g, int b) { - return this.setFoliageColor(r, g, b).setGrassColor(r, g, b); - } - - public BCLBiomeDef setLoop(SoundEvent loop) { - this.loop = loop; - return this; - } - - public BCLBiomeDef setMood(SoundEvent mood) { - this.mood = new AmbientMoodSettings(mood, 6000, 8, 2.0D); - return this; - } - - public BCLBiomeDef setAdditions(SoundEvent additions) { - this.additions = new AmbientAdditionsSettings(additions, 0.0111); - return this; - } - - public BCLBiomeDef setMusic(SoundEvent music) { - this.music = music; - return this; - } - - protected void addCustomToBuild(BiomeGenerationSettings.Builder generationSettings){ - - } - - public Biome build() { - MobSpawnSettings.Builder spawnSettings = new MobSpawnSettings.Builder(); - BiomeGenerationSettings.Builder generationSettings = new BiomeGenerationSettings.Builder(); - Builder effects = new Builder(); - - mobs.forEach((spawn) -> { - spawnSettings.addSpawn( - spawn.type.getCategory(), - new MobSpawnSettings.SpawnerData(spawn.type, spawn.weight, spawn.minGroupSize, spawn.maxGroupSize) - ); - }); - - spawns.forEach((entry) -> { - spawnSettings.addSpawn(entry.type.getCategory(), entry); - }); - - generationSettings.surfaceBuilder(surface == null ? net.minecraft.data.worldgen.SurfaceBuilders.END : surface); - structures.forEach((structure) -> generationSettings.addStructureStart(structure)); - features.forEach((info) -> generationSettings.addFeature(info.featureStep, info.feature)); - carvers.forEach((info) -> generationSettings.addCarver(info.carverStep, info.carver)); - - addCustomToBuild(generationSettings); - - effects.skyColor(skyColor) - .waterColor(waterColor) - .waterFogColor(waterFogColor) - .fogColor(fogColor) - .foliageColorOverride(foliageColor) - .grassColorOverride(grassColor); - if (loop != null) effects.ambientLoopSound(loop); - if (mood != null) effects.ambientMoodSound(mood); - if (additions != null) effects.ambientAdditionsSound(additions); - if (particleConfig != null) effects.ambientParticle(particleConfig); - effects.backgroundMusic(music != null ? new Music(music, 600, 2400, true) : Musics.END); - - return new Biome.BiomeBuilder() - .precipitation(precipitation) - .biomeCategory(category) - .depth(depth) - .scale(0.2F) - .temperature(temperature) - .downfall(downfall) - .specialEffects(effects.build()) - .mobSpawnSettings(spawnSettings.build()) - .generationSettings(generationSettings.build()) - .build(); - } - - private static final class SpawnInfo { - EntityType type; - int weight; - int minGroupSize; - int maxGroupSize; - } - - private static final class FeatureInfo { - Decoration featureStep; - ConfiguredFeature feature; - } - - private static final class CarverInfo { - Carving carverStep; - ConfiguredWorldCarver carver; - } - - public ResourceLocation getID() { - return id; - } - - public float getFodDensity() { - return fogDensity; - } - - public float getGenChance() { - return genChance; - } - - public int getEdgeSize() { - return edgeSize; - } - - public BCLBiomeDef addCarver(Carving carverStep, ConfiguredWorldCarver carver) { - CarverInfo info = new CarverInfo(); - info.carverStep = carverStep; - info.carver = carver; - carvers.add(info); - return this; - } - - public BCLBiomeDef addCustomData(String name, Object value) { - customData.put(name, value); - return this; - } - - @SuppressWarnings("unchecked") - public T getCustomData(String name, Object defaultValue) { - return (T) customData.getOrDefault(name, defaultValue); - } - - protected Map getCustomData() { - return customData; - } -} \ No newline at end of file diff --git a/src/main/java/ru/bclib/world/features/BCLDecorators.java b/src/main/java/ru/bclib/world/features/BCLDecorators.java index ee5b60b2..ca8f377d 100644 --- a/src/main/java/ru/bclib/world/features/BCLDecorators.java +++ b/src/main/java/ru/bclib/world/features/BCLDecorators.java @@ -1,13 +1,7 @@ package ru.bclib.world.features; -import net.minecraft.data.worldgen.Features; -import net.minecraft.world.level.levelgen.placement.ConfiguredDecorator; -import ru.bclib.BCLib; - -import java.lang.reflect.Field; - public class BCLDecorators { - public static final ConfiguredDecorator HEIGHTMAP_SQUARE; + /*public static final ConfiguredDecorator HEIGHTMAP_SQUARE; private static final ConfiguredDecorator getDecorator(Field[] fields, int index) { try { @@ -23,5 +17,5 @@ public class BCLDecorators { Class[] classes = Features.class.getDeclaredClasses(); Field[] fields = classes[1].getDeclaredFields(); // Decorators class HEIGHTMAP_SQUARE = getDecorator(fields, 17); - } + }*/ } diff --git a/src/main/java/ru/bclib/world/features/BCLFeature.java b/src/main/java/ru/bclib/world/features/BCLFeature.java index 02e43132..a988107a 100644 --- a/src/main/java/ru/bclib/world/features/BCLFeature.java +++ b/src/main/java/ru/bclib/world/features/BCLFeature.java @@ -2,33 +2,38 @@ package ru.bclib.world.features; import net.minecraft.core.Registry; import net.minecraft.data.BuiltinRegistries; +import net.minecraft.data.worldgen.placement.PlacementUtils; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.valueproviders.UniformInt; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.levelgen.GenerationStep.Decoration; import net.minecraft.world.level.levelgen.VerticalAnchor; -import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; import net.minecraft.world.level.levelgen.feature.Feature; -import net.minecraft.world.level.levelgen.feature.configurations.CountConfiguration; import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration; import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration; -import net.minecraft.world.level.levelgen.placement.ChanceDecoratorConfiguration; -import net.minecraft.world.level.levelgen.placement.FeatureDecorator; +import net.minecraft.world.level.levelgen.heightproviders.UniformHeight; +import net.minecraft.world.level.levelgen.placement.BiomeFilter; +import net.minecraft.world.level.levelgen.placement.CountPlacement; +import net.minecraft.world.level.levelgen.placement.HeightRangePlacement; +import net.minecraft.world.level.levelgen.placement.InSquarePlacement; +import net.minecraft.world.level.levelgen.placement.PlacedFeature; +import net.minecraft.world.level.levelgen.placement.RarityFilter; import net.minecraft.world.level.levelgen.structure.templatesystem.BlockMatchTest; public class BCLFeature { - private ConfiguredFeature featureConfigured; + private PlacedFeature placedFeature; private Decoration featureStep; private Feature feature; - public BCLFeature(Feature feature, ConfiguredFeature configuredFeature, Decoration featureStep) { - this.featureConfigured = configuredFeature; + public BCLFeature(Feature feature, PlacedFeature placedFeature, Decoration featureStep) { + this.placedFeature = placedFeature; this.featureStep = featureStep; this.feature = feature; } - public BCLFeature(ResourceLocation id, Feature feature, Decoration featureStep, ConfiguredFeature configuredFeature) { - this.featureConfigured = Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, id, configuredFeature); + public BCLFeature(ResourceLocation id, Feature feature, Decoration featureStep, PlacedFeature placedFeature) { + this.placedFeature = Registry.register(BuiltinRegistries.PLACED_FEATURE, id, placedFeature); this.feature = Registry.register(Registry.FEATURE, id, feature); this.featureStep = featureStep; } @@ -43,20 +48,19 @@ public class BCLFeature { /** * Get configured feature. - * @return {@link ConfiguredFeature}. + * @return {@link PlacedFeature}. */ - public ConfiguredFeature getFeatureConfigured() { - return featureConfigured; + public PlacedFeature getPlacedFeature() { + return placedFeature; } /** * Get feature decoration step. * @return {@link Decoration}. */ - public Decoration getFeatureStep() { + public Decoration getDecoration() { return featureStep; } - /** * Will create a basic plant feature. * @param id {@link ResourceLocation} feature ID. @@ -65,13 +69,16 @@ public class BCLFeature { * @return new BCLFeature instance. */ public static BCLFeature makeVegetationFeature(ResourceLocation id, Feature feature, int density) { - ConfiguredFeature configured = feature + PlacedFeature configured = feature .configured(FeatureConfiguration.NONE) - .decorated(BCLDecorators.HEIGHTMAP_SQUARE) - .countRandom(density); + .placed( + CountPlacement.of(UniformInt.of(0, 4)), + InSquarePlacement.spread(), + PlacementUtils.HEIGHTMAP, + BiomeFilter.biome() + ); return new BCLFeature(id, feature, Decoration.VEGETAL_DECORATION, configured); } - /** * Will create a basic ore feature. * @param id {@link ResourceLocation} feature ID. @@ -84,22 +91,45 @@ public class BCLFeature { * @return new BCLFeature instance. */ public static BCLFeature makeOreFeature(ResourceLocation id, Block blockOre, Block hostBlock, int veins, int veinSize, int minY, int maxY) { + //TODO: 1.18 See if this still works + return makeOreFeature(id, blockOre, hostBlock, veins, veinSize, minY, maxY, false); + } + + /** + * Will create a basic ore feature. + * + * @param id {@link ResourceLocation} feature ID. + * @param blockOre {@link Decoration} feature step. + * @param hostBlock {@link Block} to generate feature in. + * @param veins iterations per chunk. + * @param veinSize size of ore vein. + * @param minY minimum height. + * @param maxY maximum height. + * @param rare when true, this is placed as a rare resource + * @return new BCLFeature instance. + */ + public static BCLFeature makeOreFeature(ResourceLocation id, Block blockOre, Block hostBlock, int veins, int veinSize, int minY, int maxY, boolean rare) { OreConfiguration featureConfig = new OreConfiguration( new BlockMatchTest(hostBlock), blockOre.defaultBlockState(), veinSize ); - ConfiguredFeature oreFeature = Feature.ORE + + PlacedFeature oreFeature = Feature.ORE .configured(featureConfig) - .rangeUniform( - VerticalAnchor.absolute(minY), - VerticalAnchor.absolute(maxY) - ) - .squared() - .count(veins); + .placed( + InSquarePlacement.spread(), + rare ? RarityFilter.onAverageOnceEvery(veins) : CountPlacement.of(veins), + HeightRangePlacement.of( + UniformHeight.of( + VerticalAnchor.absolute(minY), + VerticalAnchor.absolute(maxY) + ) + ), + BiomeFilter.biome()); return new BCLFeature( - Feature.ORE, - Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, id, oreFeature), + net.minecraft.world.level.levelgen.feature.Feature.ORE, + Registry.register(BuiltinRegistries.PLACED_FEATURE, id, oreFeature), Decoration.UNDERGROUND_ORES ); } @@ -112,9 +142,9 @@ public class BCLFeature { * @return new BCLFeature instance. */ public static BCLFeature makeChunkFeature(ResourceLocation id, Decoration step, Feature feature) { - ConfiguredFeature configured = feature + PlacedFeature configured = feature .configured(FeatureConfiguration.NONE) - .decorated(FeatureDecorator.COUNT.configured(new CountConfiguration(1))); + .placed(CountPlacement.of(1)); return new BCLFeature(id, feature, step, configured); } @@ -127,9 +157,9 @@ public class BCLFeature { * @return new BCLFeature instance. */ public static BCLFeature makeChancedFeature(ResourceLocation id, Decoration step, Feature feature, int chance) { - ConfiguredFeature configured = feature + PlacedFeature configured = feature .configured(FeatureConfiguration.NONE) - .decorated(FeatureDecorator.CHANCE.configured(new ChanceDecoratorConfiguration(chance))); + .placed(RarityFilter.onAverageOnceEvery(chance)); return new BCLFeature(id, feature, step, configured); } @@ -142,9 +172,10 @@ public class BCLFeature { * @return new BCLFeature instance. */ public static BCLFeature makeCountFeature(ResourceLocation id, Decoration step, Feature feature, int count) { - ConfiguredFeature configured = feature + PlacedFeature configured = feature .configured(FeatureConfiguration.NONE) - .decorated(FeatureDecorator.COUNT.configured(new CountConfiguration(count))); + .placed(CountPlacement.of(count)); + //.decorated(FeatureDecorator.COUNT.configured(new CountConfiguration(count))); return new BCLFeature(id, feature, step, configured); } @@ -156,37 +187,7 @@ public class BCLFeature { * @return new BCLFeature instance. */ public static BCLFeature makeFeatureConfigured(ResourceLocation id, Decoration step, Feature feature) { - ConfiguredFeature configured = feature.configured(FeatureConfiguration.NONE); + PlacedFeature configured = feature.configured(FeatureConfiguration.NONE).placed(); return new BCLFeature(id, feature, step, configured); } - - @Deprecated(forRemoval = true) - public static BCLFeature makeOreFeature(ResourceLocation id, Block blockOre, Block hostBlock, int veins, int veinSize, int offset, int minY, int maxY) { - return makeOreFeature(id, blockOre, hostBlock, veins, veinSize, minY, maxY); - } - - @Deprecated(forRemoval = true) - public static BCLFeature makeRawGenFeature(ResourceLocation id, Feature feature, int chance) { - return makeChancedFeature(id, Decoration.RAW_GENERATION, feature, chance); - } - - @Deprecated(forRemoval = true) - public static BCLFeature makeChunkFeature(ResourceLocation id, Feature feature) { - return makeChunkFeature(id, Decoration.LOCAL_MODIFICATIONS, feature); - } - - @Deprecated(forRemoval = true) - public static BCLFeature makeChansedFeature(ResourceLocation id, Feature feature, int chance) { - return makeChancedFeature(id, Decoration.SURFACE_STRUCTURES, feature, chance); - } - - @Deprecated(forRemoval = true) - public static BCLFeature makeCountRawFeature(ResourceLocation id, Feature feature, int chance) { - return makeCountFeature(id, Decoration.RAW_GENERATION, feature, chance); - } - - @Deprecated(forRemoval = true) - public static BCLFeature makeFeatureConfigured(ResourceLocation id, Feature feature) { - return makeFeatureConfigured(id, Decoration.RAW_GENERATION, feature); - } } diff --git a/src/main/java/ru/bclib/world/features/NBTStructureFeature.java b/src/main/java/ru/bclib/world/features/NBTStructureFeature.java index 37aa0050..e0b44884 100644 --- a/src/main/java/ru/bclib/world/features/NBTStructureFeature.java +++ b/src/main/java/ru/bclib/world/features/NBTStructureFeature.java @@ -10,6 +10,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.state.BlockState; @@ -18,9 +19,8 @@ import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConf import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; -import net.minecraft.world.level.levelgen.surfacebuilders.SurfaceBuilderConfiguration; -import ru.bclib.api.BiomeAPI; import ru.bclib.api.TagAPI; +import ru.bclib.api.biomes.BiomeAPI; import ru.bclib.util.BlocksHelper; import ru.bclib.world.processors.DestructionStructureProcessor; @@ -142,11 +142,14 @@ public abstract class NBTStructureFeature extends DefaultFeature { BlockState stateSt = world.getBlockState(mut); if (!stateSt.is(TagAPI.BLOCK_GEN_TERRAIN)) { if (merge == TerrainMerge.SURFACE) { - SurfaceBuilderConfiguration config = world.getBiome(mut) - .getGenerationSettings() - .getSurfaceBuilderConfig(); +// SurfaceBuilderConfiguration config = world.getBiome(mut) +// .getGenerationSettings() +// .getSurfaceBuilderConfig(); boolean isTop = mut.getY() == surfMax && state.getMaterial().isSolidBlocking(); - BlockState top = isTop ? config.getTopMaterial() : config.getUnderMaterial(); + BlockState top = + Blocks.PURPLE_CONCRETE.defaultBlockState(); + //TODO: 1.18 find another way to get the Top/Bottom Materiel + //isTop ? config.getTopMaterial() : config.getUnderMaterial(); BlocksHelper.setWithoutUpdate(world, mut, top); } else { @@ -156,10 +159,13 @@ public abstract class NBTStructureFeature extends DefaultFeature { else { if (stateSt.is(TagAPI.BLOCK_END_GROUND) && state.getMaterial().isSolidBlocking()) { if (merge == TerrainMerge.SURFACE) { - SurfaceBuilderConfiguration config = world.getBiome(mut) - .getGenerationSettings() - .getSurfaceBuilderConfig(); - BlocksHelper.setWithoutUpdate(world, mut, config.getUnderMaterial()); +// SurfaceBuilderConfiguration config = world.getBiome(mut) +// .getGenerationSettings() +// .getSurfaceBuilderConfig(); + BlockState bottom = Blocks.PURPLE_CONCRETE.defaultBlockState(); + //TODO: 1.18 find another way to get the Top Material + //config.getUnderMaterial() + BlocksHelper.setWithoutUpdate(world, mut, bottom); } else { BlocksHelper.setWithoutUpdate(world, mut, state); diff --git a/src/main/java/ru/bclib/world/generator/BCLibEndBiomeSource.java b/src/main/java/ru/bclib/world/generator/BCLibEndBiomeSource.java index 9cc4dc62..bfae3eed 100644 --- a/src/main/java/ru/bclib/world/generator/BCLibEndBiomeSource.java +++ b/src/main/java/ru/bclib/world/generator/BCLibEndBiomeSource.java @@ -9,15 +9,20 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome.BiomeCategory; import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.biome.Climate; import net.minecraft.world.level.biome.TheEndBiomeSource; +import net.minecraft.world.level.levelgen.LegacyRandomSource; import net.minecraft.world.level.levelgen.WorldgenRandom; import net.minecraft.world.level.levelgen.synth.SimplexNoise; import ru.bclib.BCLib; -import ru.bclib.api.BiomeAPI; +import ru.bclib.api.biomes.BiomeAPI; import ru.bclib.config.ConfigKeeper.StringArrayEntry; import ru.bclib.config.Configs; +import ru.bclib.interfaces.BiomeMap; import ru.bclib.noise.OpenSimplexNoise; import ru.bclib.world.biomes.BCLBiome; +import ru.bclib.world.generator.map.hex.HexBiomeMap; +import ru.bclib.world.generator.map.square.SquareBiomeMap; import java.awt.Point; import java.util.List; @@ -45,20 +50,35 @@ public class BCLibEndBiomeSource extends BiomeSource { public BCLibEndBiomeSource(Registry biomeRegistry, long seed) { super(getBiomes(biomeRegistry)); + BiomeAPI.initRegistry(biomeRegistry); BiomeAPI.END_LAND_BIOME_PICKER.clearMutables(); BiomeAPI.END_VOID_BIOME_PICKER.clearMutables(); - this.possibleBiomes.forEach(biome -> { + List includeVoid = Configs.BIOMES_CONFIG.getEntry("force_include", "end_void_biomes", StringArrayEntry.class).getValue(); + this.possibleBiomes().forEach(biome -> { ResourceLocation key = biomeRegistry.getKey(biome); if (!BiomeAPI.hasBiome(key)) { - BCLBiome bclBiome = new BCLBiome(key, biome, 1, 1); - BiomeAPI.END_LAND_BIOME_PICKER.addBiomeMutable(bclBiome); + String group = key.getNamespace() + "." + key.getPath(); + float chance = Configs.BIOMES_CONFIG.getFloat(group, "generation_chance", 1.0F); + float fog = Configs.BIOMES_CONFIG.getFloat(group, "fog_density", 1.0F); + BCLBiome bclBiome = new BCLBiome(key, biome).setGenChance(chance).setFogDensity(fog); + if (includeVoid.contains(key.toString())) { + BiomeAPI.END_VOID_BIOME_PICKER.addBiomeMutable(bclBiome); + } + else { + BiomeAPI.END_LAND_BIOME_PICKER.addBiomeMutable(bclBiome); + } } else { BCLBiome bclBiome = BiomeAPI.getBiome(key); - if (bclBiome != BiomeAPI.EMPTY_BIOME && !bclBiome.hasParentBiome()) { + if (bclBiome != BiomeAPI.EMPTY_BIOME && bclBiome.getParentBiome() == null) { if (!BiomeAPI.END_LAND_BIOME_PICKER.containsImmutable(key) && !BiomeAPI.END_VOID_BIOME_PICKER.containsImmutable(key)) { - BiomeAPI.END_LAND_BIOME_PICKER.addBiomeMutable(bclBiome); + if (includeVoid.contains(key.toString())) { + BiomeAPI.END_VOID_BIOME_PICKER.addBiomeMutable(bclBiome); + } + else { + BiomeAPI.END_LAND_BIOME_PICKER.addBiomeMutable(bclBiome); + } } } } @@ -72,14 +92,21 @@ public class BCLibEndBiomeSource extends BiomeSource { BiomeAPI.END_LAND_BIOME_PICKER.rebuild(); BiomeAPI.END_VOID_BIOME_PICKER.rebuild(); - this.mapLand = new BiomeMap(seed, GeneratorOptions.getBiomeSizeEndLand(), BiomeAPI.END_LAND_BIOME_PICKER); - this.mapVoid = new BiomeMap(seed, GeneratorOptions.getBiomeSizeEndVoid(), BiomeAPI.END_VOID_BIOME_PICKER); + if (GeneratorOptions.useOldBiomeGenerator()) { + this.mapLand = new SquareBiomeMap(seed, GeneratorOptions.getBiomeSizeEndLand(), BiomeAPI.END_LAND_BIOME_PICKER); + this.mapVoid = new SquareBiomeMap(seed, GeneratorOptions.getBiomeSizeEndVoid(), BiomeAPI.END_VOID_BIOME_PICKER); + } + else { + this.mapLand = new HexBiomeMap(seed, GeneratorOptions.getBiomeSizeEndLand(), BiomeAPI.END_LAND_BIOME_PICKER); + this.mapVoid = new HexBiomeMap(seed, GeneratorOptions.getBiomeSizeEndVoid(), BiomeAPI.END_VOID_BIOME_PICKER); + } + this.centerBiome = biomeRegistry.getOrThrow(Biomes.THE_END); this.barrens = biomeRegistry.getOrThrow(Biomes.END_BARRENS); this.biomeRegistry = biomeRegistry; this.seed = seed; - WorldgenRandom chunkRandom = new WorldgenRandom(seed); + WorldgenRandom chunkRandom = new WorldgenRandom(new LegacyRandomSource(seed)); chunkRandom.consumeCount(17292); this.noise = new SimplexNoise(chunkRandom); @@ -88,12 +115,13 @@ public class BCLibEndBiomeSource extends BiomeSource { } private static List getBiomes(Registry biomeRegistry) { - List include = Configs.BIOMES_CONFIG.getEntry("force_include", "end_biomes", StringArrayEntry.class).getValue(); + List includeLand = Configs.BIOMES_CONFIG.getEntry("force_include", "end_land_biomes", StringArrayEntry.class).getValue(); + List includeVoid = Configs.BIOMES_CONFIG.getEntry("force_include", "end_void_biomes", StringArrayEntry.class).getValue(); return biomeRegistry.stream().filter(biome -> { ResourceLocation key = biomeRegistry.getKey(biome); - if (include.contains(key.toString())) { + if (includeLand.contains(key.toString()) || includeVoid.contains(key.toString())) { return true; } @@ -103,7 +131,7 @@ public class BCLibEndBiomeSource extends BiomeSource { BCLBiome bclBiome = BiomeAPI.getBiome(key); if (bclBiome != BiomeAPI.EMPTY_BIOME) { - if (bclBiome.hasParentBiome()) { + if (bclBiome.getParentBiome() != null) { bclBiome = bclBiome.getParentBiome(); } key = bclBiome.getID(); @@ -113,7 +141,7 @@ public class BCLibEndBiomeSource extends BiomeSource { } @Override - public Biome getNoiseBiome(int biomeX, int biomeY, int biomeZ) { + public Biome getNoiseBiome(int biomeX, int biomeY, int biomeZ, Climate.Sampler sampler) { long i = (long) biomeX * (long) biomeX; long j = (long) biomeZ * (long) biomeZ; long check = GeneratorOptions.isFarEndBiomes() ? 65536L : 625L; diff --git a/src/main/java/ru/bclib/world/generator/BCLibNetherBiomeSource.java b/src/main/java/ru/bclib/world/generator/BCLibNetherBiomeSource.java index 6f26a475..11625350 100644 --- a/src/main/java/ru/bclib/world/generator/BCLibNetherBiomeSource.java +++ b/src/main/java/ru/bclib/world/generator/BCLibNetherBiomeSource.java @@ -8,17 +8,19 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome.BiomeCategory; import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.Climate; import ru.bclib.BCLib; -import ru.bclib.api.BiomeAPI; +import ru.bclib.api.biomes.BiomeAPI; import ru.bclib.config.ConfigKeeper.StringArrayEntry; import ru.bclib.config.Configs; +import ru.bclib.interfaces.BiomeMap; import ru.bclib.world.biomes.BCLBiome; +import ru.bclib.world.generator.map.hex.HexBiomeMap; +import ru.bclib.world.generator.map.square.SquareBiomeMap; -import java.util.LinkedList; import java.util.List; -import java.util.function.Consumer; -public class BCLibNetherBiomeSource extends BiomeSource { +public class BCLibNetherBiomeSource extends BiomeSource { public static final Codec CODEC = RecordCodecBuilder.create((instance) -> { return instance.group(RegistryLookupCodec.create(Registry.BIOME_REGISTRY).forGetter((theEndBiomeSource) -> { return theEndBiomeSource.biomeRegistry; @@ -29,24 +31,37 @@ public class BCLibNetherBiomeSource extends BiomeSource { private final Registry biomeRegistry; private BiomeMap biomeMap; private final long seed; - - @Deprecated(forRemoval = true) - public static final List> onInit = new LinkedList<>(); + private static boolean forceLegacyGenerator = false; + + /** + * When true, the older square generator is used for the nether. + * + * This override is used (for example) by BetterNether to force the legacy generation for worlds + * that were created before 1.18 + * @param val wether or not you want to force the old generatore. + */ + public static void setForceLegacyGeneration(boolean val){ + forceLegacyGenerator = val; + } public BCLibNetherBiomeSource(Registry biomeRegistry, long seed) { super(getBiomes(biomeRegistry)); + BiomeAPI.initRegistry(biomeRegistry); BiomeAPI.NETHER_BIOME_PICKER.clearMutables(); - this.possibleBiomes.forEach(biome -> { + this.possibleBiomes().forEach(biome -> { ResourceLocation key = biomeRegistry.getKey(biome); if (!BiomeAPI.hasBiome(key)) { - BCLBiome bclBiome = new BCLBiome(key, biome, 1, 1); + String group = key.getNamespace() + "." + key.getPath(); + float chance = Configs.BIOMES_CONFIG.getFloat(group, "generation_chance", 1.0F); + float fog = Configs.BIOMES_CONFIG.getFloat(group, "fog_density", 1.0F); + BCLBiome bclBiome = new BCLBiome(key, biome).setGenChance(chance).setFogDensity(fog); BiomeAPI.NETHER_BIOME_PICKER.addBiomeMutable(bclBiome); } else { BCLBiome bclBiome = BiomeAPI.getBiome(key); - if (bclBiome != BiomeAPI.EMPTY_BIOME && !bclBiome.hasParentBiome()) { + if (bclBiome != BiomeAPI.EMPTY_BIOME && bclBiome.getParentBiome() == null) { if (!BiomeAPI.NETHER_BIOME_PICKER.containsImmutable(key)) { BiomeAPI.NETHER_BIOME_PICKER.addBiomeMutable(bclBiome); } @@ -58,11 +73,15 @@ public class BCLibNetherBiomeSource extends BiomeSource { BiomeAPI.NETHER_BIOME_PICKER.getBiomes().forEach(biome -> biome.updateActualBiomes(biomeRegistry)); BiomeAPI.NETHER_BIOME_PICKER.rebuild(); - this.biomeMap = new BiomeMap(seed, GeneratorOptions.getBiomeSizeNether(), BiomeAPI.NETHER_BIOME_PICKER); + if (GeneratorOptions.useOldBiomeGenerator() || forceLegacyGenerator) { + this.biomeMap = new SquareBiomeMap(seed, GeneratorOptions.getBiomeSizeNether(), BiomeAPI.NETHER_BIOME_PICKER); + } + else { + this.biomeMap = new HexBiomeMap(seed, GeneratorOptions.getBiomeSizeNether(), BiomeAPI.NETHER_BIOME_PICKER); + } + this.biomeRegistry = biomeRegistry; this.seed = seed; - - onInit.forEach(consumer->consumer.accept(this)); } private static List getBiomes(Registry biomeRegistry) { @@ -81,7 +100,7 @@ public class BCLibNetherBiomeSource extends BiomeSource { BCLBiome bclBiome = BiomeAPI.getBiome(key); if (bclBiome != BiomeAPI.EMPTY_BIOME) { - if (bclBiome.hasParentBiome()) { + if (bclBiome.getParentBiome() != null) { bclBiome = bclBiome.getParentBiome(); } key = bclBiome.getID(); @@ -91,7 +110,7 @@ public class BCLibNetherBiomeSource extends BiomeSource { } @Override - public Biome getNoiseBiome(int biomeX, int biomeY, int biomeZ) { + public Biome getNoiseBiome(int biomeX, int biomeY, int biomeZ, Climate.Sampler var4) { if ((biomeX & 63) == 0 && (biomeZ & 63) == 0) { biomeMap.clearCache(); } diff --git a/src/main/java/ru/bclib/world/generator/GeneratorOptions.java b/src/main/java/ru/bclib/world/generator/GeneratorOptions.java index af5c084d..8cdf8911 100644 --- a/src/main/java/ru/bclib/world/generator/GeneratorOptions.java +++ b/src/main/java/ru/bclib/world/generator/GeneratorOptions.java @@ -16,6 +16,7 @@ public class GeneratorOptions { private static boolean customEndBiomeSource = true; private static boolean addNetherBiomesByCategory = false; private static boolean addEndBiomesByCategory = false; + private static boolean useOldBiomeGenerator = false; public static void init() { biomeSizeNether = Configs.GENERATOR_CONFIG.getInt("nether.biomeMap", "biomeSize", 256); @@ -25,6 +26,7 @@ public class GeneratorOptions { customEndBiomeSource = Configs.GENERATOR_CONFIG.getBoolean("options", "customEndBiomeSource", true); addNetherBiomesByCategory = Configs.GENERATOR_CONFIG.getBoolean("options", "addNetherBiomesByCategory", false); addEndBiomesByCategory = Configs.GENERATOR_CONFIG.getBoolean("options", "addEndBiomesByCategory", false); + useOldBiomeGenerator = Configs.GENERATOR_CONFIG.getBoolean("options", "useOldBiomeGenerator", false); } public static int getBiomeSizeNether() { @@ -70,4 +72,8 @@ public class GeneratorOptions { public static boolean addEndBiomesByCategory() { return addEndBiomesByCategory; } + + public static boolean useOldBiomeGenerator() { + return useOldBiomeGenerator; + } } diff --git a/src/main/java/ru/bclib/world/generator/map/hex/HexBiomeChunk.java b/src/main/java/ru/bclib/world/generator/map/hex/HexBiomeChunk.java new file mode 100644 index 00000000..0edd9a8f --- /dev/null +++ b/src/main/java/ru/bclib/world/generator/map/hex/HexBiomeChunk.java @@ -0,0 +1,133 @@ +package ru.bclib.world.generator.map.hex; + +import ru.bclib.world.biomes.BCLBiome; +import ru.bclib.world.generator.BiomePicker; + +import java.util.Random; + +public class HexBiomeChunk { + private static final short SIDE = 32; + private static final short SIZE = SIDE * SIDE; + private static final byte SIDE_MASK = SIDE - 1; + private static final byte SIDE_OFFSET = (byte) Math.round(Math.log(SIDE) / Math.log(2)); + private static final short[][] NEIGHBOURS; + public static final short SCALE = SIDE / 4; + + private final BCLBiome[] biomes; + + public HexBiomeChunk(Random random, BiomePicker picker) { + BCLBiome[][] buffers = new BCLBiome[2][SIZE]; + + byte scale = SIDE / 4; + for (byte x = 0; x < 4; x++) { + for (byte z = 0; z < 4; z++) { + byte px = (byte) (x * scale + random.nextInt(scale)); + byte pz = (byte) (z * scale + random.nextInt(scale)); + circle(buffers[0], getIndex(px, pz), picker.getBiome(random), null); + } + } + + short maxSide = SIZE - SIDE; + boolean hasEmptyCells = true; + byte bufferIndex = 0; + while (hasEmptyCells) { + BCLBiome[] inBuffer = buffers[bufferIndex]; + bufferIndex = (byte) ((bufferIndex + 1) & 1); + BCLBiome[] outBuffer = buffers[bufferIndex]; + hasEmptyCells = false; + + for (short index = SIDE; index < maxSide; index++) { + byte z = (byte) (index & SIDE_MASK); + if (z == 0 || z == SIDE_MASK) { + continue; + } + if (inBuffer[index] != null) { + outBuffer[index] = inBuffer[index]; + short[] neighbours = getNeighbours(index & SIDE_MASK); + short indexSide = (short) (index + neighbours[random.nextInt(6)]); + if (indexSide >= 0 && indexSide < SIZE && outBuffer[indexSide] == null) { + outBuffer[indexSide] = inBuffer[index]; + } + } + else { + hasEmptyCells = true; + } + } + } + + BCLBiome[] outBuffer = buffers[bufferIndex]; + byte preN = (byte) (SIDE_MASK - 2); + for (byte index = 0; index < SIDE; index++) { + outBuffer[getIndex(index, (byte) 0)] = outBuffer[getIndex(index, (byte) 2)]; + outBuffer[getIndex((byte) 0, index)] = outBuffer[getIndex((byte) 2, index)]; + outBuffer[getIndex(index, SIDE_MASK)] = outBuffer[getIndex(index, preN)]; + outBuffer[getIndex(SIDE_MASK, index)] = outBuffer[getIndex(preN, index)]; + } + + for (short index = 0; index < SIZE; index++) { + if (outBuffer[index] == null) { + outBuffer[index] = picker.getBiome(random); + } + else if (random.nextInt(4) == 0) { + circle(outBuffer, index, outBuffer[index].getSubBiome(random), outBuffer[index]); + } + } + + this.biomes = outBuffer; + } + + private void circle(BCLBiome[] buffer, short center, BCLBiome biome, BCLBiome mask) { + if (buffer[center] == mask) { + buffer[center] = biome; + } + short[] neighbours = getNeighbours(center & SIDE_MASK); + for (short i: neighbours) { + short index = (short) (center + i); + if (index >= 0 && index < SIZE && buffer[index] == mask) { + buffer[index] = biome; + } + } + } + + private static byte wrap(int value) { + return (byte) (value & SIDE_MASK); + } + + private short getIndex(byte x, byte z) { + return (short) ((short) x << SIDE_OFFSET | z); + } + + public BCLBiome getBiome(int x, int z) { + return biomes[getIndex(wrap(x), wrap(z))]; + } + + public static int scaleCoordinate(int value) { + return value >> SIDE_OFFSET; + } + + public static boolean isBorder(int value) { + return wrap(value) == SIDE_MASK; + } + + private short[] getNeighbours(int z) { + return NEIGHBOURS[z & 1]; + } + + static { + NEIGHBOURS = new short[2][6]; + + NEIGHBOURS[0][0] = 1; + NEIGHBOURS[0][1] = -1; + NEIGHBOURS[0][2] = SIDE; + NEIGHBOURS[0][3] = -SIDE; + NEIGHBOURS[0][4] = SIDE + 1; + NEIGHBOURS[0][5] = SIDE - 1; + + NEIGHBOURS[1][0] = 1; + NEIGHBOURS[1][1] = -1; + NEIGHBOURS[1][2] = SIDE; + NEIGHBOURS[1][3] = -SIDE; + NEIGHBOURS[1][4] = -SIDE + 1; + NEIGHBOURS[1][5] = -SIDE - 1; + } +} diff --git a/src/main/java/ru/bclib/world/generator/map/hex/HexBiomeMap.java b/src/main/java/ru/bclib/world/generator/map/hex/HexBiomeMap.java new file mode 100644 index 00000000..f7ed1e8e --- /dev/null +++ b/src/main/java/ru/bclib/world/generator/map/hex/HexBiomeMap.java @@ -0,0 +1,166 @@ +package ru.bclib.world.generator.map.hex; + +import ru.bclib.interfaces.BiomeMap; +import ru.bclib.noise.OpenSimplexNoise; +import ru.bclib.util.MHelper; +import ru.bclib.world.biomes.BCLBiome; +import ru.bclib.world.generator.BiomePicker; + +import java.awt.Point; +import java.util.HashMap; +import java.util.Random; + +public class HexBiomeMap implements BiomeMap { + private static final float RAD_INNER = (float) Math.sqrt(3.0) * 0.5F; + private static final float COEF = 0.25F * (float) Math.sqrt(3.0); + private static final float COEF_HALF = COEF * 0.5F; + private static final float SIN = (float) Math.sin(0.4); + private static final float COS = (float) Math.cos(0.4); + private static final Random RANDOM = new Random(); + private static final float[] EDGE_CIRCLE_X; + private static final float[] EDGE_CIRCLE_Z; + + private final HashMap chunks = new HashMap<>(); + private final Point selector = new Point(); + private final BiomePicker picker; + + private final OpenSimplexNoise[] noises = new OpenSimplexNoise[2]; + private final byte noiseIterations; + private final float scale; + private final int seed; + + public HexBiomeMap(long seed, int size, BiomePicker picker) { + this.picker = picker; + this.scale = (float) size / HexBiomeChunk.SCALE; + Random random = new Random(seed); + noises[0] = new OpenSimplexNoise(random.nextInt()); + noises[1] = new OpenSimplexNoise(random.nextInt()); + noiseIterations = (byte) Math.min(Math.ceil(Math.log(scale) / Math.log(2)), 5); + this.seed = (int) (seed & 0xFFFFFFFF); + } + + @Override + public void clearCache() { + if (chunks.size() > 127) { + chunks.clear(); + } + } + + @Override + public BCLBiome getBiome(double x, double z) { + BCLBiome biome = getRawBiome(x, z); + if (biome.getEdge() != null) { + float offset = scale * biome.getEdgeSize(); + for (byte i = 0; i < 8; i++) { + if (getRawBiome(x + offset * EDGE_CIRCLE_X[i], z + offset * EDGE_CIRCLE_Z[i]) != biome) { + return biome.getEdge(); + } + } + } + return biome; + } + + private BCLBiome getRawBiome(double x, double z) { + double px = x / scale * RAD_INNER; + double pz = z / scale; + double dx = rotateX(px, pz); + double dz = rotateZ(px, pz); + px = dx; + pz = dz; + + dx = getNoise(px, pz, (byte) 0) * 0.2F; + dz = getNoise(pz, px, (byte) 1) * 0.2F; + px += dx; + pz += dz; + + int cellZ = (int) Math.floor(pz); + boolean offset = (cellZ & 1) == 1; + + if (offset) { + px += 0.5; + } + + int cellX = (int) Math.floor(px); + + float pointX = (float) (px - cellX - 0.5); + float pointZ = (float) (pz - cellZ - 0.5); + + if (Math.abs(pointZ) < 0.3333F) { + return getChunkBiome(cellX, cellZ); + } + + if (insideHexagon(0, 0, 1.1555F, pointZ * RAD_INNER, pointX)) { + return getChunkBiome(cellX, cellZ); + } + + cellX = pointX < 0 ? (offset ? cellX - 1 : cellX) : (offset ? cellX : cellX + 1); + cellZ = pointZ < 0 ? cellZ - 1 : cellZ + 1; + + return getChunkBiome(cellX, cellZ); + } + + private BCLBiome getChunkBiome(int x, int z) { + int cx = HexBiomeChunk.scaleCoordinate(x); + int cz = HexBiomeChunk.scaleCoordinate(z); + + if (((z >> 2) & 1) == 0 && HexBiomeChunk.isBorder(x)) { + x = 0; + cx += 1; + } + else if (((x >> 2) & 1) == 0 && HexBiomeChunk.isBorder(z)) { + z = 0; + cz += 1; + } + + HexBiomeChunk chunk; + synchronized (selector) { + selector.setLocation(cx, cz); + chunk = chunks.get(selector); + } + + if (chunk == null) { + synchronized (RANDOM) { + RANDOM.setSeed(MHelper.getSeed(seed, cx, cz)); + chunk = new HexBiomeChunk(RANDOM, picker); + } + chunks.put(new Point(cx, cz), chunk); + } + + return chunk.getBiome(x, z); + } + + private boolean insideHexagon(float centerX, float centerZ, float radius, float x, float z) { + double dx = Math.abs(x - centerX) / radius; + double dy = Math.abs(z - centerZ) / radius; + return (dy <= COEF) && (COEF * dx + 0.25F * dy <= COEF_HALF); + } + + private double getNoise(double x, double z, byte state) { + double result = 0; + for (byte i = 1; i <= noiseIterations; i++) { + OpenSimplexNoise noise = noises[state]; + state = (byte) ((state + 1) & 1); + result += noise.eval(x * i, z * i) / i; + } + return result; + } + + private double rotateX(double x, double z) { + return x * COS - z * SIN; + } + + private double rotateZ(double x, double z) { + return x * SIN + z * COS; + } + + static { + EDGE_CIRCLE_X = new float[8]; + EDGE_CIRCLE_Z = new float[8]; + + for (byte i = 0; i < 8; i++) { + float angle = i / 4F * (float) Math.PI; + EDGE_CIRCLE_X[i] = (float) Math.sin(angle); + EDGE_CIRCLE_Z[i] = (float) Math.cos(angle); + } + } +} diff --git a/src/main/java/ru/bclib/world/generator/BiomeChunk.java b/src/main/java/ru/bclib/world/generator/map/square/SquareBiomeChunk.java similarity index 88% rename from src/main/java/ru/bclib/world/generator/BiomeChunk.java rename to src/main/java/ru/bclib/world/generator/map/square/SquareBiomeChunk.java index d424462e..c4d366b6 100644 --- a/src/main/java/ru/bclib/world/generator/BiomeChunk.java +++ b/src/main/java/ru/bclib/world/generator/map/square/SquareBiomeChunk.java @@ -1,54 +1,55 @@ -package ru.bclib.world.generator; - -import ru.bclib.world.biomes.BCLBiome; - -import java.util.Random; - -public class BiomeChunk { - private static final int BIT_OFFSET = 4; - protected static final int WIDTH = 1 << BIT_OFFSET; - private static final int SM_WIDTH = WIDTH >> 1; - private static final int SM_BIT_OFFSET = BIT_OFFSET >> 1; - private static final int MASK_OFFSET = SM_WIDTH - 1; - protected static final int MASK_WIDTH = WIDTH - 1; - - private static final int SM_CAPACITY = SM_WIDTH * SM_WIDTH; - private static final int CAPACITY = WIDTH * WIDTH; - - private final BCLBiome[] biomes; - - public BiomeChunk(BiomeMap map, Random random, BiomePicker picker) { - BCLBiome[] PreBio = new BCLBiome[SM_CAPACITY]; - biomes = new BCLBiome[CAPACITY]; - - for (int x = 0; x < SM_WIDTH; x++) { - int offset = x << SM_BIT_OFFSET; - for (int z = 0; z < SM_WIDTH; z++) { - PreBio[offset | z] = picker.getBiome(random); - } - } - - for (int x = 0; x < WIDTH; x++) { - int offset = x << BIT_OFFSET; - for (int z = 0; z < WIDTH; z++) { - biomes[offset | z] = PreBio[getSmIndex(offsetXZ(x, random), offsetXZ(z, random))].getSubBiome(random); - } - } - } - - public BCLBiome getBiome(int x, int z) { - return biomes[getIndex(x & MASK_WIDTH, z & MASK_WIDTH)]; - } - - private int offsetXZ(int x, Random random) { - return ((x + random.nextInt(2)) >> 1) & MASK_OFFSET; - } - - private int getIndex(int x, int z) { - return x << BIT_OFFSET | z; - } - - private int getSmIndex(int x, int z) { - return x << SM_BIT_OFFSET | z; - } -} +package ru.bclib.world.generator.map.square; + +import ru.bclib.world.biomes.BCLBiome; +import ru.bclib.world.generator.BiomePicker; + +import java.util.Random; + +public class SquareBiomeChunk { + private static final int BIT_OFFSET = 4; + protected static final int WIDTH = 1 << BIT_OFFSET; + private static final int SM_WIDTH = WIDTH >> 1; + private static final int SM_BIT_OFFSET = BIT_OFFSET >> 1; + private static final int MASK_OFFSET = SM_WIDTH - 1; + protected static final int MASK_WIDTH = WIDTH - 1; + + private static final int SM_CAPACITY = SM_WIDTH * SM_WIDTH; + private static final int CAPACITY = WIDTH * WIDTH; + + private final BCLBiome[] biomes; + + public SquareBiomeChunk(Random random, BiomePicker picker) { + BCLBiome[] PreBio = new BCLBiome[SM_CAPACITY]; + biomes = new BCLBiome[CAPACITY]; + + for (int x = 0; x < SM_WIDTH; x++) { + int offset = x << SM_BIT_OFFSET; + for (int z = 0; z < SM_WIDTH; z++) { + PreBio[offset | z] = picker.getBiome(random); + } + } + + for (int x = 0; x < WIDTH; x++) { + int offset = x << BIT_OFFSET; + for (int z = 0; z < WIDTH; z++) { + biomes[offset | z] = PreBio[getSmIndex(offsetXZ(x, random), offsetXZ(z, random))].getSubBiome(random); + } + } + } + + public BCLBiome getBiome(int x, int z) { + return biomes[getIndex(x & MASK_WIDTH, z & MASK_WIDTH)]; + } + + private int offsetXZ(int x, Random random) { + return ((x + random.nextInt(2)) >> 1) & MASK_OFFSET; + } + + private int getIndex(int x, int z) { + return x << BIT_OFFSET | z; + } + + private int getSmIndex(int x, int z) { + return x << SM_BIT_OFFSET | z; + } +} diff --git a/src/main/java/ru/bclib/world/generator/BiomeMap.java b/src/main/java/ru/bclib/world/generator/map/square/SquareBiomeMap.java similarity index 56% rename from src/main/java/ru/bclib/world/generator/BiomeMap.java rename to src/main/java/ru/bclib/world/generator/map/square/SquareBiomeMap.java index 9de76325..6c523db8 100644 --- a/src/main/java/ru/bclib/world/generator/BiomeMap.java +++ b/src/main/java/ru/bclib/world/generator/map/square/SquareBiomeMap.java @@ -1,112 +1,113 @@ -package ru.bclib.world.generator; - -import com.google.common.collect.Maps; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.levelgen.WorldgenRandom; -import ru.bclib.noise.OpenSimplexNoise; -import ru.bclib.util.MHelper; -import ru.bclib.world.biomes.BCLBiome; - -import java.util.Map; - -public class BiomeMap { - private static final WorldgenRandom RANDOM = new WorldgenRandom(); - - private final Map maps = Maps.newHashMap(); - private final int size; - private final int sizeXZ; - private final int depth; - private final OpenSimplexNoise noiseX; - private final OpenSimplexNoise noiseZ; - private final BiomePicker picker; - private final long seed; - - public BiomeMap(long seed, int size, BiomePicker picker) { - maps.clear(); - RANDOM.setSeed(seed); - noiseX = new OpenSimplexNoise(RANDOM.nextLong()); - noiseZ = new OpenSimplexNoise(RANDOM.nextLong()); - this.sizeXZ = size; - depth = (int) Math.ceil(Math.log(size) / Math.log(2)) - 2; - this.size = 1 << depth; - this.picker = picker; - this.seed = seed; - } - - public long getSeed() { - return seed; - } - - public void clearCache() { - if (maps.size() > 32) { - maps.clear(); - } - } - - private BCLBiome getRawBiome(int bx, int bz) { - double x = (double) bx * size / sizeXZ; - double z = (double) bz * size / sizeXZ; - double nx = x; - double nz = z; - - double px = bx * 0.2; - double pz = bz * 0.2; - - for (int i = 0; i < depth; i++) { - nx = (x + noiseX.eval(px, pz)) / 2F; - nz = (z + noiseZ.eval(px, pz)) / 2F; - - x = nx; - z = nz; - - px = px / 2 + i; - pz = pz / 2 + i; - } - - bx = MHelper.floor(x); - bz = MHelper.floor(z); - if ((bx & BiomeChunk.MASK_WIDTH) == BiomeChunk.MASK_WIDTH) { - x += (bz / 2) & 1; - } - if ((bz & BiomeChunk.MASK_WIDTH) == BiomeChunk.MASK_WIDTH) { - z += (bx / 2) & 1; - } - - ChunkPos cpos = new ChunkPos(MHelper.floor(x / BiomeChunk.WIDTH), MHelper.floor(z / BiomeChunk.WIDTH)); - BiomeChunk chunk = maps.get(cpos); - if (chunk == null) { - RANDOM.setBaseChunkSeed(cpos.x, cpos.z); - chunk = new BiomeChunk(this, RANDOM, picker); - maps.put(cpos, chunk); - } - - return chunk.getBiome(MHelper.floor(x), MHelper.floor(z)); - } - - public BCLBiome getBiome(int x, int z) { - BCLBiome biome = getRawBiome(x, z); - - if (biome.hasEdge() || (biome.hasParentBiome() && biome.getParentBiome().hasEdge())) { - BCLBiome search = biome; - if (biome.hasParentBiome()) { - search = biome.getParentBiome(); - } - int d = (int) Math.ceil(search.getEdgeSize() / 4F) << 2; - - boolean edge = !search.isSame(getRawBiome(x + d, z)); - edge = edge || !search.isSame(getRawBiome(x - d, z)); - edge = edge || !search.isSame(getRawBiome(x, z + d)); - edge = edge || !search.isSame(getRawBiome(x, z - d)); - edge = edge || !search.isSame(getRawBiome(x - 1, z - 1)); - edge = edge || !search.isSame(getRawBiome(x - 1, z + 1)); - edge = edge || !search.isSame(getRawBiome(x + 1, z - 1)); - edge = edge || !search.isSame(getRawBiome(x + 1, z + 1)); - - if (edge) { - biome = search.getEdge(); - } - } - - return biome; - } -} +package ru.bclib.world.generator.map.square; + +import com.google.common.collect.Maps; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.levelgen.LegacyRandomSource; +import net.minecraft.world.level.levelgen.WorldgenRandom; +import ru.bclib.interfaces.BiomeMap; +import ru.bclib.noise.OpenSimplexNoise; +import ru.bclib.util.MHelper; +import ru.bclib.world.biomes.BCLBiome; +import ru.bclib.world.generator.BiomePicker; + +import java.util.Map; + +public class SquareBiomeMap implements BiomeMap { + private final Map maps = Maps.newHashMap(); + private final OpenSimplexNoise noiseX; + private final OpenSimplexNoise noiseZ; + private final WorldgenRandom random; + private final BiomePicker picker; + + private final long seed; + private final int sizeXZ; + private final int depth; + private final int size; + + public SquareBiomeMap(long seed, int size, BiomePicker picker) { + maps.clear(); + random = new WorldgenRandom(new LegacyRandomSource(seed)); + noiseX = new OpenSimplexNoise(random.nextLong()); + noiseZ = new OpenSimplexNoise(random.nextLong()); + this.sizeXZ = size; + depth = (int) Math.ceil(Math.log(size) / Math.log(2)) - 2; + this.size = 1 << depth; + this.picker = picker; + this.seed = seed; + } + + @Override + public void clearCache() { + if (maps.size() > 32) { + maps.clear(); + } + } + + @Override + public BCLBiome getBiome(double x, double z) { + BCLBiome biome = getRawBiome(x, z); + + if (biome.getEdge() != null || (biome.getParentBiome() != null && biome.getParentBiome().getEdge() != null)) { + BCLBiome search = biome; + if (biome.getParentBiome() != null) { + search = biome.getParentBiome(); + } + int d = (int) Math.ceil(search.getEdgeSize() / 4F) << 2; + + boolean edge = !search.isSame(getRawBiome(x + d, z)); + edge = edge || !search.isSame(getRawBiome(x - d, z)); + edge = edge || !search.isSame(getRawBiome(x, z + d)); + edge = edge || !search.isSame(getRawBiome(x, z - d)); + edge = edge || !search.isSame(getRawBiome(x - 1, z - 1)); + edge = edge || !search.isSame(getRawBiome(x - 1, z + 1)); + edge = edge || !search.isSame(getRawBiome(x + 1, z - 1)); + edge = edge || !search.isSame(getRawBiome(x + 1, z + 1)); + + if (edge) { + biome = search.getEdge(); + } + } + + return biome; + } + + private BCLBiome getRawBiome(double bx, double bz) { + double x = bx * size / sizeXZ; + double z = bz * size / sizeXZ; + double nx = x; + double nz = z; + + double px = bx * 0.2; + double pz = bz * 0.2; + + for (int i = 0; i < depth; i++) { + nx = (x + noiseX.eval(px, pz)) / 2F; + nz = (z + noiseZ.eval(px, pz)) / 2F; + + x = nx; + z = nz; + + px = px / 2 + i; + pz = pz / 2 + i; + } + + int ix = MHelper.floor(x); + int iz = MHelper.floor(z); + if ((ix & SquareBiomeChunk.MASK_WIDTH) == SquareBiomeChunk.MASK_WIDTH) { + x += (iz / 2) & 1; + } + if ((iz & SquareBiomeChunk.MASK_WIDTH) == SquareBiomeChunk.MASK_WIDTH) { + z += (ix / 2) & 1; + } + + ChunkPos cpos = new ChunkPos(MHelper.floor(x / SquareBiomeChunk.WIDTH), MHelper.floor(z / SquareBiomeChunk.WIDTH)); + SquareBiomeChunk chunk = maps.get(cpos); + if (chunk == null) { + random.setLargeFeatureWithSalt(0, cpos.x, cpos.z, 0); + chunk = new SquareBiomeChunk(random, picker); + maps.put(cpos, chunk); + } + + return chunk.getBiome(MHelper.floor(x), MHelper.floor(z)); + } +} diff --git a/src/main/java/ru/bclib/world/processors/TerrainStructureProcessor.java b/src/main/java/ru/bclib/world/processors/TerrainStructureProcessor.java index 1f758427..bcb70630 100644 --- a/src/main/java/ru/bclib/world/processors/TerrainStructureProcessor.java +++ b/src/main/java/ru/bclib/world/processors/TerrainStructureProcessor.java @@ -14,10 +14,12 @@ public class TerrainStructureProcessor extends StructureProcessor { public StructureBlockInfo processBlock(LevelReader worldView, BlockPos pos, BlockPos blockPos, StructureBlockInfo structureBlockInfo, StructureBlockInfo structureBlockInfo2, StructurePlaceSettings structurePlacementData) { BlockPos bpos = structureBlockInfo2.pos; if (structureBlockInfo2.state.is(Blocks.END_STONE) && worldView.isEmptyBlock(bpos.above())) { - BlockState top = worldView.getBiome(structureBlockInfo2.pos) - .getGenerationSettings() - .getSurfaceBuilderConfig() - .getTopMaterial(); + BlockState top = Blocks.PURPLE_CONCRETE.defaultBlockState(); + //TODO: 1.18 find another way to get the Top Materiel +// worldView.getBiome(structureBlockInfo2.pos) +// .getGenerationSettings() +// .getSurfaceBuilderConfig() +// .getTopMaterial(); return new StructureBlockInfo(bpos, top, structureBlockInfo2.nbt); } return structureBlockInfo2; diff --git a/src/main/java/ru/bclib/world/structures/BCLStructureFeature.java b/src/main/java/ru/bclib/world/structures/BCLStructureFeature.java index 4497bfc7..5688a59d 100644 --- a/src/main/java/ru/bclib/world/structures/BCLStructureFeature.java +++ b/src/main/java/ru/bclib/world/structures/BCLStructureFeature.java @@ -1,7 +1,7 @@ package ru.bclib.world.structures; +import com.google.common.collect.Lists; import net.fabricmc.fabric.api.structure.v1.FabricStructureBuilder; -import net.fabricmc.fabric.mixin.structure.FlatChunkGeneratorConfigAccessor; import net.minecraft.data.BuiltinRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.levelgen.GenerationStep; @@ -9,6 +9,7 @@ import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; import net.minecraft.world.level.levelgen.feature.StructureFeature; import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration; +import java.util.List; import java.util.Random; public class BCLStructureFeature { @@ -16,16 +17,21 @@ public class BCLStructureFeature { private final StructureFeature structure; private final ConfiguredStructureFeature featureConfigured; private final GenerationStep.Decoration featureStep; + private final List biomes = Lists.newArrayList(); + private final ResourceLocation id; public BCLStructureFeature(ResourceLocation id, StructureFeature structure, GenerationStep.Decoration step, int spacing, int separation) { + this.id = id; this.featureStep = step; - this.structure = FabricStructureBuilder.create(id, structure) - .step(step) - .defaultConfig(spacing, separation, RANDOM.nextInt(8192)) - .register(); + this.structure = FabricStructureBuilder + .create(id, structure) + .step(step) + .defaultConfig(spacing, separation, RANDOM.nextInt(8192)) + .register(); this.featureConfigured = this.structure.configured(NoneFeatureConfiguration.NONE); BuiltinRegistries.register(BuiltinRegistries.CONFIGURED_STRUCTURE_FEATURE, id, this.featureConfigured); - FlatChunkGeneratorConfigAccessor.getStructureToFeatures().put(this.structure, this.featureConfigured); + //TODO: 1.18 check if structures are added correctly + //FlatChunkGeneratorConfigAccessor.getStructureToFeatures().put(this.structure, this.featureConfigured); } public StructureFeature getStructure() { @@ -39,4 +45,29 @@ public class BCLStructureFeature { public GenerationStep.Decoration getFeatureStep() { return featureStep; } + + /** + * Get the structure ID; + * @return {@link ResourceLocation} id. + */ + public ResourceLocation getID() { + return id; + } + + /** + * Adds biome into internal biome list, used in {@link ru.bclib.api.biomes.BCLBiomeBuilder}. + * @param biome {@link ResourceLocation} biome ID. + */ + public void addInternalBiome(ResourceLocation biome) { + biomes.add(biome); + } + + /** + * Get biome list where this structure feature can generate. Only represents biomes made with {@link ru.bclib.api.biomes.BCLBiomeBuilder} and only + * if structure was added during building process. Modification of this list will not affect structure generation. + * @return {@link List} of biome {@link ResourceLocation}. + */ + public List getBiomes() { + return biomes; + } } diff --git a/src/main/java/ru/bclib/world/surface/BCLSurfaceBuilders.java b/src/main/java/ru/bclib/world/surface/BCLSurfaceBuilders.java deleted file mode 100644 index 641eeace..00000000 --- a/src/main/java/ru/bclib/world/surface/BCLSurfaceBuilders.java +++ /dev/null @@ -1,20 +0,0 @@ -package ru.bclib.world.surface; - -import net.minecraft.core.Registry; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.surfacebuilders.SurfaceBuilder; -import net.minecraft.world.level.levelgen.surfacebuilders.SurfaceBuilderBaseConfiguration; - -public class BCLSurfaceBuilders { - public static SurfaceBuilder register(String name, SurfaceBuilder builder) { - return Registry.register(Registry.SURFACE_BUILDER, name, builder); - } - - public static SurfaceBuilderBaseConfiguration makeSimpleConfig(Block block) { - BlockState state = block.defaultBlockState(); - return new SurfaceBuilderBaseConfiguration(state, state, state); - } - - public static void register() {} -} diff --git a/src/main/java/ru/bclib/world/surface/DoubleBlockSurfaceBuilder.java b/src/main/java/ru/bclib/world/surface/DoubleBlockSurfaceBuilder.java deleted file mode 100644 index 434b1a39..00000000 --- a/src/main/java/ru/bclib/world/surface/DoubleBlockSurfaceBuilder.java +++ /dev/null @@ -1,66 +0,0 @@ -package ru.bclib.world.surface; - -import net.minecraft.core.Registry; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.levelgen.surfacebuilders.ConfiguredSurfaceBuilder; -import net.minecraft.world.level.levelgen.surfacebuilders.SurfaceBuilder; -import net.minecraft.world.level.levelgen.surfacebuilders.SurfaceBuilderBaseConfiguration; -import ru.bclib.noise.OpenSimplexNoise; -import ru.bclib.util.MHelper; - -import java.util.Random; - -public class DoubleBlockSurfaceBuilder extends SurfaceBuilder { - private static final OpenSimplexNoise NOISE = new OpenSimplexNoise(4141); - private SurfaceBuilderBaseConfiguration config1; - private SurfaceBuilderBaseConfiguration config2; - - private DoubleBlockSurfaceBuilder() { - super(SurfaceBuilderBaseConfiguration.CODEC); - } - - public DoubleBlockSurfaceBuilder setBlock1(Block block) { - BlockState stone = Blocks.END_STONE.defaultBlockState(); - config1 = new SurfaceBuilderBaseConfiguration(block.defaultBlockState(), stone, stone); - return this; - } - - public DoubleBlockSurfaceBuilder setBlock2(Block block) { - BlockState stone = Blocks.END_STONE.defaultBlockState(); - config2 = new SurfaceBuilderBaseConfiguration(block.defaultBlockState(), stone, stone); - return this; - } - - public static DoubleBlockSurfaceBuilder register(String name) { - return Registry.register(Registry.SURFACE_BUILDER, name, new DoubleBlockSurfaceBuilder()); - } - - public ConfiguredSurfaceBuilder configured() { - BlockState stone = Blocks.END_STONE.defaultBlockState(); - return this.configured(new SurfaceBuilderBaseConfiguration(config1.getTopMaterial(), stone, stone)); - } - - @Override - public void apply(Random random, ChunkAccess chunkAccess, Biome biome, int x, int z, int height, double noise, BlockState defaultBlock, BlockState defaultFluid, int l, int m, long seed, SurfaceBuilderBaseConfiguration surfaceBuilderConfiguration) { - noise = NOISE.eval(x * 0.1, z * 0.1) + MHelper.randRange(-0.4, 0.4, random); - SurfaceBuilder.DEFAULT.apply( - random, - chunkAccess, - biome, - x, - z, - height, - noise, - defaultBlock, - defaultFluid, - l, - m, - seed, - noise > 0 ? config1 : config2 - ); - } -} \ No newline at end of file diff --git a/src/main/resources/bclib.mixins.client.json b/src/main/resources/bclib.mixins.client.json index 3d87e139..b633a525 100644 --- a/src/main/resources/bclib.mixins.client.json +++ b/src/main/resources/bclib.mixins.client.json @@ -2,18 +2,19 @@ "required": true, "minVersion": "0.8", "package": "ru.bclib.mixin.client", - "compatibilityLevel": "JAVA_16", + "compatibilityLevel": "JAVA_17", "client": [ - "AnvilScreenMixin", + "SimpleReloadableResourceManagerMixin", + "EnchantingTableBlockMixin", "BackgroundRendererMixin", "ClientRecipeBookMixin", - "EnchantingTableBlockMixin", - "GameMixin", - "MinecraftMixin", - "ModelBakeryMixin", "ModelManagerMixin", - "SimpleReloadableResourceManagerMixin", - "TextureAtlasMixin" + "TextureAtlasMixin", + "AnvilScreenMixin", + "ModelBakeryMixin", + "MinecraftMixin", + "GameMixin", + "GameMixin" ], "injectors": { "defaultRequire": 1 diff --git a/src/main/resources/bclib.mixins.common.json b/src/main/resources/bclib.mixins.common.json index 3f39c3ef..8716bd49 100644 --- a/src/main/resources/bclib.mixins.common.json +++ b/src/main/resources/bclib.mixins.common.json @@ -2,37 +2,43 @@ "required": true, "minVersion": "0.8", "package": "ru.bclib.mixin.common", - "compatibilityLevel": "JAVA_16", + "compatibilityLevel": "JAVA_17", "mixins": [ - "AnvilBlockMixin", - "AnvilMenuMixin", - "BiomeMixin", - "BoneMealItemMixin", - "ChunkBiomeContainerMixin", - "ComposterBlockAccessor", - "CraftingMenuMixin", - "DimensionTypeMixin", - "EnchantmentMenuMixin", - "InternalBiomeDataMixin", + "SimpleReloadableResourceManagerMixin", + "BiomeGenerationSettingsAccessor", + "shears.DiggingEnchantmentMixin", "LayerLightSectionStorageMixin", - "MainMixin", - "MinecraftServerMixin", - "PistonBaseBlockMixin", - "PortalShapeMixin", + "NoiseGeneratorSettingsMixin", + "shears.TripWireBlockMixin", + "StructureSettingsAccessor", + "MobSpawnSettingsAccessor", + "shears.BeehiveBlockMixin", + "shears.PumpkinBlockMixin", + "shears.MushroomCowMixin", + "ComposterBlockAccessor", "PotionBrewingAccessor", "RecipeManagerAccessor", - "RecipeManagerMixin", - "ServerLevelMixin", - "SimpleReloadableResourceManagerMixin", - "TagLoaderMixin", - "WorldGenRegionMixin", - "shears.BeehiveBlockMixin", - "shears.DiggingEnchantmentMixin", - "shears.MushroomCowMixin", - "shears.PumpkinBlockMixin", - "shears.SheepMixin", "shears.SnowGolemMixin", - "shears.TripWireBlockMixin" + "EnchantmentMenuMixin", + "MinecraftServerMixin", + "NetherBiomeDataMixin", + "PistonBaseBlockMixin", + "TheEndBiomeDataMixin", + "ChunkGeneratorMixin", + "WorldGenRegionMixin", + "DimensionTypeMixin", + "RecipeManagerMixin", + "RecipeManagerMixin", + "BoneMealItemMixin", + "CraftingMenuMixin", + "shears.SheepMixin", + "PortalShapeMixin", + "ServerLevelMixin", + "WorldPresetMixin", + "AnvilBlockMixin", + "AnvilMenuMixin", + "TagLoaderMixin", + "MainMixin" ], "injectors": { "defaultRequire": 1 diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index d49eb0a9..4af9010c 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -28,15 +28,14 @@ ], "modmenu": [ "ru.bclib.gui.modmenu.EntryPoint::entrypointObject" ] }, - "accessWidener" : "bclib.accesswidener", - "mixins": [ + "mixins": [ "bclib.mixins.common.json", "bclib.mixins.client.json" ], "depends": { - "fabricloader": ">=0.11.6", - "fabric": ">=0.41.0", - "minecraft": ">=1.17.1" + "fabricloader": ">=0.12.6", + "fabric": ">=0.43.0", + "minecraft": ">=1.18" }, "custom":{ "modmenu":{