Merge pull request #54 from paulevsGitch/1.18

1.18
This commit is contained in:
paulevsGitch 2021-12-04 12:18:47 +03:00 committed by GitHub
commit bcee0f2239
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
113 changed files with 3624 additions and 2346 deletions

View file

@ -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

View file

@ -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 {

View file

@ -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

Binary file not shown.

View file

@ -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

269
gradlew vendored Normal file → Executable file
View file

@ -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" "$@"

22
gradlew.bat vendored
View file

@ -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

View file

@ -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();

View file

@ -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<LevelLoadBiomesCall> onLoadLevelBiomes = new ArrayList<>(2);
private final static List<LevelLoadCall> onLoadLevel = new ArrayList<>(2);
private final static List<BeforeLevelLoadCall> 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

View file

@ -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<Consumer<Boolean>> postInitFunctions = Lists.newArrayList();
private static List<Tag.Named<Block>> blockTags = Lists.newArrayList();
private static List<Tag.Named<Item>> 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();
}
}
}

View file

@ -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 <T> Tag.Named<T> makeTag(Supplier<TagCollection<T>> containerSupplier, ResourceLocation id) {
Tag<T> tag = containerSupplier.get().getTag(id);
return tag == null ? TagRegistry.create(id, containerSupplier) : (Named<T>) tag;
//return tag == null ? TagRegistry.create(id, containerSupplier) : (Named<T>) tag;
return tag == null ? new TagDelegate<>(id, containerSupplier) : (Named<T>) tag;
}
/**
@ -131,7 +134,8 @@ public class TagAPI {
public static Tag.Named<Block> getMCBlockTag(String name) {
ResourceLocation id = new ResourceLocation(name);
Tag<Block> tag = BlockTags.getAllTags().getTag(id);
return tag == null ? (Named<Block>) TagRegistry.block(id) : (Named<Block>) tag;
//return tag == null ? (Named<Block>) TagRegistry.block(id) : (Named<Block>) tag;
return tag == null ? (Named<Block>) TagFactory.BLOCK.create(id): (Named<Block>) tag;
}
/**

View file

@ -44,6 +44,7 @@ public class WorldDataAPI {
catch (IOException e) {
BCLib.LOGGER.error("World data loading failed", e);
}
TAGS.put(modID, root);
}
else {
Optional<ModContainer> optional = FabricLoader.getInstance()
@ -58,11 +59,10 @@ public class WorldDataAPI {
.getVersion()
.toString());
}
TAGS.put(modID, root);
saveFile(modID);
}
}
TAGS.put(modID, root);
});
}

View file

@ -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<ConfiguredStructureFeature> 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 <M extends Mob> BCLBiomeBuilder spawn(EntityType<M> 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<BiomeGenerationSettings.Builder> 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 extends BCLBiome> T build(BiFunction<ResourceLocation, Biome, T> 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;
}
}

View file

@ -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<String, SurfaceRuleEntry> RULES_CACHE = Maps.newHashMap();
private static final SurfaceRuleBuilder INSTANCE = new SurfaceRuleBuilder();
private List<SurfaceRuleEntry> rules = Lists.newArrayList();
private SurfaceRuleEntry entryInstance;
private ResourceKey<Biome> 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<Biome> 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<SurfaceRules.RuleSource> 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<SurfaceRuleEntry> supplier) {
SurfaceRuleEntry entry = RULES_CACHE.get(name);
if (entry == null) {
entry = supplier.get();
RULES_CACHE.put(name, entry);
}
return entry;
}
}

View file

@ -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<M extends Mob> implements Comparable<SurfaceRuleEntry> {
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);
}
}

View file

@ -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;

View file

@ -48,7 +48,7 @@ public class HelloClient extends DataHandler.FromServer {
public interface IServerModMap extends Map<String, OfferedModInfo> {}
public static class ServerModMap extends HashMap<String, OfferedModInfo> 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);

View file

@ -57,7 +57,7 @@ import java.io.File;
* </table>
*/
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";

View file

@ -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<AutoSyncID> files;

View file

@ -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<AutoFileSyncEntry> files;
private String token;

View file

@ -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++) {

View file

@ -13,8 +13,7 @@ import java.util.List;
import java.util.Map;
public abstract class Patch {
private static List<Patch> ALL = new ArrayList<>(10);
private static final List<Patch> 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<String> getWorldDataIDPaths() {
return null;
}
}

View file

@ -19,7 +19,7 @@ public class SpawnRuleEntry<M extends Mob> implements Comparable<SpawnRuleEntry>
this.rule = rule;
}
boolean canSpawn(EntityType<M> type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, Random random) {
protected boolean canSpawn(EntityType<M> type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, Random random) {
return rule.canSpawn(type, world, spawnReason, pos, random);
}

View file

@ -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() {

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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) {

View file

@ -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

View file

@ -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

View file

@ -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));

View file

@ -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

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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<FabricBlockSettings> customizeProperties) {
super(BaseBlock.acceptAndReturn(customizeProperties, makeLeaves(color)));
this.sapling = sapling;
}
public BaseLeavesBlock(Block sapling, MaterialColor color, int light, Consumer<FabricBlockSettings> 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<ItemStack> 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<Named<Block>> blockTags, List<Named<Item>> itemTags) {
blockTags.add(FabricMineableTags.SHEARS_MINEABLE);
blockTags.add(TagAPI.MINEABLE_HOE);
blockTags.add(BlockTags.LEAVES);
}
}

View file

@ -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

View file

@ -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<Item> 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<Item> 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<Item> 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<Item> drop, int minCount, int maxCount, int experience) {
this(properties, drop, minCount, maxCount, experience, 0);
}
public BaseOreBlock(Properties properties, Supplier<Item> 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<ItemStack> 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<ItemStack> getDroppedItems(ItemLike block, Item dropItem, int maxCount, int minCount, BlockState state, LootContext.Builder builder) {

View file

@ -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;
}

View file

@ -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<String> pattern = PatternsHelper.createJson(BasePatterns.BLOCK_CROSS, resourceLocation);
return ModelsHelper.fromPattern(pattern);
}
@Override
public void addTags(List<Named<Block>> blockTags, List<Named<Item>> itemTags) {
blockTags.add(FabricMineableTags.SHEARS_MINEABLE);
blockTags.add(TagAPI.MINEABLE_HOE);
}
}

View file

@ -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) {

View file

@ -27,7 +27,7 @@ public class BaseRotatedPillarBlock extends RotatedPillarBlock implements BlockM
}
public BaseRotatedPillarBlock(Block block) {
super(FabricBlockSettings.copyOf(block));
this(FabricBlockSettings.copyOf(block));
}
@Override

View file

@ -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));
}
}

View file

@ -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) {

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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

View file

@ -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) {

View file

@ -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));
}

View file

@ -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) {

View file

@ -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<Direction, VoxelShape> 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) {

View file

@ -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);
}

View file

@ -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<BlockState, Feature<?>> featureSupplier) {
super(featureSupplier);
}
public FeatureHangingSaplingBlock(int light) {
super(light);
public FeatureHangingSaplingBlock(Function<BlockState, Feature<?>> featureSupplier, int light) {
super(light, featureSupplier);
}
public FeatureHangingSaplingBlock(BlockBehaviour.Properties properties, Function<BlockState, Feature<?>> featureSupplier) {
super(properties, featureSupplier);
}
@Override

View file

@ -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<BlockState, Feature<?>> feature;
public FeatureSaplingBlock() {
super();
public FeatureSaplingBlock(Function<BlockState, Feature<?>> 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<BlockState, Feature<?>> featureSupplier) {
this(FabricBlockSettings.of(Material.PLANT)
.breakByHand(true)
.collidable(false)
.luminance(light)
.instabreak()
.sound(SoundType.GRASS)
.randomTicks(),
featureSupplier
);
}
public FeatureSaplingBlock(BlockBehaviour.Properties properties, Function<BlockState, Feature<?>> featureSupplier) {
super(null, properties);
this.feature = featureSupplier;
}
protected Feature<?> getFeature(BlockState state) {
return feature.apply(state);
}
@Override
public List<ItemStack> 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<String> pattern = PatternsHelper.createJson(BasePatterns.BLOCK_CROSS, resourceLocation);
return ModelsHelper.fromPattern(pattern);
}
@Override

View file

@ -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<ItemStack> 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<String> pattern = PatternsHelper.createJson(BasePatterns.BLOCK_CROSS, resourceLocation);
return ModelsHelper.fromPattern(pattern);
}
}

View file

@ -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<Named<Block>> blockTags, List<Named<Item>> itemTags) {
blockTags.add(FabricMineableTags.SHEARS_MINEABLE);
blockTags.add(TagAPI.MINEABLE_HOE);
blockTags.add(BlockTags.LEAVES);
}
}

View file

@ -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

View file

@ -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;
}

View file

@ -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<Named<Block>> blockTags, List<Named<Item>> itemTags) {
blockTags.add(FabricMineableTags.SHEARS_MINEABLE);
blockTags.add(TagAPI.MINEABLE_HOE);
}
}

View file

@ -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

View file

@ -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<Named<Block>> blockTags, List<Named<Item>> itemTags) {
blockTags.add(FabricMineableTags.SHEARS_MINEABLE);
blockTags.add(TagAPI.MINEABLE_HOE);
}
}

View file

@ -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

View file

@ -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<String> {
private final Set<String> 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<String> getPossibleValues() {
return Collections.unmodifiableSet(values);
}
@Override
public String getName(String comparable) {
return comparable;
}
@Override
public Optional<String> 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);
}
}

View file

@ -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;

View file

@ -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));
}
}

View file

@ -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<Item> getItemTag(String name) {
ResourceLocation id = getID(name);
Tag<Item> tag = ItemTags.getAllTags().getTag(id);
return tag == null ? (Named<Item>) TagRegistry.item(id) : (Named<Item>) tag;
//return tag == null ? (Named<Item>) TagRegistry.item(id) : (Named<Item>) tag;
return tag == null ? (Named<Item>) TagFactory.ITEM.create(id) : (Named<Item>) tag;
}
public Tag.Named<Block> getBlockTag(String name) {
ResourceLocation id = getID(name);
Tag<Block> tag = BlockTags.getAllTags().getTag(id);
return tag == null ? (Named<Block>) TagRegistry.block(id) : (Named<Block>) tag;
//return tag == null ? (Named<Block>) TagRegistry.block(id) : (Named<Block>) tag;
return tag == null ? (Named<Block>) TagFactory.BLOCK.create(id) : (Named<Block>) tag;
}
}

View file

@ -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);
}

View file

@ -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();
}

View file

@ -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<Named<Block>> blockTags, List<Tag.Named<Item>> itemTags);
}

View file

@ -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();
}
}

View file

@ -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<List<Supplier<PlacedFeature>>> bclib_getFeatures();
@Accessor("features")
@Mutable
void bclib_setFeatures(List<List<Supplier<PlacedFeature>>> value);
@Accessor("featureSet")
Set<PlacedFeature> bclib_getFeatureSet();
@Accessor("featureSet")
void bclib_setFeatureSet(Set<PlacedFeature> features);
@Accessor("carvers")
Map<Carving, List<Supplier<ConfiguredWorldCarver<?>>>> bclib_getCarvers();
@Accessor("carvers")
void bclib_setCarvers(Map<GenerationStep.Carving, List<Supplier<ConfiguredWorldCarver<?>>>> features);
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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<Biome> biomeRegistry, Registry<NoiseGeneratorSettings> chunkGeneratorSettingsRegistry, long seed, CallbackInfoReturnable<ChunkGenerator> 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<MappedRegistry<LevelStem>> info, MappedRegistry<LevelStem> mappedRegistry, Registry<DimensionType> registry, Registry<Biome> biomeRegistry, Registry<NoiseGeneratorSettings> noiseSettingsRegistry, Registry<NormalNoise.NoiseParameters> 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<Biome> biomeRegistry, Registry<NoiseGeneratorSettings> chunkGeneratorSettingsRegistry, long seed, CallbackInfoReturnable<ChunkGenerator> info) {
if (GeneratorOptions.customEndBiomeSource()) {
info.setReturnValue(new NoiseBasedChunkGenerator(
new BCLibEndBiomeSource(biomeRegistry, seed),
seed,
() -> chunkGeneratorSettingsRegistry.getOrThrow(NoiseGeneratorSettings.END)
));
}
}
}
}

View file

@ -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();
}

View file

@ -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<Biome> replaced, ResourceKey<Biome> 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<Biome> highlands, ResourceKey<Biome> 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<Biome> highlands, ResourceKey<Biome> 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, Biome.ClimateParameters spawnNoisePoint, CallbackInfo info) {
FabricBiomesData.NETHER_BIOMES.add(biome);
}
}

View file

@ -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;
}
}

View file

@ -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<String> collection, CallbackInfoReturnable<CompletableFuture<Void>> 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() {

View file

@ -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<MobCategory, WeightedRandomList<SpawnerData>> bcl_getSpawners();
@Accessor("spawners")
@Mutable
void bcl_setSpawners(Map<MobCategory, WeightedRandomList<SpawnerData>> spawners);
}

View file

@ -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> biome, Climate.ParameterPoint spawnNoisePoint, CallbackInfo info) {
FabricBiomesData.NETHER_BIOMES.add(biome);
}
}

View file

@ -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<SurfaceRules.RuleSource> info) {
if (bclib_surfaceRule != null) {
info.setReturnValue(bclib_surfaceRule);
}
}
}

View file

@ -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 = "<init>*", at = @At("TAIL"))
private void bclib_onServerWorldInit(MinecraftServer server, Executor workerExecutor, LevelStorageSource.LevelStorageAccess session, ServerLevelData properties, ResourceKey<Level> registryKey, DimensionType dimensionType, ChunkProgressListener worldGenerationProgressListener, ChunkGenerator chunkGenerator, boolean debugWorld, long l, List<CustomSpawner> list, boolean bl, CallbackInfo info) {
private void bclib_onServerWorldInit(MinecraftServer server, Executor executor, LevelStorageAccess levelStorageAccess, ServerLevelData serverLevelData, ResourceKey<Level> resourceKey, DimensionType dimensionType, ChunkProgressListener chunkProgressListener, ChunkGenerator chunkGenerator, boolean bl, long l, List<CustomSpawner> 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();
}

View file

@ -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<StructureFeature<?>, ImmutableMultimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> bcl_getStructureConfig();
@Accessor("configuredStructures")
@Mutable
void bcl_setStructureConfig(ImmutableMap<StructureFeature<?>, ImmutableMultimap<ConfiguredStructureFeature<?, ?>, ResourceKey<Biome>>> structureConfig);
}

View file

@ -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<Biome> replaced, ResourceKey<Biome> 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<Biome> highlands, ResourceKey<Biome> 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<Biome> highlands, ResourceKey<Biome> barrens, double weight, CallbackInfo info) {
FabricBiomesData.END_LAND_BIOMES.put(barrens, (float) weight);
FabricBiomesData.END_VOID_BIOMES.put(barrens, (float) weight);
}
}

View file

@ -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<Boolean> 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);
}
}

View file

@ -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<WorldGenSettings> info) {
BiomeAPI.initRegistry(registryHolder.registryOrThrow(Registry.BIOME_REGISTRY));
}
}

View file

@ -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);
}
}

View file

@ -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<Block> {
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){

View file

@ -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 <E> List<E> getMutable(List<E> 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 <E> Set<E> getMutable(Set<E> 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 <K, V> Map<K, V> getMutable(Map<K, V> map) {
if (map instanceof HashMap) {
return map;
}
return new HashMap<>(map);
}
}

View file

@ -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);

View file

@ -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<BCLBiome> subbiomes = new WeightedList<BCLBiome>();
private final List<ConfiguredStructureFeature> structures = Lists.newArrayList();
private final WeightedList<BCLBiome> subbiomes = new WeightedList<>();
private final Map<String, Object> 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<String, Object> 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<Biome> 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<StructureInfo> 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<Biome> 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> 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> 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<String, Object> 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> 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<ConfiguredStructureFeature> 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;
}
}

View file

@ -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<ConfiguredStructureFeature<?, ?>> structures = Lists.newArrayList();
private final List<FeatureInfo> features = Lists.newArrayList();
private final List<CarverInfo> carvers = Lists.newArrayList();
private final List<SpawnInfo> mobs = Lists.newArrayList();
private final List<SpawnerData> spawns = Lists.newArrayList();
private final Map<String, Object> 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 <C extends CarverConfiguration> {
Carving carverStep;
ConfiguredWorldCarver<C> carver;
}
public ResourceLocation getID() {
return id;
}
public float getFodDensity() {
return fogDensity;
}
public float getGenChance() {
return genChance;
}
public int getEdgeSize() {
return edgeSize;
}
public <C extends CarverConfiguration> BCLBiomeDef addCarver(Carving carverStep, ConfiguredWorldCarver<C> 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> T getCustomData(String name, Object defaultValue) {
return (T) customData.getOrDefault(name, defaultValue);
}
protected Map<String, Object> getCustomData() {
return customData;
}
}

View file

@ -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);
}
}*/
}

View file

@ -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<NoneFeatureConfiguration> feature, Decoration featureStep, ConfiguredFeature<?, ?> configuredFeature) {
this.featureConfigured = Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, id, configuredFeature);
public BCLFeature(ResourceLocation id, Feature<NoneFeatureConfiguration> 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<NoneFeatureConfiguration> 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<NoneFeatureConfiguration> 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<NoneFeatureConfiguration> 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<NoneFeatureConfiguration> 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<NoneFeatureConfiguration> 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<NoneFeatureConfiguration> feature, int chance) {
return makeChancedFeature(id, Decoration.RAW_GENERATION, feature, chance);
}
@Deprecated(forRemoval = true)
public static BCLFeature makeChunkFeature(ResourceLocation id, Feature<NoneFeatureConfiguration> feature) {
return makeChunkFeature(id, Decoration.LOCAL_MODIFICATIONS, feature);
}
@Deprecated(forRemoval = true)
public static BCLFeature makeChansedFeature(ResourceLocation id, Feature<NoneFeatureConfiguration> feature, int chance) {
return makeChancedFeature(id, Decoration.SURFACE_STRUCTURES, feature, chance);
}
@Deprecated(forRemoval = true)
public static BCLFeature makeCountRawFeature(ResourceLocation id, Feature<NoneFeatureConfiguration> feature, int chance) {
return makeCountFeature(id, Decoration.RAW_GENERATION, feature, chance);
}
@Deprecated(forRemoval = true)
public static BCLFeature makeFeatureConfigured(ResourceLocation id, Feature<NoneFeatureConfiguration> feature) {
return makeFeatureConfigured(id, Decoration.RAW_GENERATION, feature);
}
}

View file

@ -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);

View file

@ -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<Biome> 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<String> 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<Biome> getBiomes(Registry<Biome> biomeRegistry) {
List<String> include = Configs.BIOMES_CONFIG.getEntry("force_include", "end_biomes", StringArrayEntry.class).getValue();
List<String> includeLand = Configs.BIOMES_CONFIG.getEntry("force_include", "end_land_biomes", StringArrayEntry.class).getValue();
List<String> 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;

Some files were not shown because too many files have changed in this diff Show more