diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..8dd87bb4fb --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,39 @@ +# Automatically build the project and run any configured tests for every push +# and submitted pull request. This can help catch issues that only occur on +# certain platforms or Java versions, and provides a first line of defence +# against bad commits. + +name: build +on: [ pull_request, push ] + +jobs: + build: + strategy: + matrix: + # Use these Java versions + java: [ + 21, # Current Java LTS & minimum supported by Minecraft + ] + # and run on both Linux and Windows + os: [ ubuntu-20.04, windows-2022 ] + runs-on: ${{ matrix.os }} + steps: + - name: checkout repository + uses: actions/checkout@v2 + - name: validate gradle wrapper + uses: gradle/wrapper-validation-action@v1 + - name: setup jdk ${{ matrix.java }} + uses: actions/setup-java@v1 + with: + java-version: ${{ matrix.java }} + - name: make gradle wrapper executable + if: ${{ runner.os != 'Windows' }} + run: chmod +x ./gradlew + - name: build + run: ./gradlew build + - name: capture build artifacts + if: ${{ runner.os == 'Linux' }} + uses: actions/upload-artifact@v2 + with: + name: Artifacts + path: build/libs/ diff --git a/.gitignore b/.gitignore index 3f289dd002..7a816289c2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,6 @@ logs/ .classpath .project build.number - .idea/ -run/ \ No newline at end of file +run/ +libs/ diff --git a/build.gradle b/build.gradle index 7b629f1483..b2ae1dc8c5 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,9 @@ plugins { - id 'fabric-loom' version '1.4-SNAPSHOT' + id 'fabric-loom' version '1.6-SNAPSHOT' } -sourceCompatibility = JavaVersion.VERSION_17 -targetCompatibility = JavaVersion.VERSION_17 +sourceCompatibility = JavaVersion.VERSION_21 +targetCompatibility = JavaVersion.VERSION_21 repositories { maven { url 'https://masa.dy.fi/maven' } @@ -19,8 +19,9 @@ dependencies { modImplementation "fi.dy.masa.malilib:malilib-fabric-${project.minecraft_version_out}:${project.malilib_version}" - // Fabric API. This is technically optional, but you probably want it anyway. - //modCompile "net.fabricmc.fabric-api:fabric-api:" + project.fabric_version + //include(modApi(fabricApi.module("fabric-api-base", project.fabric_api_version))) + include(modApi(fabricApi.module("fabric-networking-api-v1", project.fabric_api_version))) + include(modApi(fabricApi.module("fabric-resource-loader-v0", project.fabric_api_version))) modCompileOnly "com.terraformersmc:modmenu:${project.mod_menu_version}" } @@ -55,8 +56,8 @@ tasks.withType(JavaCompile).configureEach { // If Javadoc is generated, this must be specified in that task too. it.options.encoding = "UTF-8" - // Minecraft 1.18 (1.18-pre2) upwards uses Java 17. - it.options.release = 17 + // Minecraft 1.20.5 (24w14a) upwards uses Java 21. + it.options.release = 21 } tasks.withType(AbstractArchiveTask).configureEach { diff --git a/gradle.properties b/gradle.properties index 02f1abb562..6205a0b13c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,15 +9,16 @@ author = masa mod_file_name = litematica-fabric # Current mod version -mod_version = 0.17.3 +mod_version = 0.18.0 # Required malilib version -malilib_version = 0.18.0 +malilib_version = 0.19.0 # Minecraft, Fabric and mappings versions -minecraft_version_out = 1.20.4 -minecraft_version = 1.20.4 -mappings_version = 1.20.4+build.1 +minecraft_version_out = 1.20.6 +minecraft_version = 1.20.6 +mappings_version = 1.20.6+build.3 -fabric_loader_version = 0.15.1 -mod_menu_version = 9.0.0-pre.1 +fabric_loader_version = 0.15.10 +mod_menu_version = 10.0.0-beta.1 +fabric_api_version = 0.97.8+1.20.5 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c023..d64cd49177 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2bbac7dd7d..48c0a02ca4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists \ No newline at end of file +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0c81..1aa94a4269 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,99 @@ # ############################################################################## -## -## 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/HEAD/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_NAME="Gradle" -APP_BASE_NAME=`basename "$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"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # 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 @@ -87,9 +119,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 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 @@ -98,88 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - 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. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "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 +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# 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 +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "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 +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 - 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\"" + 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 - i=`expr $i + 1` + # 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 - 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" ;; - 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, 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" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 107acd32c4..25da30dbde 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +41,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/jitpack.yml b/jitpack.yml new file mode 100644 index 0000000000..33e78efd3f --- /dev/null +++ b/jitpack.yml @@ -0,0 +1,3 @@ +before_install: + - sdk install java 21.0.2-tem + - sdk use java 21.0.2-tem diff --git a/src/main/java/fi/dy/masa/litematica/config/Configs.java b/src/main/java/fi/dy/masa/litematica/config/Configs.java index 9cf1b0539c..42bd1e5edb 100644 --- a/src/main/java/fi/dy/masa/litematica/config/Configs.java +++ b/src/main/java/fi/dy/masa/litematica/config/Configs.java @@ -8,23 +8,14 @@ import fi.dy.masa.malilib.config.HudAlignment; import fi.dy.masa.malilib.config.IConfigBase; import fi.dy.masa.malilib.config.IConfigHandler; -import fi.dy.masa.malilib.config.options.ConfigBoolean; -import fi.dy.masa.malilib.config.options.ConfigColor; -import fi.dy.masa.malilib.config.options.ConfigDouble; -import fi.dy.masa.malilib.config.options.ConfigInteger; -import fi.dy.masa.malilib.config.options.ConfigOptionList; -import fi.dy.masa.malilib.config.options.ConfigString; +import fi.dy.masa.malilib.config.options.*; import fi.dy.masa.malilib.util.FileUtils; import fi.dy.masa.malilib.util.JsonUtils; import fi.dy.masa.malilib.util.MessageOutputType; import fi.dy.masa.litematica.Reference; import fi.dy.masa.litematica.data.DataManager; import fi.dy.masa.litematica.selection.CornerSelectionMode; -import fi.dy.masa.litematica.util.BlockInfoAlignment; -import fi.dy.masa.litematica.util.EasyPlaceProtocol; -import fi.dy.masa.litematica.util.InventoryUtils; -import fi.dy.masa.litematica.util.PasteNbtBehavior; -import fi.dy.masa.litematica.util.ReplaceBehavior; +import fi.dy.masa.litematica.util.*; public class Configs implements IConfigHandler { @@ -35,7 +26,7 @@ public static class Generic public static final ConfigOptionList EASY_PLACE_PROTOCOL = new ConfigOptionList("easyPlaceProtocolVersion", EasyPlaceProtocol.AUTO, "The type of \"accurate placement protocol\" to use.\n- Auto: Uses v3 in single player, and by default Slabs-only in multiplayer,\n unless the server has Carpet mod that sends a 'carpet:hello'\n packet, in which case v2 is used on that server.\n- Version 3: Only supported by Litematica itself (in single player) for now.\n- Version 2: Compatible with servers with the Carpet mod\n (either QuickCarpet by skyrising and DeadlyMC,\n or CarpetExtra in addition to FabricCarpet.\n And in both cases the 'accurateBlockPlacement' Carpet rule needs\n to be enabled on the server).\n- Slabs only: Only fixes top slabs. Compatible with Paper servers.\n- None: Does not modify coordinates."); public static final ConfigOptionList PASTE_NBT_BEHAVIOR = new ConfigOptionList("pasteNbtRestoreBehavior", PasteNbtBehavior.NONE, "Whether or not the NBT data of blocks is attempted to be restored,\nand which method is used for that.\n- Place & Data Modify will try to place the \"NBT-picked\" block\n near the player, and then use the data modify\n command to transfer the NBT data to the setblock'ed block\n- Place & Clone will try to place the \"NBT-picked\" block\n near the player, and then clone it to the final location.\n- Teleport & Place will try to teleport the player nearby and then\n directly place the NBT-picked item in the correct position.\nNote that the teleport & place method doesn't currently work correctly/at all.\nThe recommended method is §ePlace & Data Modify§r, however for that to work\nyou will probably need to lower the pasteCommandLimit to 1 per tick and increase\nthe pasteCommandInterval to 1-4 ticks or something.\nThus you should only use this for pasting important blocks that need the data,\nfor example by making a schematic of just the inventories,\nand then paste that with replace behavior set to None."); public static final ConfigOptionList PASTE_REPLACE_BEHAVIOR = new ConfigOptionList("pasteReplaceBehavior", ReplaceBehavior.NONE, "The behavior of replacing existing blocks\nin the Paste schematic tool mode"); - public static final ConfigOptionList PLACEMENT_REPLACE_BEHAVIOR = new ConfigOptionList("placementReplaceBehavior", ReplaceBehavior.ALL, "The block replace behavior when adding blocks\nto the schematic world.\n\nThis allows using overlapped placements without the\nlater handled placement always ovewriting earlier ones with air.\nOn the other hand some blocks like light blocks are considered\nto be air, so they would need the \"All\" replace behavior\nto get placed at all."); + public static final ConfigOptionList PLACEMENT_REPLACE_BEHAVIOR = new ConfigOptionList("placementReplaceBehavior", ReplaceBehavior.ALL, "The block replace behavior when adding blocks\nto the schematic world.\n\nThis allows using overlapped placements without the\nlater handled placement always overwriting earlier ones with air.\nOn the other hand some blocks like light blocks are considered\nto be air, so they would need the \"All\" replace behavior\nto get placed at all."); public static final ConfigOptionList PLACEMENT_RESTRICTION_WARN = new ConfigOptionList("placementRestrictionWarn", MessageOutputType.ACTIONBAR, "Selects which type of warning message to show (if any)\nwhen either the Easy Place mode or Placement Restriction prevent placing a block"); public static final ConfigOptionList SELECTION_CORNERS_MODE = new ConfigOptionList("selectionCornersMode", CornerSelectionMode.CORNERS, "The Area Selection corners mode to use (Corners, or Expand)"); @@ -57,6 +48,7 @@ public static class Generic public static final ConfigInteger COMMAND_TASK_INTERVAL = new ConfigInteger("commandTaskInterval", 1, 1, 1000, "The interval in game ticks the Paste, Fill and Delete tasks\nare executed at. The commandLimitPerTick config sets the maximum\nnumber of commands to send per execution, and this config\nsets the interval in game ticks before the next execution."); public static final ConfigBoolean COMMAND_USE_WORLDEDIT = new ConfigBoolean("commandUseWorldEdit", false, "If enabled, instead of using the configured setblock and fill commands,\nthe World Edit //pos1, //pos2 and //set commands are used.\nNote that using World Edit commands is around 3x slower\nthan using vanilla commands due to the command limit per tick,\nand WE requiring multiple commands per block or area (//pos1 //pos2 //set).\n§6WARNING: The paste replace behavior option WILL NOT WORK if using\n§6the World Edit commands and fill volumes instead of individual setblock commands!\nThus it's recommended to use the vanilla commands, if you have the permission to run them.\nOne other thing that might make you prefer WE commands in some cases\nis that they can prevent block updates, if the server doesn't have\nthe Carpet mod and thus the '/carpet fillUpdates false' rule available."); public static final ConfigBoolean DEBUG_LOGGING = new ConfigBoolean("debugLogging", false, "Enables some debug log messages in the game console,\nfor debugging certain issues or crashes."); + public static final ConfigInteger DATAFIXER_DEFAULT_SCHEMA = new ConfigInteger("datafixerDefaultSchema", 1139, 99, 2724, true, "Default Schema Value for the Vanilla Data Fixer\n\nUsed to adjust the lowest possible value, and the value used\nwhen the loaded schematic does not contain this information.\n\n§6WARNING: This setting is meant to be used at the direction\n§6from a Litematica developer such as masa themselves.\n§6When in doubt, keep the default for Minecraft 1.12."); public static final ConfigBoolean EASY_PLACE_FIRST = new ConfigBoolean("easyPlaceFirst", true, "This causes the Easy Place mode to place the first/closest block\nyou are looking at first, instead of the furthest/bottom-most block.\nSetting this to false allows you to place multiple layers \"at once\",\nsince the furthest blocks would be placed before the closer ones block the line of sight."); public static final ConfigBoolean EASY_PLACE_HOLD_ENABLED = new ConfigBoolean("easyPlaceHoldEnabled", true, "When enabled, then you can hold down the use key\nand look at different schematic blocks to place them,\nwithout having to click on every block individually."); public static final ConfigBoolean EASY_PLACE_MODE = new ConfigBoolean("easyPlaceMode", false, "When enabled, then simply trying to use an item/place a block\non schematic blocks will place that block in that position"); @@ -104,6 +96,7 @@ public static class Generic COMMAND_USE_WORLDEDIT, CUSTOM_SCHEMATIC_BASE_DIRECTORY_ENABLED, DEBUG_LOGGING, + DATAFIXER_DEFAULT_SCHEMA, EASY_PLACE_FIRST, EASY_PLACE_HOLD_ENABLED, EASY_PLACE_MODE, diff --git a/src/main/java/fi/dy/masa/litematica/data/DataManager.java b/src/main/java/fi/dy/masa/litematica/data/DataManager.java index 5538801667..d52574e686 100644 --- a/src/main/java/fi/dy/masa/litematica/data/DataManager.java +++ b/src/main/java/fi/dy/masa/litematica/data/DataManager.java @@ -1,29 +1,20 @@ package fi.dy.masa.litematica.data; +import javax.annotation.Nullable; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.annotation.Nullable; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; -import com.mojang.brigadier.StringReader; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.StringNbtReader; import net.minecraft.registry.Registries; import net.minecraft.text.Text; import net.minecraft.util.Identifier; import fi.dy.masa.malilib.gui.interfaces.IDirectoryCache; -import fi.dy.masa.malilib.util.FileUtils; -import fi.dy.masa.malilib.util.JsonUtils; -import fi.dy.masa.malilib.util.LayerRange; -import fi.dy.masa.malilib.util.StringUtils; +import fi.dy.masa.malilib.util.*; import fi.dy.masa.litematica.Litematica; import fi.dy.masa.litematica.Reference; import fi.dy.masa.litematica.config.Configs; @@ -46,8 +37,6 @@ public class DataManager implements IDirectoryCache { private static final DataManager INSTANCE = new DataManager(); - private static final Pattern PATTERN_ITEM_NBT = Pattern.compile("^(?[a-z0-9\\._-]+:[a-z0-9\\._-]+)(?\\{.*\\})$"); - private static final Pattern PATTERN_ITEM_BASE = Pattern.compile("^(?(?:[a-z0-9\\._-]+:)[a-z0-9\\._-]+)$"); private static final Map LAST_DIRECTORIES = new HashMap<>(); private static final ArrayList> CHAT_LISTENERS = new ArrayList<>(); @@ -58,6 +47,7 @@ public class DataManager implements IDirectoryCache private static boolean isCarpetServer; private static long clientTickStart; + public static Identifier CARPET_HELLO = Identifier.of("carpet", "hello"); private final SelectionManager selectionManager = new SelectionManager(); private final SchematicPlacementManager schematicPlacementManager = new SchematicPlacementManager(); private final SchematicProjectsManager schematicProjectsManager = new SchematicProjectsManager(); @@ -71,7 +61,7 @@ private DataManager() { } - private static DataManager getInstance() + public static DataManager getInstance() { return INSTANCE; } @@ -509,50 +499,19 @@ private static File getCurrentStorageFile(boolean globalData) return new File(dir, StringUtils.getStorageFileName(globalData, Reference.MOD_ID + "_", ".json", "default")); } + /** + * Sets the current toolItem, if itemNameIn is invalid, sets toolItem to the default minecraft:stick + * @param itemNameIn (String representation of the item Identifier) + */ public static void setToolItem(String itemNameIn) { - if (itemNameIn.isEmpty() || itemNameIn.equals("empty")) - { - toolItem = ItemStack.EMPTY; - return; - } - - try - { - Matcher matcherNbt = PATTERN_ITEM_NBT.matcher(itemNameIn); - Matcher matcherBase = PATTERN_ITEM_BASE.matcher(itemNameIn); - - String itemName = null; - NbtCompound nbt = null; - - if (matcherNbt.matches()) - { - itemName = matcherNbt.group("name"); - nbt = (new StringNbtReader(new StringReader(matcherNbt.group("nbt")))).parseCompound(); - } - else if (matcherBase.matches()) - { - itemName = matcherBase.group("name"); - } - - if (itemName != null) - { - Item item = Registries.ITEM.get(new Identifier(itemName)); + toolItem = InventoryUtils.getItemStackFromString(itemNameIn); - if (item != null && item != Items.AIR) - { - toolItem = new ItemStack(item); - toolItem.setNbt(nbt); - return; - } - } - } - catch (Exception ignore) + if (toolItem == null) { + // Fall back to a stick + toolItem = new ItemStack(Items.STICK); + Configs.Generic.TOOL_ITEM.setValueFromString(Registries.ITEM.getId(Items.STICK).toString()); } - - // Fall back to a stick - toolItem = new ItemStack(Items.STICK); - Configs.Generic.TOOL_ITEM.setValueFromString(Registries.ITEM.getId(Items.STICK).toString()); } } diff --git a/src/main/java/fi/dy/masa/litematica/event/InputHandler.java b/src/main/java/fi/dy/masa/litematica/event/InputHandler.java index e061119b62..f3390315f0 100644 --- a/src/main/java/fi/dy/masa/litematica/event/InputHandler.java +++ b/src/main/java/fi/dy/masa/litematica/event/InputHandler.java @@ -5,12 +5,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import fi.dy.masa.malilib.gui.Message.MessageType; -import fi.dy.masa.malilib.hotkeys.IHotkey; -import fi.dy.masa.malilib.hotkeys.IKeybindManager; -import fi.dy.masa.malilib.hotkeys.IKeybindProvider; -import fi.dy.masa.malilib.hotkeys.IKeyboardInputHandler; -import fi.dy.masa.malilib.hotkeys.IMouseInputHandler; -import fi.dy.masa.malilib.hotkeys.KeybindMulti; +import fi.dy.masa.malilib.hotkeys.*; import fi.dy.masa.malilib.util.GuiUtils; import fi.dy.masa.malilib.util.InfoUtils; import fi.dy.masa.litematica.Litematica; diff --git a/src/main/java/fi/dy/masa/litematica/event/RenderHandler.java b/src/main/java/fi/dy/masa/litematica/event/RenderHandler.java index 97e1a165c2..2adfea797d 100644 --- a/src/main/java/fi/dy/masa/litematica/event/RenderHandler.java +++ b/src/main/java/fi/dy/masa/litematica/event/RenderHandler.java @@ -4,7 +4,6 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.util.math.MatrixStack; import fi.dy.masa.litematica.config.Configs; import fi.dy.masa.litematica.data.DataManager; @@ -19,22 +18,22 @@ public class RenderHandler implements IRenderer { @Override - public void onRenderWorldLast(MatrixStack matrices, Matrix4f projMatrix) + public void onRenderWorldLast(Matrix4f matrix4f, Matrix4f projMatrix) { MinecraftClient mc = MinecraftClient.getInstance(); if (Configs.Visuals.ENABLE_RENDERING.getBooleanValue() && mc.player != null) { - OverlayRenderer.getInstance().renderBoxes(matrices); + OverlayRenderer.getInstance().renderBoxes(matrix4f); if (Configs.InfoOverlays.VERIFIER_OVERLAY_ENABLED.getBooleanValue()) { - OverlayRenderer.getInstance().renderSchematicVerifierMismatches(matrices); + OverlayRenderer.getInstance().renderSchematicVerifierMismatches(matrix4f); } if (DataManager.getToolMode() == ToolMode.REBUILD) { - OverlayRenderer.getInstance().renderSchematicRebuildTargetingOverlay(matrices); + OverlayRenderer.getInstance().renderSchematicRebuildTargetingOverlay(matrix4f); } } } diff --git a/src/main/java/fi/dy/masa/litematica/gui/GuiConfigs.java b/src/main/java/fi/dy/masa/litematica/gui/GuiConfigs.java index 065c295be7..c6588114a6 100644 --- a/src/main/java/fi/dy/masa/litematica/gui/GuiConfigs.java +++ b/src/main/java/fi/dy/masa/litematica/gui/GuiConfigs.java @@ -19,7 +19,7 @@ public class GuiConfigs extends GuiConfigsBase { public GuiConfigs() { - super(10, 50, Reference.MOD_ID, null, "litematica.gui.title.configs"); + super(10, 50, Reference.MOD_ID, null, "litematica.gui.title.configs", String.format("%s", Reference.MOD_VERSION)); } @Override diff --git a/src/main/java/fi/dy/masa/litematica/gui/GuiSchematicSaveBase.java b/src/main/java/fi/dy/masa/litematica/gui/GuiSchematicSaveBase.java index b67b9b1912..c88c65a29f 100644 --- a/src/main/java/fi/dy/masa/litematica/gui/GuiSchematicSaveBase.java +++ b/src/main/java/fi/dy/masa/litematica/gui/GuiSchematicSaveBase.java @@ -52,10 +52,8 @@ public void initGui() boolean focused = this.textField.isFocused(); String text = this.textField.getText(); - int pos = this.textField.getCursor(); this.textField = new GuiTextFieldGeneric(10, 32, this.width - 260, 18, this.textRenderer); this.textField.setText(text); - this.textField.setCursor(pos, false); this.textField.setFocused(focused); DirectoryEntry entry = this.getListWidget().getLastSelectedEntry(); @@ -101,7 +99,6 @@ protected void setTextFieldText(String text) { this.lastText = text; this.textField.setText(text); - this.textField.setCursorToEnd(false); } protected String getTextFieldText() diff --git a/src/main/java/fi/dy/masa/litematica/gui/widgets/WidgetSchematicVerificationResult.java b/src/main/java/fi/dy/masa/litematica/gui/widgets/WidgetSchematicVerificationResult.java index cb616a4947..17e0b56005 100644 --- a/src/main/java/fi/dy/masa/litematica/gui/widgets/WidgetSchematicVerificationResult.java +++ b/src/main/java/fi/dy/masa/litematica/gui/widgets/WidgetSchematicVerificationResult.java @@ -611,7 +611,7 @@ private static void renderQuads(List quads, float[] brightness, int[] private static void renderQuad(BakedQuad quad, float[] brightness, int[] light, MatrixStack.Entry matrixEntry, VertexConsumer vertexConsumer) { - vertexConsumer.quad(matrixEntry, quad, brightness, 1.0f, 1.0f, 1.0f, light, OverlayTexture.DEFAULT_UV, true); + vertexConsumer.quad(matrixEntry, quad, brightness, 1.0f, 1.0f, 1.0f, 1.0f, light, OverlayTexture.DEFAULT_UV, true); } private static class ButtonListener implements IButtonActionListener diff --git a/src/main/java/fi/dy/masa/litematica/materials/MaterialListHudRenderer.java b/src/main/java/fi/dy/masa/litematica/materials/MaterialListHudRenderer.java index 2919dde5db..9bf199638e 100644 --- a/src/main/java/fi/dy/masa/litematica/materials/MaterialListHudRenderer.java +++ b/src/main/java/fi/dy/masa/litematica/materials/MaterialListHudRenderer.java @@ -277,8 +277,9 @@ public static void highlightSlotsWithItem(ItemStack referenceItem, HandledScreen for (Slot slot : slots) { if (slot.hasStack() && - (fi.dy.masa.malilib.util.InventoryUtils.areStacksEqual(slot.getStack(), referenceItem) || - InventoryUtils.doesShulkerBoxContainItem(slot.getStack(), referenceItem))) + (fi.dy.masa.malilib.util.InventoryUtils.areStacksEqualIgnoreNbt(slot.getStack(), referenceItem) || + InventoryUtils.doesShulkerBoxContainItem(slot.getStack(), referenceItem) || + InventoryUtils.doesBundleContainItem(slot.getStack(), referenceItem))) { renderOutlinedBox(guiX + slot.x, guiY + slot.y, 16, 16, color.intValue, color.intValue | 0xFF000000, 1f); } diff --git a/src/main/java/fi/dy/masa/litematica/materials/MaterialListUtils.java b/src/main/java/fi/dy/masa/litematica/materials/MaterialListUtils.java index a5bdbe4af8..80168cf9f8 100644 --- a/src/main/java/fi/dy/masa/litematica/materials/MaterialListUtils.java +++ b/src/main/java/fi/dy/masa/litematica/materials/MaterialListUtils.java @@ -11,6 +11,8 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.Inventory; import net.minecraft.item.BlockItem; +import net.minecraft.item.BundleItem; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.collection.DefaultedList; import net.minecraft.util.math.Vec3i; @@ -147,18 +149,35 @@ public static Object2IntOpenHashMap getInventoryItemCounts(Inventory i if (stack.isEmpty() == false) { - map.addTo(new ItemType(stack, true, false), stack.getCount()); + Item item = stack.getItem(); - if (stack.getItem() instanceof BlockItem && + if (item instanceof BlockItem && ((BlockItem) stack.getItem()).getBlock() instanceof ShulkerBoxBlock && InventoryUtils.shulkerBoxHasItems(stack)) { Object2IntOpenHashMap boxCounts = getStoredItemCounts(stack); - for (ItemType type : boxCounts.keySet()) + for (ItemType boxType : boxCounts.keySet()) { - map.addTo(type, boxCounts.getInt(type)); + map.addTo(boxType, boxCounts.getInt(boxType)); } + + boxCounts.clear(); + } + else if (item instanceof BundleItem && InventoryUtils.bundleHasItems(stack)) + { + Object2IntOpenHashMap bundleCounts = getBundleItemCounts(stack); + + for (ItemType bundleType : bundleCounts.keySet()) + { + map.addTo(bundleType, bundleCounts.getInt(bundleType)); + } + + bundleCounts.clear(); + } + else + { + map.addTo(new ItemType(stack, true, false), stack.getCount()); } } } @@ -171,11 +190,27 @@ public static Object2IntOpenHashMap getStoredItemCounts(ItemStack stac Object2IntOpenHashMap map = new Object2IntOpenHashMap<>(); DefaultedList items = InventoryUtils.getStoredItems(stackShulkerBox); - for (ItemStack stack : items) + for (ItemStack boxStack : items) { - if (stack.isEmpty() == false) + if (boxStack.isEmpty() == false) + { + map.addTo(new ItemType(boxStack, false, false), boxStack.getCount()); + } + } + + return map; + } + + public static Object2IntOpenHashMap getBundleItemCounts(ItemStack stackBundle) + { + Object2IntOpenHashMap map = new Object2IntOpenHashMap<>(); + DefaultedList items = InventoryUtils.getBundleItems(stackBundle); + + for (ItemStack bundleStack : items) + { + if (bundleStack.isEmpty() == false) { - map.addTo(new ItemType(stack, true, false), stack.getCount()); + map.addTo(new ItemType(bundleStack, false, false), bundleStack.getCount()); } } diff --git a/src/main/java/fi/dy/masa/litematica/mixin/MixinAbstractSignEditScreen.java b/src/main/java/fi/dy/masa/litematica/mixin/MixinAbstractSignEditScreen.java index 03f885141c..434ed7b548 100644 --- a/src/main/java/fi/dy/masa/litematica/mixin/MixinAbstractSignEditScreen.java +++ b/src/main/java/fi/dy/masa/litematica/mixin/MixinAbstractSignEditScreen.java @@ -8,7 +8,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import net.minecraft.block.entity.SignBlockEntity; -import net.minecraft.block.entity.SignText; import net.minecraft.client.gui.screen.ingame.AbstractSignEditScreen; import fi.dy.masa.litematica.config.Configs; diff --git a/src/main/java/fi/dy/masa/litematica/mixin/MixinClientPlayNetworkHandler.java b/src/main/java/fi/dy/masa/litematica/mixin/MixinClientPlayNetworkHandler.java index 8df691190c..c9116aec31 100644 --- a/src/main/java/fi/dy/masa/litematica/mixin/MixinClientPlayNetworkHandler.java +++ b/src/main/java/fi/dy/masa/litematica/mixin/MixinClientPlayNetworkHandler.java @@ -12,7 +12,6 @@ import fi.dy.masa.litematica.Litematica; import fi.dy.masa.litematica.config.Configs; import fi.dy.masa.litematica.data.DataManager; -import fi.dy.masa.litematica.network.CarpetHelloPacketHandler; import fi.dy.masa.litematica.util.SchematicWorldRefresher; @Mixin(ClientPlayNetworkHandler.class) @@ -58,7 +57,7 @@ private void litematica_onGameMessage(GameMessageS2CPacket packet, CallbackInfo @Inject(method = "onCustomPayload", at = @At("HEAD")) private void litematica_onCustomPayload(CustomPayload payload, CallbackInfo ci) { - if (CarpetHelloPacketHandler.HELLO_CHANNEL.equals(payload.id())) + if (payload.getId().id().equals(DataManager.CARPET_HELLO)) { DataManager.setIsCarpetServer(true); } diff --git a/src/main/java/fi/dy/masa/litematica/mixin/MixinWorldRenderer.java b/src/main/java/fi/dy/masa/litematica/mixin/MixinWorldRenderer.java index f789e74aab..e662ec8334 100644 --- a/src/main/java/fi/dy/masa/litematica/mixin/MixinWorldRenderer.java +++ b/src/main/java/fi/dy/masa/litematica/mixin/MixinWorldRenderer.java @@ -1,15 +1,12 @@ package fi.dy.masa.litematica.mixin; +import net.minecraft.client.render.*; import org.joml.Matrix4f; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.Frustum; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.util.math.MatrixStack; import fi.dy.masa.litematica.render.LitematicaRenderer; @Mixin(net.minecraft.client.render.WorldRenderer.class) @@ -36,24 +33,24 @@ private void onPostSetupTerrain( } @Inject(method = "renderLayer", at = @At("TAIL")) - private void onRenderLayer(RenderLayer renderLayer, MatrixStack matrixStack, double x, double y, double z, Matrix4f matrix4f, CallbackInfo ci) + private void onRenderLayer(RenderLayer renderLayer, double x, double y, double z, Matrix4f matrix4f, Matrix4f positionMatrix, CallbackInfo ci) { if (renderLayer == RenderLayer.getSolid()) { - LitematicaRenderer.getInstance().piecewiseRenderSolid(matrixStack, matrix4f); + LitematicaRenderer.getInstance().piecewiseRenderSolid(matrix4f, positionMatrix); } else if (renderLayer == RenderLayer.getCutoutMipped()) { - LitematicaRenderer.getInstance().piecewiseRenderCutoutMipped(matrixStack, matrix4f); + LitematicaRenderer.getInstance().piecewiseRenderCutoutMipped(matrix4f, positionMatrix); } else if (renderLayer == RenderLayer.getCutout()) { - LitematicaRenderer.getInstance().piecewiseRenderCutout(matrixStack, matrix4f); + LitematicaRenderer.getInstance().piecewiseRenderCutout(matrix4f, positionMatrix); } else if (renderLayer == RenderLayer.getTranslucent()) { - LitematicaRenderer.getInstance().piecewiseRenderTranslucent(matrixStack, matrix4f); - LitematicaRenderer.getInstance().piecewiseRenderOverlay(matrixStack, matrix4f); + LitematicaRenderer.getInstance().piecewiseRenderTranslucent(matrix4f, positionMatrix); + LitematicaRenderer.getInstance().piecewiseRenderOverlay(matrix4f, positionMatrix); } } @@ -61,15 +58,11 @@ else if (renderLayer == RenderLayer.getTranslucent()) at = @At(value = "INVOKE_STRING", args = "ldc=blockentities", target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V")) private void onPostRenderEntities( - net.minecraft.client.util.math.MatrixStack matrices, - float tickDelta, long limitTime, boolean renderBlockOutline, - net.minecraft.client.render.Camera camera, - net.minecraft.client.render.GameRenderer gameRenderer, - net.minecraft.client.render.LightmapTextureManager lightmapTextureManager, - Matrix4f matrix4f, - CallbackInfo ci) + float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, + GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, + Matrix4f matrix4f, Matrix4f matrix4f2, CallbackInfo ci) { - LitematicaRenderer.getInstance().piecewiseRenderEntities(matrices, tickDelta); + LitematicaRenderer.getInstance().piecewiseRenderEntities(matrix4f, tickDelta); } /* diff --git a/src/main/java/fi/dy/masa/litematica/network/CarpetHelloPacketHandler.java b/src/main/java/fi/dy/masa/litematica/network/CarpetHelloPacketHandler.java deleted file mode 100644 index 2557a3a64e..0000000000 --- a/src/main/java/fi/dy/masa/litematica/network/CarpetHelloPacketHandler.java +++ /dev/null @@ -1,8 +0,0 @@ -package fi.dy.masa.litematica.network; - -import net.minecraft.util.Identifier; - -public class CarpetHelloPacketHandler -{ - public static final Identifier HELLO_CHANNEL = new Identifier("carpet:hello"); -} diff --git a/src/main/java/fi/dy/masa/litematica/render/LitematicaRenderer.java b/src/main/java/fi/dy/masa/litematica/render/LitematicaRenderer.java index 2f2b77929f..a342e10010 100644 --- a/src/main/java/fi/dy/masa/litematica/render/LitematicaRenderer.java +++ b/src/main/java/fi/dy/masa/litematica/render/LitematicaRenderer.java @@ -8,7 +8,6 @@ import net.minecraft.client.render.Camera; import net.minecraft.client.render.Frustum; import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.util.math.MatrixStack; import fi.dy.masa.litematica.config.Configs; import fi.dy.masa.litematica.config.Hotkeys; import fi.dy.masa.litematica.render.schematic.WorldRendererSchematic; @@ -208,7 +207,7 @@ private void renderWorld(MatrixStack matrices, Matrix4f matrix, float partialTic } */ - public void renderSchematicOverlay(MatrixStack matrices, Matrix4f projMatrix) + public void renderSchematicOverlay(Matrix4f matrix4f, Matrix4f projMatrix) { boolean invert = Hotkeys.INVERT_OVERLAY_RENDER_STATE.getKeybind().isKeybindHeld(); @@ -226,7 +225,7 @@ public void renderSchematicOverlay(MatrixStack matrices, Matrix4f projMatrix) fi.dy.masa.malilib.render.RenderUtils.color(1f, 1f, 1f, 1f); //TODO: RenderSystem.glMultiTexCoord2f(GL13.GL_TEXTURE1, 240.0F, 240.0F); - this.getWorldRenderer().renderBlockOverlays(matrices, this.getCamera(), projMatrix); + this.getWorldRenderer().renderBlockOverlays(matrix4f, this.getCamera(), projMatrix); RenderSystem.enableDepthTest(); RenderSystem.polygonOffset(0f, 0f); @@ -270,7 +269,7 @@ public void piecewisePrepareAndUpdate(Frustum frustum) } } - public void piecewiseRenderSolid(MatrixStack matrices, Matrix4f projMatrix) + public void piecewiseRenderSolid(Matrix4f matrix4f, Matrix4f projMatrix) { if (this.renderPiecewiseBlocks) { @@ -282,7 +281,7 @@ public void piecewiseRenderSolid(MatrixStack matrices, Matrix4f projMatrix) RenderSystem.polygonOffset(-0.3f, -0.6f); } - this.getWorldRenderer().renderBlockLayer(RenderLayer.getSolid(), matrices, this.getCamera(), projMatrix); + this.getWorldRenderer().renderBlockLayer(RenderLayer.getSolid(), matrix4f, this.getCamera(), projMatrix); if (this.renderCollidingSchematicBlocks) { @@ -294,7 +293,7 @@ public void piecewiseRenderSolid(MatrixStack matrices, Matrix4f projMatrix) } } - public void piecewiseRenderCutoutMipped(MatrixStack matrices, Matrix4f projMatrix) + public void piecewiseRenderCutoutMipped(Matrix4f matrix4f, Matrix4f projMatrix) { if (this.renderPiecewiseBlocks) { @@ -306,7 +305,7 @@ public void piecewiseRenderCutoutMipped(MatrixStack matrices, Matrix4f projMatri RenderSystem.polygonOffset(-0.3f, -0.6f); } - this.getWorldRenderer().renderBlockLayer(RenderLayer.getCutoutMipped(), matrices, this.getCamera(), projMatrix); + this.getWorldRenderer().renderBlockLayer(RenderLayer.getCutoutMipped(), matrix4f, this.getCamera(), projMatrix); if (this.renderCollidingSchematicBlocks) { @@ -318,7 +317,7 @@ public void piecewiseRenderCutoutMipped(MatrixStack matrices, Matrix4f projMatri } } - public void piecewiseRenderCutout(MatrixStack matrices, Matrix4f projMatrix) + public void piecewiseRenderCutout(Matrix4f matrix4f, Matrix4f projMatrix) { if (this.renderPiecewiseBlocks) { @@ -330,7 +329,7 @@ public void piecewiseRenderCutout(MatrixStack matrices, Matrix4f projMatrix) RenderSystem.polygonOffset(-0.3f, -0.6f); } - this.getWorldRenderer().renderBlockLayer(RenderLayer.getCutout(), matrices, this.getCamera(), projMatrix); + this.getWorldRenderer().renderBlockLayer(RenderLayer.getCutout(), matrix4f, this.getCamera(), projMatrix); if (this.renderCollidingSchematicBlocks) { @@ -342,7 +341,7 @@ public void piecewiseRenderCutout(MatrixStack matrices, Matrix4f projMatrix) } } - public void piecewiseRenderTranslucent(MatrixStack matrices, Matrix4f projMatrix) + public void piecewiseRenderTranslucent(Matrix4f matrix4f, Matrix4f projMatrix) { if (this.renderPiecewiseBlocks) { @@ -354,7 +353,7 @@ public void piecewiseRenderTranslucent(MatrixStack matrices, Matrix4f projMatrix RenderSystem.polygonOffset(-0.3f, -0.6f); } - this.getWorldRenderer().renderBlockLayer(RenderLayer.getTranslucent(), matrices, this.getCamera(), projMatrix); + this.getWorldRenderer().renderBlockLayer(RenderLayer.getTranslucent(), matrix4f, this.getCamera(), projMatrix); if (this.renderCollidingSchematicBlocks) { @@ -366,7 +365,7 @@ public void piecewiseRenderTranslucent(MatrixStack matrices, Matrix4f projMatrix } } - public void piecewiseRenderOverlay(MatrixStack matrices, Matrix4f matrix4f) + public void piecewiseRenderOverlay(Matrix4f matrix4f, Matrix4f projMatrix) { if (this.renderPiecewiseSchematic) { @@ -379,7 +378,7 @@ public void piecewiseRenderOverlay(MatrixStack matrices, Matrix4f matrix4f) fb.beginWrite(false); } - this.renderSchematicOverlay(matrices, matrix4f); + this.renderSchematicOverlay(matrix4f, projMatrix); if (fb != null) { @@ -392,13 +391,13 @@ public void piecewiseRenderOverlay(MatrixStack matrices, Matrix4f matrix4f) this.cleanup(); } - public void piecewiseRenderEntities(MatrixStack matrices, float partialTicks) + public void piecewiseRenderEntities(Matrix4f matrix4f, float partialTicks) { if (this.renderPiecewiseBlocks) { this.mc.getProfiler().push("litematica_entities"); - this.getWorldRenderer().renderEntities(this.getCamera(), this.frustum, matrices, partialTicks); + this.getWorldRenderer().renderEntities(this.getCamera(), this.frustum, matrix4f, partialTicks); this.mc.getProfiler().pop(); } diff --git a/src/main/java/fi/dy/masa/litematica/render/OverlayRenderer.java b/src/main/java/fi/dy/masa/litematica/render/OverlayRenderer.java index 7af8128c33..271e666381 100644 --- a/src/main/java/fi/dy/masa/litematica/render/OverlayRenderer.java +++ b/src/main/java/fi/dy/masa/litematica/render/OverlayRenderer.java @@ -1,11 +1,12 @@ package fi.dy.masa.litematica.render; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.annotation.Nullable; import com.google.common.collect.ImmutableMap; +import org.joml.Matrix4f; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.block.BlockState; @@ -16,7 +17,6 @@ import net.minecraft.client.render.Tessellator; import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormats; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; import net.minecraft.registry.Registries; import net.minecraft.util.hit.BlockHitResult; @@ -47,11 +47,7 @@ import fi.dy.masa.malilib.config.HudAlignment; import fi.dy.masa.malilib.gui.GuiBase; import fi.dy.masa.malilib.gui.LeftRight; -import fi.dy.masa.malilib.util.BlockUtils; -import fi.dy.masa.malilib.util.Color4f; -import fi.dy.masa.malilib.util.GuiUtils; -import fi.dy.masa.malilib.util.InventoryUtils; -import fi.dy.masa.malilib.util.WorldUtils; +import fi.dy.masa.malilib.util.*; public class OverlayRenderer { @@ -124,7 +120,7 @@ public void updatePlacementCache() } } - public void renderBoxes(MatrixStack matrices) + public void renderBoxes(Matrix4f matrix4f) { SelectionManager sm = DataManager.getSelectionManager(); AreaSelection currentSelection = sm.getCurrentSelection(); @@ -152,7 +148,7 @@ public void renderBoxes(MatrixStack matrices) for (Box box : currentSelection.getAllSubRegionBoxes()) { BoxType type = box == currentBox ? BoxType.AREA_SELECTED : BoxType.AREA_UNSELECTED; - this.renderSelectionBox(box, type, expand, lineWidthBlockBox, lineWidthArea, null, matrices); + this.renderSelectionBox(box, type, expand, lineWidthBlockBox, lineWidthArea, null, matrix4f); } BlockPos origin = currentSelection.getExplicitOrigin(); @@ -162,7 +158,7 @@ public void renderBoxes(MatrixStack matrices) if (currentSelection.isOriginSelected()) { Color4f colorTmp = Color4f.fromColor(this.colorAreaOrigin, 0.4f); - RenderUtils.renderAreaSides(origin, origin, colorTmp, matrices, this.mc); + RenderUtils.renderAreaSides(origin, origin, colorTmp, matrix4f, this.mc); } Color4f color = currentSelection.isOriginSelected() ? this.colorSelectedCorner : this.colorAreaOrigin; @@ -189,7 +185,7 @@ public void renderBoxes(MatrixStack matrices) String boxName = entryBox.getKey(); boolean boxSelected = schematicPlacement == currentPlacement && (origin || boxName.equals(schematicPlacement.getSelectedSubRegionName())); BoxType type = boxSelected ? BoxType.PLACEMENT_SELECTED : BoxType.PLACEMENT_UNSELECTED; - this.renderSelectionBox(entryBox.getValue(), type, expand, 1f, 1f, schematicPlacement, matrices); + this.renderSelectionBox(entryBox.getValue(), type, expand, 1f, 1f, schematicPlacement, matrix4f); } Color4f color = schematicPlacement == currentPlacement && origin ? this.colorSelectedCorner : schematicPlacement.getBoxesBBColor(); @@ -207,7 +203,7 @@ public void renderBoxes(MatrixStack matrices) { float alpha = (float) Configs.Visuals.PLACEMENT_BOX_SIDE_ALPHA.getDoubleValue(); color = new Color4f(color.r, color.g, color.b, alpha); - RenderUtils.renderAreaSides(box.getPos1(), box.getPos2(), color, matrices, this.mc); + RenderUtils.renderAreaSides(box.getPos1(), box.getPos2(), color, matrix4f, this.mc); } } } @@ -229,7 +225,7 @@ public void renderBoxes(MatrixStack matrices) } public void renderSelectionBox(Box box, BoxType boxType, float expand, - float lineWidthBlockBox, float lineWidthArea, @Nullable SchematicPlacement placement, MatrixStack matrices) + float lineWidthBlockBox, float lineWidthArea, @Nullable SchematicPlacement placement, Matrix4f matrix4f) { BlockPos pos1 = box.getPos1(); BlockPos pos2 = box.getPos2(); @@ -307,18 +303,18 @@ else if (boxType == BoxType.PLACEMENT_UNSELECTED) ((boxType == BoxType.PLACEMENT_SELECTED || boxType == BoxType.PLACEMENT_UNSELECTED) && Configs.Visuals.RENDER_PLACEMENT_BOX_SIDES.getBooleanValue())) { - RenderUtils.renderAreaSides(pos1, pos2, sideColor, matrices, this.mc); + RenderUtils.renderAreaSides(pos1, pos2, sideColor, matrix4f, this.mc); } if (box.getSelectedCorner() == Corner.CORNER_1) { Color4f color = Color4f.fromColor(this.colorPos1, 0.4f); - RenderUtils.renderAreaSides(pos1, pos1, color, matrices, this.mc); + RenderUtils.renderAreaSides(pos1, pos1, color, matrix4f, this.mc); } else if (box.getSelectedCorner() == Corner.CORNER_2) { Color4f color = Color4f.fromColor(this.colorPos2, 0.4f); - RenderUtils.renderAreaSides(pos2, pos2, color, matrices, this.mc); + RenderUtils.renderAreaSides(pos2, pos2, color, matrix4f, this.mc); } RenderUtils.renderBlockOutline(pos1, expand, lineWidthBlockBox, color1, this.mc); @@ -326,7 +322,7 @@ else if (box.getSelectedCorner() == Corner.CORNER_2) } else { - RenderUtils.renderBlockOutlineOverlapping(pos1, expand, lineWidthBlockBox, color1, color2, this.colorOverlapping, matrices, this.mc); + RenderUtils.renderBlockOutlineOverlapping(pos1, expand, lineWidthBlockBox, color1, color2, this.colorOverlapping, matrix4f, this.mc); } } else @@ -343,7 +339,7 @@ else if (box.getSelectedCorner() == Corner.CORNER_2) } } - public void renderSchematicVerifierMismatches(MatrixStack matrices) + public void renderSchematicVerifierMismatches(Matrix4f matrix4f) { SchematicPlacement placement = DataManager.getSchematicPlacementManager().getSelectedSchematicPlacement(); @@ -359,12 +355,12 @@ public void renderSchematicVerifierMismatches(MatrixStack matrices) List posList = verifier.getSelectedMismatchBlockPositionsForRender(); BlockHitResult trace = RayTraceUtils.traceToPositions(posList, entity, 128); BlockPos posLook = trace != null && trace.getType() == HitResult.Type.BLOCK ? trace.getBlockPos() : null; - this.renderSchematicMismatches(list, posLook, matrices); + this.renderSchematicMismatches(list, posLook, matrix4f); } } } - private void renderSchematicMismatches(List posList, @Nullable BlockPos lookPos, MatrixStack matrices) + private void renderSchematicMismatches(List posList, @Nullable BlockPos lookPos, Matrix4f matrix4f) { RenderSystem.disableDepthTest(); RenderSystem.depthMask(false); @@ -637,7 +633,7 @@ private void addBlockInfoLines(BlockState state) this.blockInfoLines.addAll(BlockUtils.getFormattedBlockStateProperties(state)); } - public void renderSchematicRebuildTargetingOverlay(MatrixStack matrixStack) + public void renderSchematicRebuildTargetingOverlay(Matrix4f matrix4f) { RayTraceWrapper traceWrapper = null; Color4f color = null; @@ -691,12 +687,12 @@ else if (Hotkeys.SCHEMATIC_EDIT_REPLACE_DIRECTION.getKeybind().isKeybindHeld()) if (direction) { fi.dy.masa.malilib.render.RenderUtils.renderBlockTargetingOverlay( - entity, pos, trace.getSide(), trace.getPos(), color, matrixStack, this.mc); + entity, pos, trace.getSide(), trace.getPos(), color, matrix4f, this.mc); } else { fi.dy.masa.malilib.render.RenderUtils.renderBlockTargetingOverlaySimple( - entity, pos, trace.getSide(), color, matrixStack, this.mc); + entity, pos, trace.getSide(), color, matrix4f, this.mc); } RenderSystem.disablePolygonOffset(); diff --git a/src/main/java/fi/dy/masa/litematica/render/RenderUtils.java b/src/main/java/fi/dy/masa/litematica/render/RenderUtils.java index a630e3494a..7b306beb6e 100644 --- a/src/main/java/fi/dy/masa/litematica/render/RenderUtils.java +++ b/src/main/java/fi/dy/masa/litematica/render/RenderUtils.java @@ -1,19 +1,15 @@ package fi.dy.masa.litematica.render; import java.util.List; +import org.joml.Matrix4f; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.block.BlockState; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.render.Tessellator; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; +import net.minecraft.client.render.*; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedQuad; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.inventory.Inventory; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; @@ -116,7 +112,7 @@ public static void drawConnectingLineBatchedLines(BlockPos pos1, BlockPos pos2, } public static void renderBlockOutlineOverlapping(BlockPos pos, float expand, float lineWidth, - Color4f color1, Color4f color2, Color4f color3, MatrixStack matrices, MinecraftClient mc) + Color4f color1, Color4f color2, Color4f color3, Matrix4f matrix4f, MinecraftClient mc) { Vec3d cameraPos = mc.gameRenderer.getCamera().getPos(); final double dx = cameraPos.x; @@ -256,7 +252,7 @@ private static void drawBoundingBoxLinesZ(BufferBuilder buffer, double minX, dou buffer.vertex(maxX, maxY, maxZ).color(color.r, color.g, color.b, color.a).next(); } - public static void renderAreaSides(BlockPos pos1, BlockPos pos2, Color4f color, MatrixStack matrices, MinecraftClient mc) + public static void renderAreaSides(BlockPos pos1, BlockPos pos2, Color4f color, Matrix4f matrix4f, MinecraftClient mc) { RenderSystem.enableBlend(); RenderSystem.disableCull(); diff --git a/src/main/java/fi/dy/masa/litematica/render/schematic/BlockModelRendererSchematic.java b/src/main/java/fi/dy/masa/litematica/render/schematic/BlockModelRendererSchematic.java index dbf26c42c6..ca5d897550 100644 --- a/src/main/java/fi/dy/masa/litematica/render/schematic/BlockModelRendererSchematic.java +++ b/src/main/java/fi/dy/masa/litematica/render/schematic/BlockModelRendererSchematic.java @@ -1,8 +1,8 @@ package fi.dy.masa.litematica.render.schematic; +import javax.annotation.Nullable; import java.util.BitSet; import java.util.List; -import javax.annotation.Nullable; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.client.MinecraftClient; @@ -19,9 +19,9 @@ import net.minecraft.util.math.random.BaseRandom; import net.minecraft.util.math.random.LocalRandom; import net.minecraft.world.BlockRenderView; -import fi.dy.masa.malilib.util.PositionUtils; import fi.dy.masa.litematica.config.Configs; import fi.dy.masa.litematica.data.DataManager; +import fi.dy.masa.malilib.util.PositionUtils; public class BlockModelRendererSchematic { @@ -34,24 +34,24 @@ public BlockModelRendererSchematic(BlockColors blockColorsIn) } public boolean renderModel(BlockRenderView worldIn, BakedModel modelIn, BlockState stateIn, - BlockPos posIn, MatrixStack matrices, + BlockPos posIn, MatrixStack matrixStack, VertexConsumer vertexConsumer, long rand) { boolean ao = MinecraftClient.isAmbientOcclusionEnabled() && stateIn.getLuminance() == 0 && modelIn.useAmbientOcclusion(); Vec3d offset = stateIn.getModelOffset(worldIn, posIn); - matrices.translate(offset.x, offset.y, offset.z); + matrixStack.translate((float) offset.x, (float) offset.y, (float) offset.z); int overlay = OverlayTexture.DEFAULT_UV; try { if (ao) { - return this.renderModelSmooth(worldIn, modelIn, stateIn, posIn, matrices, vertexConsumer, this.random, rand, overlay); + return this.renderModelSmooth(worldIn, modelIn, stateIn, posIn, matrixStack, vertexConsumer, this.random, rand, overlay); } else { - return this.renderModelFlat(worldIn, modelIn, stateIn, posIn, matrices, vertexConsumer, this.random, rand, overlay); + return this.renderModelFlat(worldIn, modelIn, stateIn, posIn, matrixStack, vertexConsumer, this.random, rand, overlay); } } catch (Throwable throwable) @@ -67,7 +67,7 @@ public boolean renderModel(BlockRenderView worldIn, BakedModel modelIn, BlockSta } } - public boolean renderModelSmooth(BlockRenderView worldIn, BakedModel modelIn, BlockState stateIn, BlockPos posIn, MatrixStack matrices, + public boolean renderModelSmooth(BlockRenderView worldIn, BakedModel modelIn, BlockState stateIn, BlockPos posIn, MatrixStack matrixStack, VertexConsumer vertexConsumer, BaseRandom random, long seedIn, int overlay) { boolean renderedSomething = false; @@ -84,7 +84,7 @@ public boolean renderModelSmooth(BlockRenderView worldIn, BakedModel modelIn, Bl { if (this.shouldRenderModelSide(worldIn, stateIn, posIn, side)) { - this.renderQuadsSmooth(worldIn, stateIn, posIn, matrices, vertexConsumer, quads, quadBounds, bitset, aoFace, overlay); + this.renderQuadsSmooth(worldIn, stateIn, posIn, matrixStack, vertexConsumer, quads, quadBounds, bitset, aoFace, overlay); renderedSomething = true; } } @@ -95,7 +95,7 @@ public boolean renderModelSmooth(BlockRenderView worldIn, BakedModel modelIn, Bl if (quads.isEmpty() == false) { - this.renderQuadsSmooth(worldIn, stateIn, posIn, matrices, vertexConsumer, quads, quadBounds, bitset, aoFace, overlay); + this.renderQuadsSmooth(worldIn, stateIn, posIn, matrixStack, vertexConsumer, quads, quadBounds, bitset, aoFace, overlay); renderedSomething = true; } @@ -103,7 +103,7 @@ public boolean renderModelSmooth(BlockRenderView worldIn, BakedModel modelIn, Bl } public boolean renderModelFlat(BlockRenderView worldIn, BakedModel modelIn, BlockState stateIn, - BlockPos posIn, MatrixStack matrices, + BlockPos posIn, MatrixStack matrixStack, VertexConsumer vertexConsumer, BaseRandom random, long seedIn, int overlay) { boolean renderedSomething = false; @@ -119,7 +119,7 @@ public boolean renderModelFlat(BlockRenderView worldIn, BakedModel modelIn, Bloc if (this.shouldRenderModelSide(worldIn, stateIn, posIn, side)) { int light = WorldRenderer.getLightmapCoordinates(worldIn, stateIn, posIn.offset(side)); - this.renderQuadsFlat(worldIn, stateIn, posIn, light, overlay, false, matrices, vertexConsumer, quads, bitset); + this.renderQuadsFlat(worldIn, stateIn, posIn, light, overlay, false, matrixStack, vertexConsumer, quads, bitset); renderedSomething = true; } } @@ -130,7 +130,7 @@ public boolean renderModelFlat(BlockRenderView worldIn, BakedModel modelIn, Bloc if (quads.isEmpty() == false) { - this.renderQuadsFlat(worldIn, stateIn, posIn, -1, overlay, true, matrices, vertexConsumer, quads, bitset); + this.renderQuadsFlat(worldIn, stateIn, posIn, -1, overlay, true, matrixStack, vertexConsumer, quads, bitset); renderedSomething = true; } @@ -144,7 +144,7 @@ protected boolean shouldRenderModelSide(BlockRenderView worldIn, BlockState stat Block.shouldDrawSide(stateIn, worldIn, posIn, side ,posIn.offset(side)); } - protected void renderQuadsSmooth(BlockRenderView world, BlockState state, BlockPos pos, MatrixStack matrices, + protected void renderQuadsSmooth(BlockRenderView world, BlockState state, BlockPos pos, MatrixStack matrixStack, VertexConsumer vertexConsumer, List list, float[] box, BitSet flags, AmbientOcclusionCalculator ambientOcclusionCalculator, int overlay) { final int size = list.size(); @@ -156,7 +156,7 @@ protected void renderQuadsSmooth(BlockRenderView world, BlockState state, BlockP this.getQuadDimensions(world, state, pos, bakedQuad.getVertexData(), bakedQuad.getFace(), box, flags); ambientOcclusionCalculator.apply(world, state, pos, bakedQuad.getFace(), box, flags, bakedQuad.hasShade()); - this.renderQuad(world, state, pos, vertexConsumer, matrices.peek(), bakedQuad, + this.renderQuad(world, state, pos, vertexConsumer, matrixStack, bakedQuad, ambientOcclusionCalculator.brightness[0], ambientOcclusionCalculator.brightness[1], ambientOcclusionCalculator.brightness[2], @@ -169,7 +169,7 @@ protected void renderQuadsSmooth(BlockRenderView world, BlockState state, BlockP } protected void renderQuadsFlat(BlockRenderView world, BlockState state, BlockPos pos, - int light, int overlay, boolean useWorldLight, MatrixStack matrices, VertexConsumer vertexConsumer, List list, BitSet flags) + int light, int overlay, boolean useWorldLight, MatrixStack matrixStack, VertexConsumer vertexConsumer, List list, BitSet flags) { final int size = list.size(); @@ -184,11 +184,11 @@ protected void renderQuadsFlat(BlockRenderView world, BlockState state, BlockPos light = WorldRenderer.getLightmapCoordinates(world, state, blockPos); } - this.renderQuad(world, state, pos, vertexConsumer, matrices.peek(), bakedQuad, 1.0F, 1.0F, 1.0F, 1.0F, light, light, light, light, overlay); + this.renderQuad(world, state, pos, vertexConsumer, matrixStack, bakedQuad, 1.0F, 1.0F, 1.0F, 1.0F, light, light, light, light, overlay); } } - protected void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, VertexConsumer vertexConsumer, MatrixStack.Entry matrixEntry, + protected void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, VertexConsumer vertexConsumer, MatrixStack matrixStack, BakedQuad quad, float brightness0, float brightness1, float brightness2, float brightness3, int light0, int light1, int light2, int light3, int overlay) { @@ -209,9 +209,11 @@ protected void renderQuad(BlockRenderView world, BlockState state, BlockPos pos, g = 1.0F; b = 1.0F; } + // TODO -- Make sure this works --> the VertexCustomer.quad() call uses MartrixStack.Entry, + // maybe Matrix4f directly in the future since matrixStack.peek() = matrix4f basically - vertexConsumer.quad(matrixEntry, quad, new float[]{ brightness0, brightness1, brightness2, brightness3 }, - r, g, b, new int[]{ light0, light1, light2, light3 }, overlay, true); + vertexConsumer.quad(matrixStack.peek(), quad, new float[]{ brightness0, brightness1, brightness2, brightness3 }, + r, g, b, 1.0f, new int[]{ light0, light1, light2, light3 }, overlay, true); } protected void getQuadDimensions(BlockRenderView world, BlockState state, BlockPos pos, int[] vertexData, Direction face, @Nullable float[] box, BitSet flags) diff --git a/src/main/java/fi/dy/masa/litematica/render/schematic/ChunkRendererSchematicVbo.java b/src/main/java/fi/dy/masa/litematica/render/schematic/ChunkRendererSchematicVbo.java index 207a4c0095..d3f1269818 100644 --- a/src/main/java/fi/dy/masa/litematica/render/schematic/ChunkRendererSchematicVbo.java +++ b/src/main/java/fi/dy/masa/litematica/render/schematic/ChunkRendererSchematicVbo.java @@ -1,15 +1,9 @@ package fi.dy.masa.litematica.render.schematic; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import javax.annotation.Nullable; +import java.util.*; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Supplier; -import javax.annotation.Nullable; import com.google.common.collect.Sets; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.VertexSorter; @@ -20,12 +14,7 @@ import net.minecraft.block.entity.BlockEntity; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gl.VertexBuffer; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.RenderLayers; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; +import net.minecraft.client.render.*; import net.minecraft.client.render.block.entity.BlockEntityRenderer; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.util.math.MatrixStack; @@ -271,7 +260,9 @@ public void rebuildChunk(ChunkRenderTaskSchematic task) float z = (float) cameraPos.z - this.position.getZ(); Set usedLayers = new HashSet<>(); BufferBuilderCache buffers = task.getBufferCache(); - MatrixStack matrices = new MatrixStack(); + MatrixStack matrixStack = new MatrixStack(); + // TODO --> Do we need to change this to a Matrix4f in the future, + // when Matrix4f doesn't break things here or do we need to call RenderSystem again? int bottomY = this.position.getY(); for (IntBoundingBox box : this.boxes) @@ -292,12 +283,12 @@ public void rebuildChunk(ChunkRenderTaskSchematic task) // Fluid models and the overlay use the VertexConsumer#vertex(x, y, z) method. // Fluid rendering and the overlay do not use the MatrixStack. // Block models use the VertexConsumer#quad() method, and they use the MatrixStack. - matrices.push(); - matrices.translate(posMutable.getX() & 0xF, posMutable.getY() - bottomY, posMutable.getZ() & 0xF); + matrixStack.push(); + matrixStack.translate(posMutable.getX() & 0xF, posMutable.getY() - bottomY, posMutable.getZ() & 0xF); - this.renderBlocksAndOverlay(posMutable, data, tileEntities, usedLayers, matrices, buffers); + this.renderBlocksAndOverlay(posMutable, data, tileEntities, usedLayers, matrixStack, buffers); - matrices.pop(); + matrixStack.pop(); } } @@ -351,7 +342,7 @@ public void rebuildChunk(ChunkRenderTaskSchematic task) } protected void renderBlocksAndOverlay(BlockPos pos, ChunkRenderDataSchematic data, Set tileEntities, - Set usedLayers, MatrixStack matrices, BufferBuilderCache buffers) + Set usedLayers, MatrixStack matrixStack, BufferBuilderCache buffers) { BlockState stateSchematic = this.schematicWorldView.getBlockState(pos); BlockState stateClient = this.clientWorldView.getBlockState(pos); @@ -407,7 +398,7 @@ protected void renderBlocksAndOverlay(BlockPos pos, ChunkRenderDataSchematic dat this.preRenderBlocks(bufferSchematic, layer); } - if (this.worldRenderer.renderBlock(this.schematicWorldView, stateSchematic, pos, matrices, bufferSchematic)) + if (this.worldRenderer.renderBlock(this.schematicWorldView, stateSchematic, pos, matrixStack, bufferSchematic)) { usedLayers.add(layer); } @@ -663,6 +654,7 @@ protected OverlayType getOverlayType(BlockState stateSchematic, BlockState state boolean clientHasAir = stateClient.isAir(); boolean schematicHasAir = stateSchematic.isAir(); + // TODO --> Maybe someday Mojang will add something to replace isLiquid(), and isSolid(), someday? if (schematicHasAir) { return (clientHasAir || (this.ignoreClientWorldFluids && stateClient.isLiquid())) ? OverlayType.NONE : OverlayType.EXTRA; diff --git a/src/main/java/fi/dy/masa/litematica/render/schematic/WorldRendererSchematic.java b/src/main/java/fi/dy/masa/litematica/render/schematic/WorldRendererSchematic.java index eb4c7df1e2..10a164291c 100644 --- a/src/main/java/fi/dy/masa/litematica/render/schematic/WorldRendererSchematic.java +++ b/src/main/java/fi/dy/masa/litematica/render/schematic/WorldRendererSchematic.java @@ -1,15 +1,10 @@ package fi.dy.masa.litematica.render.schematic; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; import javax.annotation.Nullable; -import com.mojang.blaze3d.systems.RenderSystem; +import java.util.*; import org.joml.Matrix4f; +import org.joml.Matrix4fStack; +import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockState; @@ -18,14 +13,7 @@ import net.minecraft.client.gl.GlUniform; import net.minecraft.client.gl.ShaderProgram; import net.minecraft.client.gl.VertexBuffer; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.BufferBuilderStorage; -import net.minecraft.client.render.BufferRenderer; -import net.minecraft.client.render.Camera; -import net.minecraft.client.render.Frustum; -import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.*; import net.minecraft.client.render.block.BlockRenderManager; import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; import net.minecraft.client.render.entity.EntityRenderDispatcher; @@ -402,7 +390,7 @@ public void updateChunks(long finishTimeNano) this.mc.getProfiler().pop(); } - public int renderBlockLayer(RenderLayer renderLayer, MatrixStack matrices, Camera camera, Matrix4f projMatrix) + public int renderBlockLayer(RenderLayer renderLayer, Matrix4f matrices, Camera camera, Matrix4f projMatrix) { this.world.getProfiler().push("render_block_layer_" + renderLayer.toString()); @@ -518,17 +506,17 @@ public int renderBlockLayer(RenderLayer renderLayer, MatrixStack matrices, Camer return count; } - public void renderBlockOverlays(MatrixStack matrices, Camera camera, Matrix4f projMatrix) + public void renderBlockOverlays(Matrix4f matrix4f, Camera camera, Matrix4f projMatrix) { - this.renderBlockOverlay(OverlayRenderType.OUTLINE, matrices, camera, projMatrix); - this.renderBlockOverlay(OverlayRenderType.QUAD, matrices, camera, projMatrix); + this.renderBlockOverlay(OverlayRenderType.OUTLINE, matrix4f, camera, projMatrix); + this.renderBlockOverlay(OverlayRenderType.QUAD, matrix4f, camera, projMatrix); } - protected static void initShader(ShaderProgram shader, MatrixStack matrices, Matrix4f projMatrix) + protected static void initShader(ShaderProgram shader, Matrix4f matrix4f, Matrix4f projMatrix) { for (int i = 0; i < 12; ++i) shader.addSampler("Sampler" + i, RenderSystem.getShaderTexture(i)); - if (shader.modelViewMat != null) shader.modelViewMat.set(matrices.peek().getPositionMatrix()); + if (shader.modelViewMat != null) shader.modelViewMat.set(matrix4f); if (shader.projectionMat != null) shader.projectionMat.set(projMatrix); if (shader.colorModulator != null) shader.colorModulator.set(RenderSystem.getShaderColor()); if (shader.fogStart != null) shader.fogStart.set(RenderSystem.getShaderFogStart()); @@ -538,7 +526,7 @@ protected static void initShader(ShaderProgram shader, MatrixStack matrices, Mat if (shader.gameTime != null) shader.gameTime.set(RenderSystem.getShaderGameTime()); } - protected void renderBlockOverlay(OverlayRenderType type, MatrixStack matrixStack, Camera camera, Matrix4f projMatrix) + protected void renderBlockOverlay(OverlayRenderType type, Matrix4f matrix4f, Camera camera, Matrix4f projMatrix) { RenderLayer renderLayer = RenderLayer.getTranslucent(); renderLayer.startDrawing(); @@ -571,6 +559,9 @@ protected void renderBlockOverlay(OverlayRenderType type, MatrixStack matrixStac ShaderProgram shader = RenderSystem.getShader(); BufferRenderer.reset(); + // I tried using the matrix4f value here, only to have things break + Matrix4fStack matrix4fStack = RenderSystem.getModelViewStack(); + for (int i = this.renderInfos.size() - 1; i >= 0; --i) { ChunkRendererSchematicVbo renderer = this.renderInfos.get(i); @@ -584,12 +575,13 @@ protected void renderBlockOverlay(OverlayRenderType type, MatrixStack matrixStac VertexBuffer buffer = renderer.getOverlayVertexBuffer(type); BlockPos chunkOrigin = renderer.getOrigin(); - matrixStack.push(); - matrixStack.translate(chunkOrigin.getX() - x, chunkOrigin.getY() - y, chunkOrigin.getZ() - z); + matrix4fStack.pushMatrix(); + matrix4fStack.translate((float) (chunkOrigin.getX() - x), (float) (chunkOrigin.getY() - y), (float) (chunkOrigin.getZ() - z)); buffer.bind(); - buffer.draw(matrixStack.peek().getPositionMatrix(), projMatrix, shader); + buffer.draw(matrix4fStack, projMatrix, shader); + VertexBuffer.unbind(); - matrixStack.pop(); + matrix4fStack.popMatrix(); } } } @@ -602,7 +594,7 @@ protected void renderBlockOverlay(OverlayRenderType type, MatrixStack matrixStac this.world.getProfiler().pop(); } - public boolean renderBlock(BlockRenderView world, BlockState state, BlockPos pos, MatrixStack matrices, BufferBuilder bufferBuilderIn) + public boolean renderBlock(BlockRenderView world, BlockState state, BlockPos pos, MatrixStack matrixStack, BufferBuilder bufferBuilderIn) { try { @@ -615,7 +607,7 @@ public boolean renderBlock(BlockRenderView world, BlockState state, BlockPos pos else { return renderType == BlockRenderType.MODEL && - this.blockModelRenderer.renderModel(world, this.getModelForState(state), state, pos, matrices, bufferBuilderIn, state.getRenderingSeed(pos)); + this.blockModelRenderer.renderModel(world, this.getModelForState(state), state, pos, matrixStack, bufferBuilderIn, state.getRenderingSeed(pos)); } } catch (Throwable throwable) @@ -642,7 +634,7 @@ public BakedModel getModelForState(BlockState state) return this.blockRenderManager.getModel(state); } - public void renderEntities(Camera camera, Frustum frustum, MatrixStack matrices, float partialTicks) + public void renderEntities(Camera camera, Frustum frustum, Matrix4f matrix4f, float partialTicks) { if (this.renderEntitiesStartupCounter > 0) { @@ -668,6 +660,16 @@ public void renderEntities(Camera camera, Frustum frustum, MatrixStack matrices, this.world.getProfiler().swap("regular_entities"); //List entitiesMultipass = Lists.newArrayList(); + // TODO --> Convert Matrix4f back to to MatrixStack? + // Causes strange entity behavior (translations not applied) + // if this is missing ( Including the push() and pop() ... ?) + // Doing this restores the expected behavior of Entity Rendering in the Schematic World + + MatrixStack matrixStack = new MatrixStack(); + matrixStack.push(); + matrixStack.multiplyPositionMatrix(matrix4f); + matrixStack.pop(); + VertexConsumerProvider.Immediate entityVertexConsumers = this.bufferBuilders.getEntityVertexConsumers(); LayerRange layerRange = DataManager.getRenderLayerRange(); @@ -694,8 +696,14 @@ public void renderEntities(Camera camera, Frustum frustum, MatrixStack matrices, double y = entityTmp.getY() - cameraY; double z = entityTmp.getZ() - cameraZ; - this.entityRenderDispatcher.render(entityTmp, x, y, z, entityTmp.getYaw(), 1.0f, matrices, entityVertexConsumers, this.entityRenderDispatcher.getLight(entityTmp, partialTicks)); + matrixStack.push(); + + // TODO --> this render() call does not seem to have a push() and pop(), + // and does not accept Matrix4f/Matrix4fStack as a parameter + this.entityRenderDispatcher.render(entityTmp, x, y, z, entityTmp.getYaw(), 1.0f, matrixStack, entityVertexConsumers, this.entityRenderDispatcher.getLight(entityTmp, partialTicks)); ++this.countEntitiesRendered; + + matrixStack.pop(); } } } @@ -709,7 +717,7 @@ public void renderEntities(Camera camera, Frustum frustum, MatrixStack matrices, ChunkRenderDataSchematic data = chunkRenderer.getChunkRenderData(); List tiles = data.getBlockEntities(); - if (tiles.isEmpty() == false) + if (tiles.isEmpty() == false) { BlockPos chunkOrigin = chunkRenderer.getOrigin(); ChunkSchematic chunk = this.world.getChunkProvider().getChunk(chunkOrigin.getX() >> 4, chunkOrigin.getZ() >> 4); @@ -721,12 +729,14 @@ public void renderEntities(Camera camera, Frustum frustum, MatrixStack matrices, try { BlockPos pos = te.getPos(); - matrices.push(); - matrices.translate(pos.getX() - cameraX, pos.getY() - cameraY, pos.getZ() - cameraZ); + matrixStack.push(); + matrixStack.translate(pos.getX() - cameraX, pos.getY() - cameraY, pos.getZ() - cameraZ); - renderer.render(te, partialTicks, matrices, entityVertexConsumers); + // TODO --> this render() call does not seem to have a push() and pop(), + // and does not accept Matrix4f/Matrix4fStack as a parameter + renderer.render(te, partialTicks, matrixStack, entityVertexConsumers); - matrices.pop(); + matrixStack.pop(); } catch (Exception ignore) { @@ -743,12 +753,14 @@ public void renderEntities(Camera camera, Frustum frustum, MatrixStack matrices, try { BlockPos pos = te.getPos(); - matrices.push(); - matrices.translate(pos.getX() - cameraX, pos.getY() - cameraY, pos.getZ() - cameraZ); + matrixStack.push(); + matrixStack.translate(pos.getX() - cameraX, pos.getY() - cameraY, pos.getZ() - cameraZ); - renderer.render(te, partialTicks, matrices, entityVertexConsumers); + // TODO --> this render() call does not seem to have a push() and pop(), + // and does not accept Matrix4f/Matrix4fStack as a parameter + renderer.render(te, partialTicks, matrixStack, entityVertexConsumers); - matrices.pop(); + matrixStack.pop(); } catch (Exception ignore) { diff --git a/src/main/java/fi/dy/masa/litematica/scheduler/tasks/TaskCountBlocksPlacement.java b/src/main/java/fi/dy/masa/litematica/scheduler/tasks/TaskCountBlocksPlacement.java index 0c9fa9fbbc..99ee434f16 100644 --- a/src/main/java/fi/dy/masa/litematica/scheduler/tasks/TaskCountBlocksPlacement.java +++ b/src/main/java/fi/dy/masa/litematica/scheduler/tasks/TaskCountBlocksPlacement.java @@ -62,7 +62,7 @@ protected void countAtPosition(BlockPos pos) this.countsMissing.addTo(stateSchematic, 1); } else if (stateClient != stateSchematic && - (this.ignoreState == false || stateClient.getBlock() != stateSchematic.getBlock())) + (this.ignoreState == false || stateClient.getBlock() != stateSchematic.getBlock())) { this.countsMissing.addTo(stateSchematic, 1); this.countsMismatch.addTo(stateSchematic, 1); diff --git a/src/main/java/fi/dy/masa/litematica/scheduler/tasks/TaskPasteSchematicPerChunkCommand.java b/src/main/java/fi/dy/masa/litematica/scheduler/tasks/TaskPasteSchematicPerChunkCommand.java index 004a5953f1..a9a63103f8 100644 --- a/src/main/java/fi/dy/masa/litematica/scheduler/tasks/TaskPasteSchematicPerChunkCommand.java +++ b/src/main/java/fi/dy/masa/litematica/scheduler/tasks/TaskPasteSchematicPerChunkCommand.java @@ -1,13 +1,9 @@ package fi.dy.masa.litematica.scheduler.tasks; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Locale; -import java.util.Queue; -import java.util.Set; -import java.util.function.Consumer; +import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.*; +import java.util.function.Consumer; import com.google.common.collect.Queues; import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap; import it.unimi.dsi.fastutil.longs.LongArrayList; @@ -17,21 +13,19 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.world.ClientWorld; import net.minecraft.command.argument.BlockArgumentParser; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.NbtComponent; import net.minecraft.entity.Entity; import net.minecraft.entity.decoration.ItemFrameEntity; import net.minecraft.item.ItemStack; -import net.minecraft.item.PlayerHeadItem; import net.minecraft.nbt.NbtCompound; +import net.minecraft.registry.DynamicRegistryManager; import net.minecraft.registry.Registries; import net.minecraft.registry.tag.BlockTags; import net.minecraft.util.Hand; import net.minecraft.util.Identifier; import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.*; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.WorldChunk; @@ -330,11 +324,11 @@ protected String getSummonCommandForItemFrame(ItemFrameEntity itemFrame, String Identifier itemId = Registries.ITEM.getId(stack.getItem()); int facingId = itemFrame.getHorizontalFacing().getId(); String nbtStr = String.format(" {Facing:%db,Item:{id:\"%s\",Count:1b}}", facingId, itemId); - NbtCompound tag = stack.getNbt(); + NbtComponent entityComp = stack.get(DataComponentTypes.ENTITY_DATA); - if (tag != null) + if (entityComp != null && entityComp.isEmpty() == false) { - String itemNbt = tag.toString(); + String itemNbt = entityComp.toString(); String tmp = String.format(" {Facing:%db,Item:{id:\"%s\",Count:1b,tag:%s}}", facingId, itemId, itemNbt); @@ -447,7 +441,7 @@ protected void setDataViaDataModify(BlockPos pos, BlockState state, BlockEntity try { - Set keys = new HashSet<>(be.createNbt().getKeys()); + Set keys = new HashSet<>(be.createNbt(clientWorld.getRegistryManager()).getKeys()); keys.remove("id"); keys.remove("x"); keys.remove("y"); @@ -486,7 +480,7 @@ protected void specialPasteSignBlock(BlockPos pos, BlockState state, World schem if (be instanceof SignBlockEntity signBe) { - NbtCompound tag = be.createNbt(); + NbtCompound tag = be.createNbt(schematicWorld.getRegistryManager()); if (tag != null) { @@ -547,12 +541,12 @@ protected void placeBlockViaClone(BlockPos pos, BlockState state, BlockEntity be @Nullable protected BlockPos placeNbtPickedBlock(BlockPos pos, BlockState state, BlockEntity be, - World schematicWorld, ClientWorld clientWorld) + @Nonnull World schematicWorld, @Nonnull ClientWorld clientWorld) { - double reach = this.mc.interactionManager.getReachDistance(); + double reach = this.mc.player.getBlockInteractionRange(); BlockPos placementPos = this.findEmptyNearbyPosition(clientWorld, this.mc.player.getPos(), 4, reach); - if (placementPos != null && preparePickedStack(pos, state, be, schematicWorld, this.mc)) + if (placementPos != null && preparePickedStack(pos, state, be, schematicWorld, this.mc, clientWorld.getRegistryManager())) { Vec3d posVec = new Vec3d(placementPos.getX() + 0.5, placementPos.getY() + 0.5, placementPos.getZ() + 0.5); BlockHitResult hitResult = new BlockHitResult(posVec, Direction.UP, placementPos, true); @@ -986,13 +980,14 @@ public static boolean isPositionAndSidesEmpty(World world, BlockPos centerPos, B } protected static boolean preparePickedStack(BlockPos pos, BlockState state, BlockEntity be, - World world, MinecraftClient mc) + World world, MinecraftClient mc, + @Nonnull DynamicRegistryManager registryManager) { ItemStack stack = state.getBlock().getPickStack(world, pos, state); if (stack.isEmpty() == false) { - addBlockEntityNbt(stack, be); + be.setStackNbt(stack, registryManager); mc.player.getInventory().offHand.set(0, stack); mc.interactionManager.clickCreativeStack(stack, 45); return true; @@ -1000,19 +995,4 @@ protected static boolean preparePickedStack(BlockPos pos, BlockState state, Bloc return false; } - - public static void addBlockEntityNbt(ItemStack stack, BlockEntity be) - { - NbtCompound tag = be.createNbt(); - - if (stack.getItem() instanceof PlayerHeadItem && tag.contains("SkullOwner")) - { - NbtCompound ownerTag = tag.getCompound("SkullOwner"); - stack.getOrCreateNbt().put("SkullOwner", ownerTag); - } - else - { - stack.setSubNbt("BlockEntityTag", tag); - } - } } diff --git a/src/main/java/fi/dy/masa/litematica/schematic/LitematicaSchematic.java b/src/main/java/fi/dy/masa/litematica/schematic/LitematicaSchematic.java index 6dfbef2628..fe0a17d9a7 100644 --- a/src/main/java/fi/dy/masa/litematica/schematic/LitematicaSchematic.java +++ b/src/main/java/fi/dy/masa/litematica/schematic/LitematicaSchematic.java @@ -1,16 +1,9 @@ package fi.dy.masa.litematica.schematic; +import javax.annotation.Nullable; import java.io.File; import java.io.FileOutputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; -import javax.annotation.Nullable; +import java.util.*; import com.google.common.collect.ImmutableMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; @@ -25,12 +18,7 @@ import net.minecraft.fluid.Fluid; import net.minecraft.fluid.Fluids; import net.minecraft.inventory.Inventory; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtElement; -import net.minecraft.nbt.NbtHelper; -import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.NbtList; -import net.minecraft.nbt.NbtLongArray; +import net.minecraft.nbt.*; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.registry.RegistryEntryLookup; @@ -39,18 +27,15 @@ import net.minecraft.util.BlockMirror; import net.minecraft.util.BlockRotation; import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.util.math.ChunkSectionPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.math.Vec3i; +import net.minecraft.util.math.*; import net.minecraft.world.World; import net.minecraft.world.tick.ChunkTickScheduler; import net.minecraft.world.tick.OrderedTick; import net.minecraft.world.tick.TickPriority; +import fi.dy.masa.malilib.gui.Message.MessageType; +import fi.dy.masa.malilib.interfaces.IStringConsumer; +import fi.dy.masa.malilib.util.*; import fi.dy.masa.litematica.Litematica; import fi.dy.masa.litematica.config.Configs; import fi.dy.masa.litematica.mixin.IMixinWorldTickScheduler; @@ -65,29 +50,18 @@ import fi.dy.masa.litematica.selection.Box; import fi.dy.masa.litematica.util.BlockUtils; import fi.dy.masa.litematica.util.EntityUtils; -import fi.dy.masa.litematica.util.FileType; -import fi.dy.masa.litematica.util.NbtUtils; import fi.dy.masa.litematica.util.PositionUtils; -import fi.dy.masa.litematica.util.ReplaceBehavior; -import fi.dy.masa.litematica.util.SchematicPlacingUtils; import fi.dy.masa.litematica.util.WorldUtils; -import fi.dy.masa.malilib.gui.Message.MessageType; -import fi.dy.masa.malilib.interfaces.IStringConsumer; -import fi.dy.masa.malilib.util.Constants; -import fi.dy.masa.malilib.util.FileUtils; -import fi.dy.masa.malilib.util.InfoUtils; -import fi.dy.masa.malilib.util.IntBoundingBox; -import fi.dy.masa.malilib.util.NBTUtils; -import fi.dy.masa.malilib.util.StringUtils; +import fi.dy.masa.litematica.util.*; public class LitematicaSchematic { public static final String FILE_EXTENSION = ".litematic"; public static final int SCHEMATIC_VERSION_1_13_2 = 5; + public static final int MINECRAFT_DATA_VERSION_1_12 = 1139; // MC 1.12 public static final int MINECRAFT_DATA_VERSION_1_13_2 = 1631; // MC 1.13.2 - public static final int MINECRAFT_DATA_VERSION = SharedConstants.getGameVersion().getSaveVersion().getId(); - public static final int SCHEMATIC_VERSION = 6; + public static final int SCHEMATIC_VERSION = 7; // This is basically a "sub-version" for the schematic version, // intended to help with possible data fix needs that are discovered. public static final int SCHEMATIC_VERSION_SUB = 1; // Bump to one after the sleeping entity position fix @@ -461,7 +435,7 @@ private boolean placeBlocksToWorld(World world, BlockPos origin, BlockPos region try { - te.readNbt(teNBT); + te.read(teNBT, world.getRegistryManager()); if (ignoreInventories && te instanceof Inventory) { @@ -630,7 +604,7 @@ public void takeEntitiesFromWorldWithinChunk(World world, int chunkX, int chunkZ // warning about invalid hanging position when loading the entity from NBT if (entity instanceof AbstractDecorationEntity decorationEntity) { - BlockPos p = decorationEntity.getDecorationBlockPos(); + BlockPos p = decorationEntity.getBlockPos(); tag.putInt("TileX", p.getX() - regionPosAbs.getX()); tag.putInt("TileY", p.getY() - regionPosAbs.getY()); tag.putInt("TileZ", p.getZ() - regionPosAbs.getZ()); @@ -702,7 +676,7 @@ private void takeBlocksFromWorld(World world, List boxes, SchematicSaveInfo { // TODO Add a TileEntity NBT cache from the Chunk packets, to get the original synced data (too) BlockPos pos = new BlockPos(x, y, z); - NbtCompound tag = te.createNbtWithId(); + NbtCompound tag = te.createNbtWithId(world.getRegistryManager()); NBTUtils.writeBlockPosToTag(pos, tag); tileEntityMap.put(pos, tag); } @@ -946,7 +920,7 @@ public void takeBlocksFromWorldWithinChunk(World world, ImmutableMap= 1 && version <= SCHEMATIC_VERSION) { @@ -1192,8 +1166,12 @@ private void readSubRegionsFromNBT(NbtCompound tag, int version, int minecraftDa if (version >= 2) { tiles = this.readTileEntitiesFromNBT(regionTag.getList("TileEntities", Constants.NBT.TAG_COMPOUND)); + tiles = this.convertTileEntities_to_1_20_5(tiles, minecraftDataVersion); this.tileEntities.put(regionName, tiles); - this.entities.put(regionName, this.readEntitiesFromNBT(regionTag.getList("Entities", Constants.NBT.TAG_COMPOUND))); + + NbtList entities = regionTag.getList("Entities", Constants.NBT.TAG_COMPOUND); + entities = this.convertEntities_to_1_20_5(entities, minecraftDataVersion); + this.entities.put(regionName, this.readEntitiesFromNBT(entities)); } else if (version == 1) { @@ -1228,6 +1206,7 @@ else if (version == 1) BlockPos size = posMax.subtract(posMin).add(1, 1, 1); palette = this.convertBlockStatePalette_1_12_to_1_13_2(palette, version, minecraftDataVersion); + palette = this.convertBlockStatePalette_to_1_20_5(palette, minecraftDataVersion); LitematicaBlockStateContainer container = LitematicaBlockStateContainer.createFrom(palette, blockStateArr, size); @@ -1298,6 +1277,7 @@ protected boolean readPaletteFromLitematicaFormatTag(NbtList tagList, ILitematic public static boolean isValidSpongeSchematic(NbtCompound tag) { + // v2 Sponge Schematic if (tag.contains("Width", Constants.NBT.TAG_ANY_NUMERIC) && tag.contains("Height", Constants.NBT.TAG_ANY_NUMERIC) && tag.contains("Length", Constants.NBT.TAG_ANY_NUMERIC) && @@ -1311,6 +1291,28 @@ public static boolean isValidSpongeSchematic(NbtCompound tag) return false; } + public static boolean isValidSpongeSchematicv3(NbtCompound tag) + { + // v3 Sponge Schematic + if (tag.contains("Schematic", Constants.NBT.TAG_COMPOUND)) + { + NbtCompound nbtV3 = tag.getCompound("Schematic"); + + if (nbtV3.contains("Width", Constants.NBT.TAG_ANY_NUMERIC) && + nbtV3.contains("Height", Constants.NBT.TAG_ANY_NUMERIC) && + nbtV3.contains("Length", Constants.NBT.TAG_ANY_NUMERIC) && + nbtV3.contains("Version", Constants.NBT.TAG_INT) && + nbtV3.getInt("Version") >= 3 && + nbtV3.contains("Blocks") && + nbtV3.contains("DataVersion")) + { + return isSizeValid(readSizeFromTagSponge(nbtV3)); + } + } + + return false; + } + public static Vec3i readSizeFromTagSponge(NbtCompound tag) { return new Vec3i(tag.getInt("Width"), tag.getInt("Height"), tag.getInt("Length")); @@ -1357,38 +1359,84 @@ protected boolean readSpongePaletteFromTag(NbtCompound tag, ILitematicaBlockStat return palette.setMapping(list); } - protected boolean readSpongeBlocksFromTag(NbtCompound tag, String schematicName, Vec3i size) + protected boolean readSpongeBlocksFromTag(NbtCompound tag, String schematicName, Vec3i size, int minecraftDataVersion, int spongeVersion) { - if (tag.contains("Palette", Constants.NBT.TAG_COMPOUND) && - tag.contains("BlockData", Constants.NBT.TAG_BYTE_ARRAY)) + NbtCompound blocksTag = new NbtCompound(); + NbtCompound paletteTag; + byte[] blockData; + int paletteSize; + + if (spongeVersion >= 3 && tag.contains("Blocks")) { - NbtCompound paletteTag = tag.getCompound("Palette"); - byte[] blockData = tag.getByteArray("BlockData"); - int paletteSize = paletteTag.getKeys().size(); - LitematicaBlockStateContainer container = LitematicaBlockStateContainer.createContainer(paletteSize, blockData, size); + blocksTag = tag.getCompound("Blocks"); - if (container == null) + if (blocksTag.contains("Palette", Constants.NBT.TAG_COMPOUND) && + blocksTag.contains("Data", Constants.NBT.TAG_BYTE_ARRAY) && + blocksTag.contains("BlockEntities", Constants.NBT.TAG_LIST)) + { + paletteTag = blocksTag.getCompound("Palette"); + blockData = blocksTag.getByteArray("Data"); + paletteSize = paletteTag.getKeys().size(); + } + else + { + return false; + } + } + else + { + if (tag.contains("Palette", Constants.NBT.TAG_COMPOUND) && + tag.contains("BlockData", Constants.NBT.TAG_BYTE_ARRAY)) + { + paletteTag = tag.getCompound("Palette"); + blockData = tag.getByteArray("BlockData"); + paletteSize = paletteTag.getKeys().size(); + } + else { - String msg = "Failed to read blocks from Sponge schematic"; - InfoUtils.showGuiOrInGameMessage(MessageType.ERROR, msg); - Litematica.logger.error(msg); return false; } + } + + LitematicaBlockStateContainer container = LitematicaBlockStateContainer.createContainer(paletteSize, blockData, size); + + if (container == null) + { + String msg = "Failed to read blocks from Sponge schematic"; + InfoUtils.showGuiOrInGameMessage(MessageType.ERROR, msg); + Litematica.logger.error(msg); + return false; + } - this.blockContainers.put(schematicName, container); + this.blockContainers.put(schematicName, container); - return this.readSpongePaletteFromTag(paletteTag, container.getPalette()); + if (this.readSpongePaletteFromTag(paletteTag, container.getPalette()) == false) + { + return false; } - return false; + if (spongeVersion >= 3) + { + if (blocksTag.isEmpty() == false) + { + // tileEntities list moved to "Blocks" tag for V3 + Map tileEntities = this.readSpongeBlockEntitiesFromTag(blocksTag, spongeVersion); + tileEntities = this.convertTileEntities_to_1_20_5(tileEntities, minecraftDataVersion); + this.tileEntities.put(schematicName, tileEntities); + } + else + { + return false; + } + } + + return true; } - protected Map readSpongeBlockEntitiesFromTag(NbtCompound tag) + protected Map readSpongeBlockEntitiesFromTag(NbtCompound tag, int spongeVersion) { Map blockEntities = new HashMap<>(); - - int version = tag.getInt("Version"); - String tagName = version == 1 ? "TileEntities" : "BlockEntities"; + String tagName = spongeVersion == 1 ? "TileEntities" : "BlockEntities"; NbtList tagList = tag.getList(tagName, Constants.NBT.TAG_COMPOUND); final int size = tagList.size(); @@ -1406,19 +1454,27 @@ protected Map readSpongeBlockEntitiesFromTag(NbtCompound beTag.remove("Id"); beTag.remove("Pos"); - if (version == 1) + if (spongeVersion == 1) { beTag.remove("ContentVersion"); } - blockEntities.put(pos, beTag); + if (spongeVersion >= 3) + { + NbtCompound beData = beTag.getCompound("Data"); + blockEntities.put(pos, beData); + } + else + { + blockEntities.put(pos, beTag); + } } } return blockEntities; } - protected List readSpongeEntitiesFromTag(NbtCompound tag, Vec3i offset) + protected List readSpongeEntitiesFromTag(NbtCompound tag, Vec3i offset, int spongeVersion) { List entities = new ArrayList<>(); NbtList tagList = tag.getList("Entities", Constants.NBT.TAG_COMPOUND); @@ -1426,18 +1482,31 @@ protected List readSpongeEntitiesFromTag(NbtCompound tag, Vec3i offs for (int i = 0; i < size; ++i) { - NbtCompound entityData = tagList.getCompound(i); - Vec3d pos = NbtUtils.readVec3dFromListTag(entityData); + NbtCompound entityEntry = tagList.getCompound(i); + Vec3d pos = NbtUtils.readVec3dFromListTag(entityEntry); - if (pos != null && entityData.isEmpty() == false) + if (pos != null && entityEntry.isEmpty() == false) { - pos = new Vec3d(pos.x - offset.getX(), pos.y - offset.getY(), pos.z - offset.getZ()); - entityData.putString("id", entityData.getString("Id")); + entityEntry.putString("id", entityEntry.getString("Id")); // Remove the Sponge tags from the data that is kept in memory - entityData.remove("Id"); + entityEntry.remove("Id"); - entities.add(new EntityInfo(pos, entityData)); + if (spongeVersion >= 3) + { + NbtCompound entityData = entityEntry.getCompound("Data"); + + if (entityData.contains("id", Constants.NBT.TAG_STRING) == false) + { + entityData.putString("id", entityEntry.getString("id")); + } + entities.add(new EntityInfo(pos, entityData)); + } + else + { + pos = new Vec3d(pos.x - offset.getX(), pos.y - offset.getY(), pos.z - offset.getZ()); + entities.add(new EntityInfo(pos, entityEntry)); + } } } @@ -1446,14 +1515,25 @@ protected List readSpongeEntitiesFromTag(NbtCompound tag, Vec3i offs public boolean readFromSpongeSchematic(String name, NbtCompound tag) { - if (isValidSpongeSchematic(tag) == false) + if (isValidSpongeSchematicv3(tag)) + { + // Probably not the "best" solution, but it works + NbtCompound spongeTag = tag.getCompound("Schematic"); + tag.remove("Schematic"); + tag.copyFrom(spongeTag); + } + else if (isValidSpongeSchematic(tag) == false) { return false; } + final int spongeVersion = tag.contains("Version") ? tag.getInt("Version") : -1; + final int minecraftDataVersion = tag.contains("DataVersion") ? tag.getInt("DataVersion") : Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue(); Vec3i size = readSizeFromTagSponge(tag); - if (this.readSpongeBlocksFromTag(tag, name, size) == false) + // Can't really use the Data Fixer for the Block State Palette in this format, + // so we're just going to ignore it, as long as we fix the Tile/Entities. + if (this.readSpongeBlocksFromTag(tag, name, size, minecraftDataVersion, spongeVersion) == false) { return false; } @@ -1461,23 +1541,45 @@ public boolean readFromSpongeSchematic(String name, NbtCompound tag) Vec3i offset = NbtUtils.readVec3iFromIntArray(tag, "Offset"); if (offset == null) + { offset = Vec3i.ZERO; + } + + if (spongeVersion < 3) + { + Map tileEntities = this.readSpongeBlockEntitiesFromTag(tag, spongeVersion); + tileEntities = this.convertTileEntities_to_1_20_5(tileEntities, minecraftDataVersion); + this.tileEntities.put(name, tileEntities); + } + + List entities = this.readSpongeEntitiesFromTag(tag, offset, spongeVersion); + entities = this.convertSpongeEntities_to_1_20_5(entities, minecraftDataVersion); + this.entities.put(name, entities); - this.tileEntities.put(name, this.readSpongeBlockEntitiesFromTag(tag)); - this.entities.put(name, this.readSpongeEntitiesFromTag(tag, offset)); + if (tag.contains("Metadata", Constants.NBT.TAG_COMPOUND)) + { + NbtCompound metadata = tag.getCompound("Metadata"); + this.metadata.setName(metadata.contains("Name", Constants.NBT.TAG_STRING) ? metadata.getString("Name") : name); + this.metadata.setAuthor(metadata.contains("Author", Constants.NBT.TAG_STRING) ? metadata.getString("Author") : "unknown"); + this.metadata.setTimeCreated(metadata.contains("Date", Constants.NBT.TAG_LONG) ? metadata.getLong("Date") : System.currentTimeMillis()); + } + else + { + this.metadata.setAuthor("unknown"); + this.metadata.setName(name); + this.metadata.setTimeCreated(System.currentTimeMillis()); + } if (tag.contains("author", Constants.NBT.TAG_STRING)) { - this.getMetadata().setAuthor(tag.getString("author")); + this.metadata.setAuthor(tag.getString("author")); } this.subRegionPositions.put(name, BlockPos.ORIGIN); this.subRegionSizes.put(name, new BlockPos(size)); - this.metadata.setName(name); this.metadata.setRegionCount(1); this.metadata.setTotalVolume(size.getX() * size.getY() * size.getZ()); this.metadata.setEnclosingSize(size); - this.metadata.setTimeCreated(System.currentTimeMillis()); this.metadata.setTimeModified(this.metadata.getTimeCreated()); this.metadata.setTotalBlocks(this.totalBlocksReadFromWorld); @@ -1493,6 +1595,7 @@ public boolean readFromVanillaStructure(String name, NbtCompound tag) isSizeValid(size)) { NbtList paletteTag = tag.getList("palette", Constants.NBT.TAG_COMPOUND); + int minecraftDataVersion = tag.contains("DataVersion") ? tag.getInt("DataVersion") : Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue(); Map tileMap = new HashMap<>(); this.tileEntities.put(name, tileMap); @@ -1502,9 +1605,17 @@ public boolean readFromVanillaStructure(String name, NbtCompound tag) List list = new ArrayList<>(paletteSize); RegistryEntryLookup lookup = Registries.BLOCK.getReadOnlyWrapper(); + if (minecraftDataVersion < LitematicaSchematic.MINECRAFT_DATA_VERSION) + { + Litematica.logger.info("VanillaStructure: executing Vanilla DataFixer for Block State Palette DataVersion {} -> {}", minecraftDataVersion, LitematicaSchematic.MINECRAFT_DATA_VERSION); + } for (int id = 0; id < paletteSize; ++id) { NbtCompound t = paletteTag.getCompound(id); + if (minecraftDataVersion < LitematicaSchematic.MINECRAFT_DATA_VERSION) + { + t = SchematicConversionMaps.updateBlockStates(t, minecraftDataVersion); + } BlockState state = NbtHelper.toBlockState(lookup, t); list.add(state); } @@ -1621,7 +1732,7 @@ else if (state != air) } this.metadata.setTotalBlocks(totalBlocks); - this.entities.put(name, this.readEntitiesFromVanillaStructure(tag)); + this.entities.put(name, this.readEntitiesFromVanillaStructure(tag, minecraftDataVersion)); return true; } @@ -1629,15 +1740,23 @@ else if (state != air) return false; } - protected List readEntitiesFromVanillaStructure(NbtCompound tag) + protected List readEntitiesFromVanillaStructure(NbtCompound tag, int minecraftDataVersion) { List entities = new ArrayList<>(); NbtList tagList = tag.getList("entities", Constants.NBT.TAG_COMPOUND); final int size = tagList.size(); + if (minecraftDataVersion < LitematicaSchematic.MINECRAFT_DATA_VERSION) + { + Litematica.logger.info("VanillaStructure: executing Vanilla DataFixer for Entities DataVersion {} -> {}", minecraftDataVersion, LitematicaSchematic.MINECRAFT_DATA_VERSION); + } for (int i = 0; i < size; ++i) { NbtCompound entityData = tagList.getCompound(i); + if (minecraftDataVersion < LitematicaSchematic.MINECRAFT_DATA_VERSION) + { + entityData = SchematicConversionMaps.updateEntity(entityData, minecraftDataVersion); + } Vec3d pos = readVec3dFromNbtList(entityData, "pos"); if (pos != null && entityData.contains("nbt", Constants.NBT.TAG_COMPOUND)) @@ -1716,6 +1835,100 @@ private NbtList convertBlockStatePalette_1_12_to_1_13_2(NbtList oldPalette, int return oldPalette; } + private NbtList convertBlockStatePalette_to_1_20_5(NbtList oldPalette, int minecraftDataVersion) + { + if (minecraftDataVersion < Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue()) + { + minecraftDataVersion = Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue(); + } + if (minecraftDataVersion < LitematicaSchematic.MINECRAFT_DATA_VERSION) + { + NbtList newPalette = new NbtList(); + final int count = oldPalette.size(); + Litematica.logger.info("LitematicaSchematic: executing Vanilla DataFixer for Block State Palette DataVersion {} -> {}", minecraftDataVersion, LitematicaSchematic.MINECRAFT_DATA_VERSION); + + for (int i = 0; i < count; ++i) + { + newPalette.add(SchematicConversionMaps.updateBlockStates(oldPalette.getCompound(i), minecraftDataVersion)); + } + + return newPalette; + } + + return oldPalette; + } + + private Map convertTileEntities_to_1_20_5(Map oldTE, int minecraftDataVersion) + { + if (minecraftDataVersion < Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue()) + { + minecraftDataVersion = Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue(); + } + if (minecraftDataVersion < LitematicaSchematic.MINECRAFT_DATA_VERSION) + { + Map newTE = new HashMap<>(); + + Litematica.logger.info("LitematicaSchematic: executing Vanilla DataFixer for Tile Entities DataVersion {} -> {}", minecraftDataVersion, LitematicaSchematic.MINECRAFT_DATA_VERSION); + + for (BlockPos key : oldTE.keySet()) + { + newTE.put(key, SchematicConversionMaps.updateBlockEntity(oldTE.get(key), minecraftDataVersion)); + } + + return newTE; + } + + return oldTE; + } + + private NbtList convertEntities_to_1_20_5(NbtList oldEntitiesList, int minecraftDataVersion) + { + if (minecraftDataVersion < Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue()) + { + minecraftDataVersion = Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue(); + } + if (minecraftDataVersion < LitematicaSchematic.MINECRAFT_DATA_VERSION) + { + NbtList newEntitiesList = new NbtList(); + final int size = oldEntitiesList.size(); + + Litematica.logger.info("LitematicaSchematic: executing Vanilla DataFixer for Entities DataVersion {} -> {}", minecraftDataVersion, LitematicaSchematic.MINECRAFT_DATA_VERSION); + + for (int i = 0; i < size; i++) + { + newEntitiesList.add(SchematicConversionMaps.updateEntity(oldEntitiesList.getCompound(i), minecraftDataVersion)); + } + + return newEntitiesList; + } + + return oldEntitiesList; + } + + private List convertSpongeEntities_to_1_20_5(List oldEntitiesList, int minecraftDataVersion) + { + if (minecraftDataVersion < Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue()) + { + minecraftDataVersion = Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue(); + } + + if (minecraftDataVersion < LitematicaSchematic.MINECRAFT_DATA_VERSION) + { + List newEntitiesList = new ArrayList<>(); + + Litematica.logger.info("SpongeSchematic: executing Vanilla DataFixer for Entities DataVersion {} -> {}", minecraftDataVersion, LitematicaSchematic.MINECRAFT_DATA_VERSION); + + for (EntityInfo oldEntityInfo : oldEntitiesList) + { + newEntitiesList.add(new EntityInfo(oldEntityInfo.posVec, SchematicConversionMaps.updateEntity(oldEntityInfo.nbt, minecraftDataVersion))); + } + + return newEntitiesList; + } + + return oldEntitiesList; + } + private List readEntitiesFromNBT(NbtList tagList) { List entityList = new ArrayList<>(); @@ -1771,7 +1984,7 @@ private Map> readPendingTicksFromNBT(NbtList tagLis // Don't crash on invalid ResourceLocation in 1.13+ try { - target = registry.get(new Identifier(tag.getString(tagName))); + target = registry.get(Identifier.tryParse(tag.getString(tagName))); if (target == null || target == emptyValue) { diff --git a/src/main/java/fi/dy/masa/litematica/schematic/SchematicaSchematic.java b/src/main/java/fi/dy/masa/litematica/schematic/SchematicaSchematic.java index 88fc4ae7ea..6f98d25808 100644 --- a/src/main/java/fi/dy/masa/litematica/schematic/SchematicaSchematic.java +++ b/src/main/java/fi/dy/masa/litematica/schematic/SchematicaSchematic.java @@ -1,14 +1,8 @@ package fi.dy.masa.litematica.schematic; -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; import javax.annotation.Nullable; +import java.io.File; +import java.util.*; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.entity.BlockEntity; @@ -32,9 +26,11 @@ import fi.dy.masa.malilib.util.InfoUtils; import fi.dy.masa.malilib.util.NBTUtils; import fi.dy.masa.litematica.Litematica; +import fi.dy.masa.litematica.config.Configs; import fi.dy.masa.litematica.schematic.LitematicaSchematic.EntityInfo; import fi.dy.masa.litematica.schematic.container.LitematicaBlockStateContainer; import fi.dy.masa.litematica.schematic.conversion.SchematicConversionFixers.IStateFixer; +import fi.dy.masa.litematica.schematic.conversion.SchematicConversionMaps; import fi.dy.masa.litematica.schematic.conversion.SchematicConverter; import fi.dy.masa.litematica.util.EntityUtils; import fi.dy.masa.litematica.util.NbtUtils; @@ -143,7 +139,7 @@ public void placeSchematicToWorld(World world, BlockPos posStart, StructurePlace try { - te.readNbt(teNBT); + te.read(teNBT, world.getRegistryManager()); } catch (Exception e) { @@ -276,7 +272,7 @@ public void placeSchematicDirectlyToChunks(World world, BlockPos posStart, Struc try { - te.readNbt(teNBT); + te.read(teNBT, world.getRegistryManager()); } catch (Exception e) { @@ -373,7 +369,7 @@ private void readBlocksFromWorld(World world, BlockPos posStart, BlockPos size) { try { - NbtCompound nbt = te.createNbtWithId(); + NbtCompound nbt = te.createNbtWithId(world.getRegistryManager()); BlockPos pos = new BlockPos(relX, relY, relZ); NBTUtils.writeBlockPosToTag(pos, nbt); @@ -686,9 +682,11 @@ private void readEntitiesFromNBT(NbtCompound nbt) this.entities.clear(); NbtList tagList = nbt.getList("Entities", Constants.NBT.TAG_COMPOUND); + Litematica.logger.info("SchematicaSchematic: executing Vanilla DataFixer for Entities DataVersion {} -> {}", Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue(), LitematicaSchematic.MINECRAFT_DATA_VERSION); + for (int i = 0; i < tagList.size(); ++i) { - this.entities.add(tagList.getCompound(i)); + this.entities.add(SchematicConversionMaps.updateEntity(tagList.getCompound(i), Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue())); } } @@ -697,6 +695,8 @@ private void readTileEntitiesFromNBT(NbtCompound nbt) this.tiles.clear(); NbtList tagList = nbt.getList("TileEntities", Constants.NBT.TAG_COMPOUND); + Litematica.logger.info("SchematicaSchematic: executing Vanilla DataFixer for Tile Entities DataVersion {} -> {}", Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue(), LitematicaSchematic.MINECRAFT_DATA_VERSION); + for (int i = 0; i < tagList.size(); ++i) { NbtCompound tag = tagList.getCompound(i); @@ -707,8 +707,7 @@ private void readTileEntitiesFromNBT(NbtCompound nbt) pos.getY() >= 0 && pos.getY() < size.getY() && pos.getZ() >= 0 && pos.getZ() < size.getZ()) { - tag = this.converter.fixTileEntityNBT(tag, this.blocks.get(pos.getX(), pos.getY(), pos.getZ())); - this.tiles.put(pos, tag); + this.tiles.put(pos, SchematicConversionMaps.updateBlockEntity(tag, Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue())); } } } diff --git a/src/main/java/fi/dy/masa/litematica/schematic/conversion/SchematicConversionFixers.java b/src/main/java/fi/dy/masa/litematica/schematic/conversion/SchematicConversionFixers.java index ff3897a367..7ba026b662 100644 --- a/src/main/java/fi/dy/masa/litematica/schematic/conversion/SchematicConversionFixers.java +++ b/src/main/java/fi/dy/masa/litematica/schematic/conversion/SchematicConversionFixers.java @@ -258,11 +258,11 @@ public class SchematicConversionFixers public static final IStateFixer FIXER_FLOWER_POT = (reader, state, pos) -> { NbtCompound tag = reader.getBlockEntityData(pos); - if (tag != null) + if (tag != null && tag.contains("Item", 8)) { String itemName = tag.getString("Item"); - if (itemName.length() > 0) + if (itemName.length() > 0 && tag.contains("Data")) { int meta = tag.getInt("Data"); @@ -382,7 +382,7 @@ public class SchematicConversionFixers public static final IStateFixer FIXER_SKULL = (reader, state, pos) -> { NbtCompound tag = reader.getBlockEntityData(pos); - if (tag != null) + if (tag != null && tag.contains("SkullType")) { int id = MathHelper.clamp(tag.getByte("SkullType"), 0, 5); diff --git a/src/main/java/fi/dy/masa/litematica/schematic/conversion/SchematicConversionMaps.java b/src/main/java/fi/dy/masa/litematica/schematic/conversion/SchematicConversionMaps.java index 35901efc0a..73932896b4 100644 --- a/src/main/java/fi/dy/masa/litematica/schematic/conversion/SchematicConversionMaps.java +++ b/src/main/java/fi/dy/masa/litematica/schematic/conversion/SchematicConversionMaps.java @@ -1,27 +1,26 @@ package fi.dy.masa.litematica.schematic.conversion; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.HashMap; -import javax.annotation.Nullable; -import com.mojang.datafixers.DataFixUtils; -import com.mojang.serialization.Dynamic; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import com.mojang.datafixers.DataFixUtils; +import com.mojang.serialization.Dynamic; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.PillarBlock; import net.minecraft.client.MinecraftClient; import net.minecraft.datafixer.TypeReferences; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtHelper; -import net.minecraft.nbt.NbtOps; -import net.minecraft.nbt.NbtString; -import net.minecraft.nbt.StringNbtReader; +import net.minecraft.nbt.*; import net.minecraft.registry.Registries; import net.minecraft.registry.RegistryEntryLookup; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; +import fi.dy.masa.malilib.util.NBTUtils; import fi.dy.masa.litematica.Litematica; +import fi.dy.masa.litematica.config.Configs; import fi.dy.masa.litematica.schematic.LitematicaSchematic; public class SchematicConversionMaps @@ -190,10 +189,10 @@ private static void addIdMetaToBlockState(int idMeta, NbtCompound newStateTag, S NbtCompound oldStateTag = getStateTagFromString(oldStateStrings[0]); String oldName = oldStateTag.getString("Name"); - // Don't run the vanilla block rename for overidden names + // Don't run the vanilla block rename for overridden names if (overriddenName == null) { - newName = updateBlockName(newName); + newName = updateBlockName(newName, Configs.Generic.DATAFIXER_DEFAULT_SCHEMA.getIntegerValue()); newStateTag.putString("Name", newName); } @@ -278,12 +277,65 @@ public static NbtCompound getStateTagFromString(String str) } } - public static String updateBlockName(String oldName) + public static String updateBlockName(String oldName, int oldVersion) { NbtString tagStr = NbtString.of(oldName); - return MinecraftClient.getInstance().getDataFixer().update(TypeReferences.BLOCK_NAME, new Dynamic<>(NbtOps.INSTANCE, tagStr), - 1139, LitematicaSchematic.MINECRAFT_DATA_VERSION).getValue().asString(); + try + { + return MinecraftClient.getInstance().getDataFixer().update(TypeReferences.BLOCK_NAME, new Dynamic<>(NbtOps.INSTANCE, tagStr), oldVersion, LitematicaSchematic.MINECRAFT_DATA_VERSION).getValue().asString(); + } + catch (Exception e) + { + Litematica.logger.warn("updateBlockName: failed to update Block Name [{}], preserving original state (data may become lost)", oldName); + return oldName; + } + } + + /** + * These are the Vanilla Data Fixer's for the 1.20.x -> 1.20.5 changes + */ + public static NbtCompound updateBlockStates(NbtCompound oldBlockState, int oldVersion) + { + try + { + return (NbtCompound) MinecraftClient.getInstance().getDataFixer().update(TypeReferences.BLOCK_STATE, new Dynamic<>(NbtOps.INSTANCE, oldBlockState), oldVersion, LitematicaSchematic.MINECRAFT_DATA_VERSION).getValue(); + } + catch (Exception e) + { + Litematica.logger.warn("updateBlockStates: failed to update Block State [{}], preserving original state (data may become lost)", + oldBlockState.contains("Name") ? oldBlockState.getString("Name") : "?"); + return oldBlockState; + } + } + + public static NbtCompound updateBlockEntity(NbtCompound oldBlockEntity, int oldVersion) + { + try + { + return (NbtCompound) MinecraftClient.getInstance().getDataFixer().update(TypeReferences.BLOCK_ENTITY, new Dynamic<>(NbtOps.INSTANCE, oldBlockEntity), oldVersion, LitematicaSchematic.MINECRAFT_DATA_VERSION).getValue(); + } + catch (Exception e) + { + BlockPos pos = NBTUtils.readBlockPos(oldBlockEntity); + Litematica.logger.warn("updateBlockEntity: failed to update Block Entity [{}] at [{}], preserving original state (data may become lost)", + oldBlockEntity.contains("id") ? oldBlockEntity.getString("id") : "?", pos != null ? pos.toShortString() : "?"); + return oldBlockEntity; + } + } + + public static NbtCompound updateEntity(NbtCompound oldEntity, int oldVersion) + { + try + { + return (NbtCompound) MinecraftClient.getInstance().getDataFixer().update(TypeReferences.ENTITY, new Dynamic<>(NbtOps.INSTANCE, oldEntity), oldVersion, LitematicaSchematic.MINECRAFT_DATA_VERSION).getValue(); + } + catch (Exception e) + { + Litematica.logger.warn("updateEntity: failed to update Entity [{}], preserving original state (data may become lost)", + oldEntity.contains("id") ? oldEntity.getString("id") : "?"); + return oldEntity; + } } private static class ConversionData diff --git a/src/main/java/fi/dy/masa/litematica/schematic/projects/SchematicProject.java b/src/main/java/fi/dy/masa/litematica/schematic/projects/SchematicProject.java index 4e23092239..a2312a82df 100644 --- a/src/main/java/fi/dy/masa/litematica/schematic/projects/SchematicProject.java +++ b/src/main/java/fi/dy/masa/litematica/schematic/projects/SchematicProject.java @@ -1,15 +1,15 @@ package fi.dy.masa.litematica.schematic.projects; +import javax.annotation.Nullable; import java.io.File; import java.util.ArrayList; import java.util.List; -import javax.annotation.Nullable; -import org.apache.commons.io.FileUtils; import com.google.common.collect.ImmutableList; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import org.apache.commons.io.FileUtils; import net.minecraft.client.MinecraftClient; import net.minecraft.util.math.BlockPos; import fi.dy.masa.litematica.data.DataManager; diff --git a/src/main/java/fi/dy/masa/litematica/util/EntityUtils.java b/src/main/java/fi/dy/masa/litematica/util/EntityUtils.java index 6397fcfe88..9adc300802 100644 --- a/src/main/java/fi/dy/masa/litematica/util/EntityUtils.java +++ b/src/main/java/fi/dy/masa/litematica/util/EntityUtils.java @@ -1,10 +1,10 @@ package fi.dy.masa.litematica.util; +import javax.annotation.Nullable; import java.util.List; import java.util.Optional; import java.util.UUID; import java.util.function.Predicate; -import javax.annotation.Nullable; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; @@ -20,11 +20,12 @@ import net.minecraft.util.math.Direction; import net.minecraft.world.World; +import fi.dy.masa.malilib.util.Constants; +import fi.dy.masa.malilib.util.InventoryUtils; import fi.dy.masa.litematica.config.Configs; import fi.dy.masa.litematica.data.DataManager; import fi.dy.masa.litematica.schematic.placement.SchematicPlacement; import fi.dy.masa.litematica.schematic.placement.SubRegionPlacement; -import fi.dy.masa.malilib.util.Constants; public class EntityUtils { @@ -43,8 +44,6 @@ public static boolean hasToolItem(LivingEntity entity) public static boolean hasToolItemInHand(LivingEntity entity, Hand hand) { - // If the configured tool item has NBT data, then the NBT is compared, otherwise it's ignored - ItemStack toolItem = DataManager.getToolItem(); if (toolItem.isEmpty()) @@ -54,12 +53,7 @@ public static boolean hasToolItemInHand(LivingEntity entity, Hand hand) ItemStack stackHand = entity.getStackInHand(hand); - if (ItemStack.areItemsEqual(toolItem, stackHand)) - { - return toolItem.hasNbt() == false || ItemUtils.areTagsEqualIgnoreDamage(toolItem, stackHand); - } - - return false; + return InventoryUtils.areStacksEqualIgnoreNbt(toolItem, stackHand); } /** @@ -74,12 +68,12 @@ public static Hand getUsedHandForItem(PlayerEntity player, ItemStack stack) { Hand hand = null; - if (ItemStack.areItemsEqual(player.getMainHandStack(), stack)) + if (InventoryUtils.areStacksEqualIgnoreNbt(player.getMainHandStack(), stack)) { hand = Hand.MAIN_HAND; } else if (player.getMainHandStack().isEmpty() && - ItemStack.areItemsEqual(player.getOffHandStack(), stack)) + InventoryUtils.areStacksEqualIgnoreNbt(player.getOffHandStack(), stack)) { hand = Hand.OFF_HAND; } @@ -89,7 +83,7 @@ else if (player.getMainHandStack().isEmpty() && public static boolean areStacksEqualIgnoreDurability(ItemStack stack1, ItemStack stack2) { - return ItemStack.areItemsEqual(stack1, stack2) && ItemStack.canCombine(stack1, stack2); + return InventoryUtils.areStacksEqualIgnoreDurability(stack1, stack2); } public static Direction getHorizontalLookingDirection(Entity entity) diff --git a/src/main/java/fi/dy/masa/litematica/util/InventoryUtils.java b/src/main/java/fi/dy/masa/litematica/util/InventoryUtils.java index bc6ddaec02..5339fd1bd5 100644 --- a/src/main/java/fi/dy/masa/litematica/util/InventoryUtils.java +++ b/src/main/java/fi/dy/masa/litematica/util/InventoryUtils.java @@ -120,7 +120,8 @@ public static void schematicWorldPickBlock(ItemStack stack, BlockPos pos, // Otherwise it would try to write whatever that TE is into the picked ItemStack. if (GuiBase.isCtrlDown() && te != null && mc.world.isAir(pos)) { - ItemUtils.storeTEInStack(stack, te); + te.setStackNbt(stack, schematicWorld.getRegistryManager()); + //stack.set(DataComponentTypes.LORE, new LoreComponent(ImmutableList.of(Text.of("(+NBT)")))); } setPickedItemToHand(stack, mc); @@ -168,7 +169,7 @@ private static boolean canPickToSlot(PlayerInventory inventory, int slotNum) } return (Configs.Generic.PICK_BLOCK_AVOID_DAMAGEABLE.getBooleanValue() == false || - stack.getItem().isDamageable() == false) && + stack.isDamageable() == false) && (Configs.Generic.PICK_BLOCK_AVOID_TOOLS.getBooleanValue() == false || (stack.getItem() instanceof ToolItem) == false); } @@ -234,11 +235,23 @@ public static boolean doesShulkerBoxContainItem(ItemStack stack, ItemStack refer { DefaultedList items = fi.dy.masa.malilib.util.InventoryUtils.getStoredItems(stack); + return doesListContainItem(items, referenceItem); + } + + public static boolean doesBundleContainItem(ItemStack stack, ItemStack referenceItem) + { + DefaultedList items = fi.dy.masa.malilib.util.InventoryUtils.getBundleItems(stack); + + return doesListContainItem(items, referenceItem); + } + + private static boolean doesListContainItem(DefaultedList items, ItemStack referenceItem) + { if (items.size() > 0) { for (ItemStack item : items) { - if (fi.dy.masa.malilib.util.InventoryUtils.areStacksEqual(item, referenceItem)) + if (fi.dy.masa.malilib.util.InventoryUtils.areStacksEqualIgnoreNbt(item, referenceItem)) { return true; } diff --git a/src/main/java/fi/dy/masa/litematica/util/ItemUtils.java b/src/main/java/fi/dy/masa/litematica/util/ItemUtils.java index fb336d9161..5fdbaf6600 100644 --- a/src/main/java/fi/dy/masa/litematica/util/ItemUtils.java +++ b/src/main/java/fi/dy/masa/litematica/util/ItemUtils.java @@ -1,20 +1,12 @@ package fi.dy.masa.litematica.util; -import java.util.HashSet; import java.util.IdentityHashMap; -import java.util.Set; -import net.minecraft.block.AbstractSkullBlock; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.SlabBlock; -import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.enums.SlabType; -import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtList; -import net.minecraft.nbt.NbtString; import net.minecraft.registry.Registries; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; @@ -26,30 +18,19 @@ public class ItemUtils public static boolean areTagsEqualIgnoreDamage(ItemStack stackReference, ItemStack stackToCheck) { - NbtCompound tagReference = stackReference.getNbt(); - NbtCompound tagToCheck = stackToCheck.getNbt(); + ItemStack ref = stackReference.copy(); + ItemStack check = stackToCheck.copy(); - if (tagReference != null && tagToCheck != null) + if (ref.isDamageable() && ref.isDamaged()) { - Set keysReference = new HashSet<>(tagReference.getKeys()); - - for (String key : keysReference) - { - if (key.equals("Damage")) - { - continue; - } - - if (tagReference.get(key).equals(tagToCheck.get(key)) == false) - { - return false; - } - } - - return true; + ref.setDamage(0); + } + if (check.isDamageable() && check.isDamaged()) + { + check.setDamage(0); } - return (tagReference == null) && (tagToCheck == null); + return ItemStack.areItemsAndComponentsEqual(ref, check); } public static ItemStack getItemForState(BlockState state) @@ -126,35 +107,6 @@ private static void overrideStackSize(BlockState state, ItemStack stack) } } - public static ItemStack storeTEInStack(ItemStack stack, BlockEntity te) - { - NbtCompound nbt = te.createNbtWithId(); - - if (nbt.contains("Owner") && stack.getItem() instanceof BlockItem && - ((BlockItem) stack.getItem()).getBlock() instanceof AbstractSkullBlock) - { - NbtCompound tagOwner = nbt.getCompound("Owner"); - NbtCompound tagSkull = new NbtCompound(); - - tagSkull.put("SkullOwner", tagOwner); - stack.setNbt(tagSkull); - - return stack; - } - else - { - NbtCompound tagLore = new NbtCompound(); - NbtList tagList = new NbtList(); - - tagList.add(NbtString.of("(+NBT)")); - tagLore.put("Lore", tagList); - stack.setSubNbt("display", tagLore); - stack.setSubNbt("BlockEntityTag", nbt); - - return stack; - } - } - public static String getStackString(ItemStack stack) { if (stack.isEmpty() == false) @@ -163,7 +115,7 @@ public static String getStackString(ItemStack stack) return String.format("[%s - display: %s - NBT: %s] (%s)", rl != null ? rl.toString() : "null", stack.getName().getString(), - stack.getNbt() != null ? stack.getNbt().toString() : "", stack); + stack.getComponents() != null ? stack.getComponents().toString() : "", stack); } return ""; diff --git a/src/main/java/fi/dy/masa/litematica/util/NbtUtils.java b/src/main/java/fi/dy/masa/litematica/util/NbtUtils.java index df7f36f113..d4ed3dad39 100644 --- a/src/main/java/fi/dy/masa/litematica/util/NbtUtils.java +++ b/src/main/java/fi/dy/masa/litematica/util/NbtUtils.java @@ -7,13 +7,13 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.NbtList; -import net.minecraft.nbt.NbtTagSizeTracker; +import net.minecraft.nbt.NbtSizeTracker; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; -import net.minecraft.util.math.Vec3i; import fi.dy.masa.litematica.Litematica; import fi.dy.masa.malilib.util.Constants; +import net.minecraft.util.math.Vec3i; public class NbtUtils { @@ -97,7 +97,7 @@ public static NbtCompound readNbtFromFile(File file) { try { - nbt = NbtIo.readCompressed(is, NbtTagSizeTracker.ofUnlimitedBytes()); + nbt = NbtIo.readCompressed(is, NbtSizeTracker.ofUnlimitedBytes()); } catch (Exception e) { diff --git a/src/main/java/fi/dy/masa/litematica/util/SchematicPlacingUtils.java b/src/main/java/fi/dy/masa/litematica/util/SchematicPlacingUtils.java index 63cdd265e5..173fbe9e88 100644 --- a/src/main/java/fi/dy/masa/litematica/util/SchematicPlacingUtils.java +++ b/src/main/java/fi/dy/masa/litematica/util/SchematicPlacingUtils.java @@ -248,7 +248,7 @@ public static boolean placeBlocksWithinChunk(World world, ChunkPos chunkPos, Str try { - te.readNbt(teNBT); + te.read(teNBT, world.getRegistryManager()); if (ignoreInventories && te instanceof Inventory) { diff --git a/src/main/java/fi/dy/masa/litematica/util/WorldUtils.java b/src/main/java/fi/dy/masa/litematica/util/WorldUtils.java index 726f40c9f1..b59007439d 100644 --- a/src/main/java/fi/dy/masa/litematica/util/WorldUtils.java +++ b/src/main/java/fi/dy/masa/litematica/util/WorldUtils.java @@ -965,7 +965,7 @@ public static boolean isSliceEmpty(World world, Direction.Axis axis, BlockPos po Chunk chunk = world.getChunk(cx, z >> 4); int xMin = Math.max(x1, cx << 4 ); int xMax = Math.min(x2, (cx << 4) + 15); - int yMax = Math.min(y2, chunk.getHighestNonEmptySectionYOffset() + 15); + int yMax = Math.min(y2, fi.dy.masa.malilib.util.WorldUtils.getHighestSectionYOffset(chunk) + 15); for (int x = xMin; x <= xMax; ++x) { @@ -1000,7 +1000,7 @@ public static boolean isSliceEmpty(World world, Direction.Axis axis, BlockPos po { Chunk chunk = world.getChunk(cx, cz); - if (y > chunk.getHighestNonEmptySectionYOffset() + 15) + if (y > fi.dy.masa.malilib.util.WorldUtils.getHighestSectionYOffset(chunk) + 15) { continue; } @@ -1041,7 +1041,7 @@ public static boolean isSliceEmpty(World world, Direction.Axis axis, BlockPos po Chunk chunk = world.getChunk(x >> 4, cz); int zMin = Math.max(z1, cz << 4 ); int zMax = Math.min(z2, (cz << 4) + 15); - int yMax = Math.min(y2, chunk.getHighestNonEmptySectionYOffset() + 15); + int yMax = Math.min(y2, fi.dy.masa.malilib.util.WorldUtils.getHighestSectionYOffset(chunk) + 15); for (int z = zMin; z <= zMax; ++z) { diff --git a/src/main/java/fi/dy/masa/litematica/world/SchematicWorldHandler.java b/src/main/java/fi/dy/masa/litematica/world/SchematicWorldHandler.java index 0db5ea2cb2..caaac25e19 100644 --- a/src/main/java/fi/dy/masa/litematica/world/SchematicWorldHandler.java +++ b/src/main/java/fi/dy/masa/litematica/world/SchematicWorldHandler.java @@ -79,7 +79,7 @@ public static WorldSchematic createSchematicWorld(@Nullable WorldRendererSchemat ClientWorld.Properties levelInfo = new ClientWorld.Properties(Difficulty.PEACEFUL, false, true); - return new WorldSchematic(levelInfo, entry, MinecraftClient.getInstance()::getProfiler, worldRenderer); + return new WorldSchematic(levelInfo, world.getRegistryManager(), entry, MinecraftClient.getInstance()::getProfiler, worldRenderer); } public void recreateSchematicWorld(boolean remove) diff --git a/src/main/java/fi/dy/masa/litematica/world/WorldSchematic.java b/src/main/java/fi/dy/masa/litematica/world/WorldSchematic.java index fb33d929a4..4c8838027d 100644 --- a/src/main/java/fi/dy/masa/litematica/world/WorldSchematic.java +++ b/src/main/java/fi/dy/masa/litematica/world/WorldSchematic.java @@ -1,5 +1,6 @@ package fi.dy.masa.litematica.world; +import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; @@ -10,11 +11,13 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.client.MinecraftClient; +import net.minecraft.component.type.MapIdComponent; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.fluid.Fluid; import net.minecraft.item.map.MapState; import net.minecraft.particle.ParticleEffect; +import net.minecraft.recipe.BrewingRecipeRegistry; import net.minecraft.recipe.RecipeManager; import net.minecraft.registry.DynamicRegistryManager; import net.minecraft.registry.RegistryKey; @@ -26,11 +29,7 @@ import net.minecraft.sound.SoundEvent; import net.minecraft.util.Identifier; import net.minecraft.util.TypeFilter; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Box; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.*; import net.minecraft.util.profiler.Profiler; import net.minecraft.world.LightType; import net.minecraft.world.MutableWorldProperties; @@ -63,16 +62,28 @@ public class WorldSchematic extends World private final TickManager tickManager; public WorldSchematic(MutableWorldProperties properties, + @Nonnull DynamicRegistryManager registryManager, RegistryEntry dimension, Supplier supplier, @Nullable WorldRendererSchematic worldRenderer) { - super(properties, REGISTRY_KEY, MinecraftClient.getInstance().getNetworkHandler().getRegistryManager(), dimension, supplier, true, false, 0L, 0); + super(properties, REGISTRY_KEY, registryManager.equals(DynamicRegistryManager.EMPTY) == false ? registryManager : MinecraftClient.getInstance().world.getRegistryManager(), dimension, supplier, true, false, 0L, 0); this.mc = MinecraftClient.getInstance(); + if (this.mc == null || this.mc.world == null) + { + throw new RuntimeException("WorldSchematic invoked when MinecraftClient.getInstance() or mc.world is null"); + } this.worldRenderer = worldRenderer; this.chunkManagerSchematic = new ChunkManagerSchematic(this); - this.biome = this.mc.world.getRegistryManager().get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS); + if (registryManager.equals(DynamicRegistryManager.EMPTY) == false) + { + this.biome = registryManager.get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS); + } + else + { + this.biome = this.mc.world.getRegistryManager().get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS); + } this.tickManager = new TickManager(); } @@ -93,6 +104,16 @@ public TickManager getTickManager() return this.tickManager; } + @Nullable + @Override + public MapState getMapState(MapIdComponent id) { return null; } + + @Override + public void putMapState(MapIdComponent id, MapState state) { } + + @Override + public MapIdComponent getNextMapId() { return null; } + @Override public QueryableTickScheduler getBlockTickScheduler() { @@ -192,25 +213,6 @@ public long getTime() return this.mc.world != null ? this.mc.world.getTime() : 0; } - @Override - @Nullable - public MapState getMapState(String id) - { - return null; - } - - @Override - public void putMapState(String name, MapState mapState) - { - // NO-OP - } - - @Override - public int getNextMapId() - { - return 0; - } - @Override public Scoreboard getScoreboard() { @@ -415,10 +417,11 @@ public void syncGlobalEvent(int eventId, BlockPos pos, int data) @Override public void syncWorldEvent(@Nullable PlayerEntity entity, int id, BlockPos pos, int data) { + // NO-OP } @Override - public void emitGameEvent(GameEvent event, Vec3d pos, @Nullable GameEvent.Emitter emitter) + public void emitGameEvent(RegistryEntry event, Vec3d emitterPos, GameEvent.Emitter emitter) { // NO-OP } @@ -435,12 +438,6 @@ public void playSoundFromEntity(@javax.annotation.Nullable PlayerEntity except, // NO-OP } - @Override - public void emitGameEvent(@Nullable Entity entity, GameEvent event, BlockPos pos) - { - // NO-OP - } - @Override public void addParticle(ParticleEffect particleParameters_1, double double_1, double double_2, double double_3, double double_4, double double_5, double double_6) { @@ -498,13 +495,40 @@ public void playSoundFromEntity(@Nullable PlayerEntity player, Entity entity, So @Override public DynamicRegistryManager getRegistryManager() { - return this.mc.world.getRegistryManager(); + if (this.mc != null && this.mc.world != null) + { + return this.mc.world.getRegistryManager(); + } + else + { + return DynamicRegistryManager.EMPTY; + } + } + + @Override + public BrewingRecipeRegistry getBrewingRecipeRegistry() + { + if (this.mc != null && this.mc.world != null) + { + return this.mc.world.getBrewingRecipeRegistry(); + } + else + { + return BrewingRecipeRegistry.EMPTY; + } } @Override public FeatureSet getEnabledFeatures() { - return this.mc.world.getEnabledFeatures(); + if (this.mc != null && this.mc.world != null) + { + return this.mc.world.getEnabledFeatures(); + } + else + { + return FeatureSet.empty(); + } } @Override @@ -512,4 +536,22 @@ public String asString() { return "Chunks[SCH] W: " + this.getChunkManager().getDebugString() + " E: " + this.getRegularEntityCount(); } + + @Override + public void emitGameEvent(@Nullable Entity entity, RegistryEntry event, Vec3d pos) + { + // NO-OP + } + + @Override + public void emitGameEvent(@Nullable Entity entity, RegistryEntry event, BlockPos pos) + { + // NO-OP + } + + @Override + public void emitGameEvent(RegistryKey event, BlockPos pos, @Nullable GameEvent.Emitter emitter) + { + // NO-OP + } } diff --git a/src/main/resources/assets/litematica/lang/en_us.json b/src/main/resources/assets/litematica/lang/en_us.json index 794de73b1f..c1e104fe1a 100644 --- a/src/main/resources/assets/litematica/lang/en_us.json +++ b/src/main/resources/assets/litematica/lang/en_us.json @@ -337,7 +337,7 @@ "litematica.gui.title.area_selection_manager": "Area Selection Manager", "litematica.gui.title.configure_schematic_placement": "Configure Schematic placement", "litematica.gui.title.configure_schematic_sub_region": "Configure Placement Sub-Region", - "litematica.gui.title.configs": "Litematica Configs", + "litematica.gui.title.configs": "Litematica Configs - %s", "litematica.gui.title.confirm_file_deletion": "Confirm file deletion", "litematica.gui.title.copy_area_selection": "Copy Area Selection '%s'", "litematica.gui.title.create_area_selection": "Create a new Area Selection", diff --git a/src/main/resources/assets/litematica/lang/fr_fr.json b/src/main/resources/assets/litematica/lang/fr_fr.json index fe07ee9013..16afa4aa17 100644 --- a/src/main/resources/assets/litematica/lang/fr_fr.json +++ b/src/main/resources/assets/litematica/lang/fr_fr.json @@ -1,511 +1,511 @@ { - "litematica.error.area_selection.copy_failed": "Échec de la copie de la sélection", - "litematica.error.area_selection.create_failed": "Échec de la création d'une nouvelle sélection avec le nom '%s', le fichier existe déjà", - "litematica.error.area_selection.failed_to_load": "Échec du chargement de la sélection de zone", - "litematica.error.area_selection.grow.no_sub_region_selected": "Aucune sous-région sélectionnée !", - "litematica.error.area_selection.no_placement_selected": "Aucun placement de schéma sélectionné !", - "litematica.error.area_selection.rename.already_exists": "Erreur : Une zone existe déjà avec le nom de fichier '%s'", - "litematica.error.area_selection.rename.invalid_safe_file_name": "Nom de fichier sécurisé généré invalide '%s'", - - "litematica.error.duplicate_schematic_placement": "Erreur : Tentative d'ajout d'un placement qui existe déjà", - "litematica.error.generic.creative_mode_only": "Cette action est uniquement disponible en mode Créatif", - "litematica.error.generic.failed_to_delete_file": "Échec de la suppression du fichier '%s'", - "litematica.error.generic.failed_to_sort_list_of_ignored_states": "Échec du tri de la liste des états ignorés", - "litematica.error.generic.schematic_world_not_loaded": "Le monde schématique n'a pas été chargé", - - "litematica.error.area_editor.create_sub_region.exists": "Une sous-région portant le nom '%s' existe déjà", - "litematica.error.area_editor.no_selection": "Aucune sélection de zone active", - "litematica.error.area_editor.open_gui.no_selection": "Actuellement en mode de sélection : Normal, mais aucune zone n'est actuellement sélectionnée", - "litematica.error.area_editor.rename_sub_region.exists": "Échec du renommage de la sous-région:\nUne sous-région existe déjà avec le nom '%s'", - "litematica.error.area_editor.switch_mode.no_selection": "Impossible de passer en mode de sélection : Normal, car aucune zone n'est actuellement sélectionnée.\nSélectionnez une zone ou créez une nouvelle sélection dans le navigateur de sélection de zone", - - "litematica.error.schematic_conversion.schematic_to_litematica.failed_to_create_schematic": "Échec de la création du schéma Litematica", - "litematica.error.schematic_conversion.schematic_to_litematica.failed_to_read_schematic": "Échec du chargement du schéma", - "litematica.error.schematic_conversion.structure_to_litematica_failed": "Échec de la conversion de la structure en schéma Litematica", - - "litematica.error.schematic.create.no_selections": "Aucune région de sélection valide !", - - "litematica.error.schematic_load.cant_read_file": "Impossible de lire le fichier schématique '%s' (n'existe pas ou problème de permission)", - "litematica.error.schematic_load.no_schematic_selected": "Aucun fichier schématique sélectionné !", - "litematica.error.schematic_load.no_schematic_version_information": "Le schéma n'a pas d'informations de version et ne peut pas être chargé en toute sécurité !", - "litematica.error.schematic_load.unsupported_schematic_version": "Version schématique non prise en charge ou future '%d'", - "litematica.error.schematic_load.unsupported_type": "Type de fichier inconnu ou non pris en charge pour '%s'", - - "litematica.error.schematic_manager.schematic_export.unsupported_type": "Seuls les schémas Litematica peuvent être exportés dans d'autres formats !", - "litematica.error.schematic_manager.schematic_import.unsupported_type": "Le type de schéma sélectionné n'est pas pris en charge pour l'importation !", - - "litematica.error.schematic_placements.remove_fail_locked": "Le placement est verrouillé !\n- Maintenez la touche Maj enfoncée pour le supprimer de force", - - "litematica.error.schematic_save.directory_doesnt_exist": "Aucun répertoire tel que '%s'", - "litematica.error.schematic_save.file_already_exists": "Le fichier '%s' existe déjà", - "litematica.error.schematic_save.invalid_directory": "Répertoire invalide '%s'", - "litematica.error.schematic_save.invalid_schematic_name": "Nom de schéma invalide '%s'", - "litematica.error.schematic_save.schematic_creation_failed": "Échec de la création du schéma !", - - "litematica.error.schematic_read_from_file_failed.cant_read": "Échec de la lecture du schéma depuis le fichier '%s'", - "litematica.error.schematic_read_from_file_failed.exception": "Exception lors de la tentative de lecture du schéma depuis le fichier '%s'", - "litematica.error.schematic_read_from_file_failed.no_file": "Échec de la lecture du schéma depuis le fichier : aucun fichier disponible (schéma en mémoire ?)", - - "litematica.error.schematic_projects.empty_selection": "Sélection de zone vide (0 sous-régions)", - "litematica.error.schematic_projects.failed_to_load_project": "Échec du chargement du projet", - "litematica.error.schematic_projects.failed_to_load_schematic": "Échec du chargement du schéma pour la version actuelle", - "litematica.error.schematic_projects.failed_to_rename_project_file_exception": "Échec du renommage du fichier de projet en '%s' (exception)", - "litematica.error.schematic_projects.failed_to_rename_project_file_exists": "Impossible de renommer le projet en '%s', le fichier existe déjà", - "litematica.error.schematic_projects.invalid_project_directory": "Répertoire de projet invalide ou inexistant", - "litematica.error.schematic_projects.no_project_open": "Aucun projet ouvert", - "litematica.error.schematic_projects.in_projects_mode_but_no_project_open": "Actuellement en mode Schematic VCS, mais aucun projet n'est actuellement ouvert", - "litematica.error.schematic_projects.null_player": "Le joueur était nul", - "litematica.error.schematic_projects.project_already_exists": "Le projet '%s' existe déjà", - "litematica.error.schematic_projects.save_already_in_progress": "Sauvegarde déjà en cours", - - "litematica.error.schematic_write_to_file_failed.directory_creation_failed": "Échec de la création du répertoire du schéma '%s'", - "litematica.error.schematic_write_to_file_failed.exception": "Échec de l'écriture du schéma dans le fichier '%s' (exception)", - "litematica.error.schematic_write_to_file_failed.exists": "Échec de l'écriture du schéma dans le fichier '%s', le fichier existe déjà", - "litematica.error.structure_write_to_file_failed.exception": "Échec de l'écriture de la structure dans le fichier '%s' (exception)", - "litematica.error.structure_write_to_file_failed.exists": "Échec de l'écriture de la structure dans le fichier '%s', le fichier existe déjà", - - "litematica.hotkeys.category.generic_hotkeys": "Raccourcis génériques", - - "litematica.info.schematic_load.schematic_loaded": "Schéma '%s' chargé avec succès en mémoire", - "litematica.info.schematic_manager.preview.right_click_to_cancel": "- Clic droit sur le bouton pour annuler une opération d'aperçu en attente\n- Ctrl + Alt + Maj + clic pour définir la vignette à partir d'une image PNG existante\n appelée 'thumb.png' dans le même répertoire que le fichier schématique.", - "litematica.info.schematic_manager.preview.set_preview_by_taking_a_screenshot": "Utilisez la touche normale de capture d'écran pour définir l'aperçu.\nOu faites un clic droit sur le bouton Définir l'aperçu pour annuler la définition de l'aperçu.", - "litematica.info.schematic_manager.preview.success": "Image d'aperçu définie avec succès", - - "litematica.gui.button.area_editor.analyze_area": "Analyser zone", - "litematica.gui.button.area_editor.change_corner_mode": "Mode Coin : %s", - "litematica.gui.button.area_editor.change_selection_mode": "Mode de sélection : %s", - "litematica.gui.button.area_editor.create_schematic": "Enregistrer le schéma", - "litematica.gui.button.area_editor.create_sub_region": "Nouvelle sous-région", - "litematica.gui.button.area_editor.origin_enabled": "Origine manuelle : %s", - "litematica.gui.button.area_editor.set_box_name": "Définir", - "litematica.gui.button.area_editor.set_selection_name": "Définir", - - "litematica.gui.button.area_selection_mode": "Mode de sélection de zone : %s", - "litematica.gui.button.area_selections.create_directory": "Créer un répertoire", - "litematica.gui.button.area_selections.create_new_selection": "Nouvelle sélection", - "litematica.gui.button.area_selections.create_selection_from_placement": "À partir du Placement", - "litematica.gui.button.area_selections.unselect": "Désélectionner", - - "litematica.gui.button.change_menu.area_editor": "Éditeur de zone", - "litematica.gui.button.change_menu.configuration_menu": "Menu de configuration", - "litematica.gui.button.change_menu.load_schematics_to_memory": "Charger les schémas", - "litematica.gui.button.change_menu.schematic_manager": "Gestionnaire de schémas", - "litematica.gui.button.change_menu.schematic_projects_manager": "Schematic VCS", - "litematica.gui.button.change_menu.show_area_selections": "Navigateur de sélection de zone", - "litematica.gui.button.change_menu.show_loaded_schematics": "Schémas chargés", - "litematica.gui.button.change_menu.show_schematic_placements": "Placements de schéma", - "litematica.gui.button.change_menu.task_manager": "Gestionnaire des tâches", - "litematica.gui.button.change_menu.to_main_menu": "Menu Litematica", - - "litematica.gui.button.config_gui.colors": "Couleurs", - "litematica.gui.button.config_gui.generic": "Générique", - "litematica.gui.button.config_gui.hotkeys": "Raccourcis", - "litematica.gui.button.config_gui.info_overlays": "Surimpressions d'informations", - "litematica.gui.button.config_gui.render_layers": "Couches de rendu", - "litematica.gui.button.config_gui.visuals": "Visuels", - - "litematica.gui.button.hover.area_editor.shift_for_in_memory": "Maintenez la touche Shift pour créer un schéma uniquement en mémoire", - "litematica.gui.button.hover.area_selections.unselect": "Désélectionne la sélection de zone actuelle", - "litematica.gui.button.hover.material_list.clear_cache": "Efface le cache des matériaux\nNormalement, cela ne devrait pas être nécessaire\nCela peut être utilisé au lieu de supprimer le fichier 'material_cache.nbt'\nsi le cache contient des données incorrectes, comme des objets\nstockés pour des blocs qui ne devraient pas en avoir, comme les têtes de piston", - "litematica.gui.button.hover.material_list.write_hold_shift_for_csv": "Maintenez la touche Shift enfoncée pour écrire dans un fichier CSV,\nau lieu du fichier texte ASCII standard", - "litematica.gui.button.hover.material_list_shift_to_select_sub_regions": "Maintenez la touche Shift enfoncée pour sélectionner les sous-régions utilisées pour la liste des matériaux", - "litematica.gui.button.hover.plus_minus_tip": "Clic gauche pour augmenter\nClic droit pour diminuer\nMaintenez Maj et/ou Alt pour augmenter la taille du pas", - "litematica.gui.button.hover.plus_minus_tip_ctrl_alt_shift": "Clic gauche pour augmenter\nClic droit pour diminuer\nMaintenez Maj/Alt/Ctrl pour augmenter la taille du pas (multiplicatif)", - "litematica.gui.button.hover.schematic_list.reload_schematic": "Recharge le schéma depuis le fichier.\nCela peut être utile en cas d'erreur\nen mode Édition de schéma.", - "litematica.gui.button.hover.schematic_projects.area_browser_disabled_currently_in_projects_mode": "Un projet Schematic VCS est actuellement ouvert.\nLe mode Schematic VCS remplace la fonctionnalité normale de sélection de zone", - "litematica.gui.button.hover.schematic_projects.delete_area": "§6Supprimer la dernière zone placée ou enregistrée§r", - "litematica.gui.button.hover.schematic_projects.menu_warning": "(Cela s'appelait Schematic Projects auparavant.)\nEn général, vous §6ne devriez pas§r utiliser cette fonctionnalité,\nà moins de savoir vraiment comment elle fonctionne et ce qu'elle fait.\nElle modifie quelque peu le fonctionnement des sélections de zone, des placements et du collage,\nnotamment qu'il y a aussi une opération de suppression de zone lors du collage.\n\nEssentiellement, cette fonctionnalité est destinée à un travail de conception §6itératif, sur place§r,\net elle vous permet de créer plus facilement plusieurs versions/snapshots\nde la même construction, ainsi que de passer entre les versions en supprimant ce qui est\ndans le monde d'abord, puis en collant la version suivante à sa place.", - "litematica.gui.button.hover.schematic_projects.move_origin_to_player": "Déplace l'origine du projet à la position actuelle du joueur\nCela déplacera également la sélection de zone et le placement", - "litematica.gui.button.hover.schematic_projects.place_to_world_warning": "§6Avertissement : Cela supprimera/écrasera les blocs actuels\n§6dans le monde dans la zone qui a été précédemment\n§6placée à partir d'une version, ou enregistrée en tant que version\n§6(en gros, c'est la dernière fois que j'ai vu \"sélection de zone efficace\")", - "litematica.gui.button.hover.schematic_projects.save_new_version": "Enregistre une nouvelle version du schéma/dans le projet actuel", - - "litematica.gui.button.material_list": "Liste des matériaux", - "litematica.gui.button.material_list.clear_cache": "Effacer le cache", - "litematica.gui.button.material_list.clear_ignored": "Effacer les ignorés", - "litematica.gui.button.material_list.hide_available": "Masquer disponible : %s", - "litematica.gui.button.material_list.ignore": "Ignorer", - "litematica.gui.button.material_list.list_type": "Afficher : %s", - "litematica.gui.button.material_list.refresh_list": "Actualiser", - "litematica.gui.button.material_list.toggle_info_hud": "HUD d'informations : %s", - "litematica.gui.button.material_list.write_to_file": "Écrire dans un fichier", - - "litematica.gui.button.placement_sub.placement_configuration": "Configuration du placement", - "litematica.gui.button.placement_sub.reset_sub_region_placement": "Réinitialiser la sous-région", - "litematica.gui.button.placement_sub.slice_type": "Tranche : %s", - - "litematica.gui.button.schematic_manager.export_as": "Exporter en :", - - "litematica.gui.button.schematic_placement.abbr.rendering": "R", - - "litematica.gui.button.schematic_placement.ignore_entities": "Ignorer les entités : %s", - "litematica.gui.button.schematic_placement.region_enabled": "Région : %s", - "litematica.gui.button.schematic_placement.reset_sub_region_placements": "Réinitialiser tous les placements de sous-régions", - "litematica.gui.button.schematic_placement.toggle_all_off": "Tout §cDÉSACTIVɧr", - "litematica.gui.button.schematic_placement.toggle_all_on": "Tout §aACTIVɧr", - - "litematica.gui.button.schematic_placement.hover.enclosing_box": "Rendu de la boîte englobante : %s", - "litematica.gui.button.schematic_placement.hover.lock": "Verrouiller un placement empêche de le déplacer ou de\nle modifier d'une autre manière (accidentellement)", - "litematica.gui.button.schematic_placement.hover.rendering": "Rendu : %s\nNotez que cela fonctionne un peu étrangement\net n'empêche pas le rendu des entités.\nEn général, vous devriez simplement désactiver\nle placement entièrement", - - "litematica.gui.button.schematic_placements.configure": "Configurer", - "litematica.gui.button.schematic_placements.disable": "Désactiver", - "litematica.gui.button.schematic_placements.locked": "Verrouillé : %s", - "litematica.gui.button.schematic_placements.placement_enabled": "Placement : %s", - "litematica.gui.button.schematic_placements.remove": "Supprimer", - "litematica.gui.button.schematic_placements.rendering_enabled": "Rendu : %s", - "litematica.gui.button.schematic_placements.select": "Sélectionner", - - "litematica.gui.button.schematic_projects.close_project": "Fermer le projet actuel", - "litematica.gui.button.schematic_projects.create_project": "Créer un projet", - "litematica.gui.button.schematic_projects.delete_area": "Supprimer la zone", - "litematica.gui.button.schematic_projects.load_project": "Charger le projet", - "litematica.gui.button.schematic_projects.move_origin_to_player": "Déplacer vers toi", - "litematica.gui.button.schematic_projects.open_area_editor": "Éditeur de zone", - "litematica.gui.button.schematic_projects.open_manager_gui": "Ouvrir le gestionnaire", - "litematica.gui.button.schematic_projects.open_project_browser": "Navigateur de projet VCS", - "litematica.gui.button.schematic_projects.place_to_world": "Placer dans le monde", - "litematica.gui.button.schematic_projects.save_version": "Enregistrer la version", - - "litematica.gui.button.schematic_verifier.ignore": "Ignorer", - "litematica.gui.button.schematic_verifier.range_type": "Plage : %s", - "litematica.gui.button.schematic_verifier.reset_ignored": "Réinitialiser les ignorés", - "litematica.gui.button.schematic_verifier.reset_verifier": "Réinitialiser les données", - "litematica.gui.button.schematic_verifier.resume": "Reprendre la vérification", - "litematica.gui.button.schematic_verifier.start": "Démarrer la vérification", - "litematica.gui.button.schematic_verifier.stop": "Arrêter la vérification", - "litematica.gui.button.schematic_verifier.toggle_info_hud": "HUD d'informations : %s", - - "litematica.gui.button.cancel": "Annuler", - "litematica.gui.button.configure": "Configurer", - "litematica.gui.button.copy": "Copier", - "litematica.gui.button.create_directory": "Créer un nouveau répertoire", - "litematica.gui.button.create_placement": "Créer un placement", - "litematica.gui.button.delete": "Supprimer", - "litematica.gui.button.disable": "Désactiver", - "litematica.gui.button.enable": "Activer", - "litematica.gui.button.import": "Importer", - "litematica.gui.button.load_schematic_to_memory": "Charger le schéma", - "litematica.gui.button.mirror_value": "Miroir : %s", - "litematica.gui.button.move_to_player": "Déplacer vers toi", - "litematica.gui.button.ok": "Ok", - "litematica.gui.button.reload": "Recharger", - "litematica.gui.button.remove": "Supprimer", - "litematica.gui.button.remove_placement": "Supprimer le placement", - "litematica.gui.button.rename": "Renommer", - "litematica.gui.button.rotation_value": "Rotation : %s", - "litematica.gui.button.save_new_schematic_version": "Enregistrer la version", - "litematica.gui.button.save_schematic": "Enregistrer le schéma", - "litematica.gui.button.save_to_file": "Enregistrer dans un fichier", - "litematica.gui.button.schematic_verifier": "Vérificateur de schéma", - "litematica.gui.button.set_preview": "Définir l'aperçu", - "litematica.gui.button.tool_mode": "Mode d'outil : %s", - "litematica.gui.button.unload": "Décharger", - "litematica.gui.button.unlocked": "Déverrouillé", - - "litematica.gui.label.area_editor.box_name": "Nom de la boîte de la sous-région", - "litematica.gui.label.area_editor.selection_name": "Nom de la sélection", - "litematica.gui.label.area_editor.corner_1": "Coin 1", - "litematica.gui.label.area_editor.corner_2": "Coin 2", - "litematica.gui.label.area_editor.origin": "Origine", - "litematica.gui.label.area_editor.dimensions": "Dimensions", - "litematica.gui.label.area_editor.pos1": "Coin 1", - "litematica.gui.label.area_editor.pos2": "Coin 2", - "litematica.gui.label.area_editor.sub_regions": "Sous-régions (%s)", - - "litematica.gui.label.area_selection_manager.current_selection": "Zone sélectionnée : %s", - - "litematica.gui.label.area_selection_box_count": "Boîtes : %d", - "litematica.gui.label.area_selection_origin": "Origine : %s", - "litematica.gui.label.area_selection.mode.normal": "Normal", - "litematica.gui.label.area_selection.mode.simple": "Simple", - - "litematica.gui.label.block_info.state_client": "État du bloc dans le monde client", - "litematica.gui.label.block_info.state_schematic": "État du bloc dans le monde schématique", - - "litematica.gui.label.block_info_list_type.all": "Tout", - "litematica.gui.label.block_info_list_type.render_layers": "Couches de rendu", - - "litematica.gui.label.easy_place_protocol.auto": "Auto", - "litematica.gui.label.easy_place_protocol.none": "Aucun", - "litematica.gui.label.easy_place_protocol.slabs_only": "Seulement des dalles", - "litematica.gui.label.easy_place_protocol.v2": "Version 2", - "litematica.gui.label.easy_place_protocol.v3": "Version 3", - - "litematica.gui.label.loaded_schematic.modified_on": "§6Modifié le %s§r", - - "litematica.gui.label.material_list.abbr.shulker_box": "SB", - "litematica.gui.label.material_list.title.available": "Disponible", - "litematica.gui.label.material_list.title.item": "Objet", - "litematica.gui.label.material_list.title.missing": "Manquant", - "litematica.gui.label.material_list.title.total": "Total", - - "litematica.gui.label.material_list.multiplier": "Multiplicateur :", - "litematica.gui.label.material_list.name": "Nom", - "litematica.gui.label.material_list.progress": "Progression : %s", - "litematica.gui.label.material_list.progress.done": "Fait %s", - "litematica.gui.label.material_list.progress.mismatch": "Incompatibilité %s", - "litematica.gui.label.material_list.progress.missing": "Manquant %s", - "litematica.gui.label.material_list.total": "Total : %s objets", - - "litematica.gui.label.origin.auto": "Auto", - "litematica.gui.label.origin.manual": "Manuel", - - "litematica.gui.label.paste_nbt_behavior.none": "Aucun", - "litematica.gui.label.paste_nbt_behavior.place_data_modify": "Placer & Modifier les données", - "litematica.gui.label.paste_nbt_behavior.place_clone": "Placer & Cloner", - - "litematica.gui.label.placement_sub.region_name": "Nom de la région : %s", - "litematica.gui.label.placement_sub.region_position": "Position de la région", - "litematica.gui.label.placement_sub.region_size": "Taille de la région : %s", - - "litematica.gui.label.placement_settings.placement_origin": "Origine du placement", - - "litematica.gui.label.render_layers.hotkey": "Raccourci", - "litematica.gui.label.render_layers.hover.hotkey": "Les raccourcis suivant/précédent de la couche affecteront cette limite.\nSi les deux sont désélectionnés, alors les raccourcis affecteront\nla limite la plus proche du joueur.", - - "litematica.gui.label.replace_behavior.all": "Tout", - "litematica.gui.label.replace_behavior.none": "Aucun", - "litematica.gui.label.replace_behavior.with_non_air": "Avec des blocs non-air", - - "litematica.gui.label.schematic_info.schematic_author": "Schéma créé par : §f%s§r", - "litematica.gui.label.schematic_info.description": "Description :", - "litematica.gui.label.schematic_info.enclosing_size": "Taille de l'enclos :", - "litematica.gui.label.schematic_info.enclosing_size_value": "Taille de l'enclos : §f%s§r", - "litematica.gui.label.schematic_info.name": "Nom :", - "litematica.gui.label.schematic_info.region_count": "Régions : §f%d§r", - "litematica.gui.label.schematic_info.time_created": "Créé : §f%s§r", - "litematica.gui.label.schematic_info.time_modified": "Modifié : §f%s§r", - "litematica.gui.label.schematic_info.total_blocks": "Bloc total : §f%d§r", - "litematica.gui.label.schematic_info.total_blocks_and_volume": "Blocs/Volume : §f%d§r/§f%d§r", - "litematica.gui.label.schematic_info.total_volume": "Volume total : Blocs §f%d§r", - - "litematica.gui.label.schematic_load.checkbox.create_placement": "Créer un placement", - "litematica.gui.label.schematic_load.hoverinfo.create_placement": "Créez immédiatement un nouveau placement\net sélectionnez ce placement", - - "litematica.gui.label.schematic_placement.enclosing_size": "Taille de l'enclos : %s", - "litematica.gui.label.schematic_placement.hoverinfo.hold_shift_to_create_as_disabled": "Maintenez la touche Maj enfoncée pour désactiver le placement lors de sa création", - "litematica.gui.label.schematic_placement.in_memory": "EN MÉMOIRE UNIQUEMENT", - "litematica.gui.label.schematic_placement.origin": "Origine : %s", - "litematica.gui.label.schematic_placement.rename_placement": "Renommer le placement :", - "litematica.gui.label.schematic_placement.schematic_file": "Fichier : %s", - "litematica.gui.label.schematic_placement.schematic_name": "Schéma : %s", - "litematica.gui.label.schematic_placement.sub_region_count": "Sous-régions : %s", - "litematica.gui.label.schematic_placement.sub_regions": "Sous-régions (%s) :", - - "litematica.gui.label.schematic_projects.currently_open_project": "Projet actuellement ouvert : %s", - "litematica.gui.label.schematic_projects.origin": "Origine :", - "litematica.gui.label.schematic_projects.project": "Projet :", - "litematica.gui.label.schematic_projects.version": "Version : %s (sur %s)", - "litematica.gui.label.schematic_projects.version_entry": "Ver. %d - %s", - "litematica.gui.label.schematic_projects.version_name": "Nom de la version :", - - "litematica.gui.label.schematic_save.checkbox.ignore_entities": "Ignorer les entités", - "litematica.gui.label.schematic_save.hoverinfo.hold_shift_to_overwrite": "Maintenez la touche Maj enfoncée pour écraser un fichier existant", - - "litematica.gui.label.schematic_verifier.count": "Compter", - "litematica.gui.label.schematic_verifier.expected": "Attendu", - "litematica.gui.label.schematic_verifier.found": "Trouvé", - "litematica.gui.label.schematic_verifier_display_type.all": "Tous (non ignorés)", - "litematica.gui.label.schematic_verifier_display_type.correct_state": "État correct", - "litematica.gui.label.schematic_verifier_display_type.extra": "Blocs supplémentaires", - "litematica.gui.label.schematic_verifier_display_type.missing": "Blocs manquants", - "litematica.gui.label.schematic_verifier_display_type.wrong_blocks": "Mauvais blocs", - "litematica.gui.label.schematic_verifier_display_type.wrong_state": "États incorrects", - "litematica.gui.label.schematic_verifier.status.done_errors": "Mauvais : §cBloc : %s§r, §6État : %s§r, §bManquants : %s§r, §dSupplémentaires : %s§r", - "litematica.gui.label.schematic_verifier.status.done_correct_total": "§aCorrects : %s§r, Total : %s", - "litematica.gui.label.schematic_verifier.status.verifying": "Chunks non vus : %s / %s", - "litematica.gui.label.schematic_verifier.verifier": "Vérificateur de schéma", - - "litematica.gui.label.task.title.remaining_chunks": "%s, chunks restants (%s)", - "litematica.gui.label.task_name.area_analyzer": "Analyseur de zone", - "litematica.gui.label.task_name.delete": "Supprimer la tâche", - "litematica.gui.label.task_name.fill": "Tâche de remplissage", - "litematica.gui.label.task_name.material_list": "Liste des matériaux", - "litematica.gui.label.task_name.paste": "Coller le schéma", - "litematica.gui.label.task_name.save_schematic": "Enregistrer le schéma", - "litematica.gui.label.task_name.verifier": "Vérificateur", - - "litematica.gui.message.confirm_file_deletion": "Voulez-vous supprimer le fichier '%s' ?", - "litematica.gui.message.schematic_projects.confirm_delete_area": "Voulez-vous supprimer la zone \"dernièrement affectée\" ?\nCela supprimera les blocs et entités présents dans la zone que le gestionnaire de projet a récemment placée dans le monde, ou sauvegardée en tant que version. (Essentiellement la \"zone affectée vue en dernier\", de sorte que si vous deviez changer de version, cela ne laisserait pas de blocs derrière de la version précédente.)", - "litematica.gui.message.schematic_projects.confirm_place_to_world": "Voulez-vous placer cette version dans le monde ?\nCela supprimera les blocs présents dans la zone que le gestionnaire de projet a récemment placée dans le monde, ou sauvegardée en tant que version. (Essentiellement la \"zone affectée vue en dernier\", de sorte que si vous deviez changer de version, cela ne laisserait pas de blocs derrière de la version précédente.)", - - "litematica.gui.title.area_editor_normal": "Éditeur de zone (Mode normal/Multi-boîtes)", - "litematica.gui.title.area_editor_normal_schematic_projects": "Éditeur de zone (Zone de schéma §6§lVCS§r)", - "litematica.gui.title.area_editor_simple": "Éditeur de zone (Mode simple)", - "litematica.gui.title.area_editor_sub_region": "Éditeur de zone (Sous-région)", - "litematica.gui.title.area_editor.sub_region_name": "Nom de la sous-région", - "litematica.gui.title.area_selection_manager": "Gestionnaire de sélection de zone", - "litematica.gui.title.configure_schematic_placement": "Configurer le placement du schéma", - "litematica.gui.title.configure_schematic_sub_region": "Configurer la sous-région de placement", - "litematica.gui.title.configs": "Configurations Litematica", - "litematica.gui.title.confirm_file_deletion": "Confirmer la suppression de fichier", - "litematica.gui.title.copy_area_selection": "Copier la sélection de zone '%s'", - "litematica.gui.title.create_area_selection": "Créer une nouvelle sélection de zone", - "litematica.gui.title.create_area_selection_from_placement": "Créer une nouvelle sélection de zone à partir d'un placement de schéma", - "litematica.gui.title.create_directory": "Créer un nouveau répertoire", - "litematica.gui.title.create_in_memory_schematic": "Créer un schéma en mémoire", - "litematica.gui.title.create_schematic_project": "Créer un nouveau projet de schéma", - "litematica.gui.title.litematica_main_menu": "Litematica %s", - "litematica.gui.title.load_schematic": "Charger le schéma", - "litematica.gui.title.manage_loaded_schematics": "Gérer les schémas chargés", - "litematica.gui.title.manage_schematic_placements": "Gérer les placements de schémas", - "litematica.gui.title.material_list.area_analyzer": "Analyse de zone pour la sélection '%s'", - "litematica.gui.title.material_list.placement": "Liste des matériaux pour le placement '%s'", - "litematica.gui.title.material_list.schematic": "Liste des matériaux pour le schéma '%s' (%s sur %s régions)", - "litematica.gui.title.material_list.select_schematic_regions": "Sélectionnez les sous-régions pour la liste des matériaux de '%s'", - "litematica.gui.title.rename_area_selection": "Renommer la sélection de zone", - "litematica.gui.title.rename_area_sub_region": "Renommer la sous-région", - "litematica.gui.title.rename_schematic": "Renommer le schéma", - "litematica.gui.title.create_schematic_from_selection": "Enregistrer la zone actuellement sélectionnée comme schéma", - "litematica.gui.title.save_exported_schematic": "Enregistrer un %s exporté de '%s'", - "litematica.gui.title.save_imported_schematic": "Enregistrer un schéma importé", - "litematica.gui.title.save_schematic_from_memory": "Enregistrer un schéma en mémoire dans un fichier", - "litematica.gui.title.save_schematic_filename": "Nom du fichier du schéma", - "litematica.gui.title.schematic_browser": "Navigateur de schémas", - "litematica.gui.title.schematic_manager": "Gestionnaire de schémas", - "litematica.gui.title.schematic_project_manager": "Gestionnaire de projets de schémas VCS", - "litematica.gui.title.schematic_projects.confirm_delete_area": "Confirmer la suppression de la zone", - "litematica.gui.title.schematic_projects.confirm_place_to_world": "Confirmer l'action de placement dans le monde", - "litematica.gui.title.schematic_projects.save_new_version": "Enregistrer une nouvelle version de schéma", - "litematica.gui.title.schematic_projects_browser": "Navigateur de projets de schémas VCS", - "litematica.gui.title.schematic_verifier": "Vérificateur de schéma pour '%s'", - "litematica.gui.title.schematic_verifier_errors": "Erreurs de vérificateur de schéma", - "litematica.gui.title.task_manager": "Gestionnaire de tâches", - - "litematica.hud.area_selection.box_count": "Boîtes: %s", - "litematica.hud.area_selection.dimensions_position": "Dim: %s - p1: %s, p2: %s", - "litematica.hud.area_selection.mode.corners": "Coins", - "litematica.hud.area_selection.mode.expand": "Étendre", - "litematica.hud.area_selection.origin": "Origine: %s", - "litematica.hud.area_selection.selected_area_normal": "Zone: %s", - "litematica.hud.area_selection.selected_area_simple": "Zone [§6Mode simple§r]: %s", - "litematica.hud.area_selection.selected_sub_region": "Sous-région: %s", - "litematica.hud.area_selection.selection_corners_mode": "Mode Coins: %s", - - "litematica.hud.delete.target_mode": "Mode cible de suppression: %s", - "litematica.hud.delete.target_mode.area": "Zone actuelle", - "litematica.hud.delete.target_mode.placement": "Placement actuel", - - "litematica.hud.misc.easy_place_mode_enabled": "Mode Placement Facile §aON§r", - "litematica.hud.misc.none_brackets": "", - "litematica.hud.misc.placement_restriction_mode_enabled": "Mode Restriction de Placement §aON§r", - "litematica.hud.misc.render_layer_mode": "Mode de calque: %s - %s", - "litematica.hud.misc.render_layer_mode_all": "Mode de calque: %s", - "litematica.hud.misc.renderer_status": "Rendus: A: %s S: %s B: %s O: %s SEL: %s", - "litematica.hud.misc.schematic_paste.data_restore_mode": "Mode de restauration des données: §b%s", - "litematica.hud.misc.schematic_paste.replace_mode": "Remplacer les blocs: %s", - - "litematica.hud.schematic_placement.hover_info.lock_coordinate": "Verrouiller cette coordonnée\nCela permet de modifier les autres coordonnées\nsans affecter les coordonnées verrouillées", - "litematica.hud.schematic_placement.hover_info.placement_locked": "Ce placement a été verrouillé et ne peut pas\nêtre modifié sans être déverrouillé au préalable", - "litematica.hud.schematic_placement.hover_info.placement_modified": "Ce placement a été modifié", - "litematica.hud.schematic_placement.hover_info.placement_sub_region_modified": "Cette sous-région a été modifiée", - "litematica.hud.schematic_placement.selected_placement": "Placement", - "litematica.hud.schematic_placement.selected_sub_region": "Sous-région", - "litematica.hud.schematic_placement.sub_region_count": "Régions", - "litematica.hud.schematic_placement.sub_region_modified": "Modifié", - "litematica.hud.schematic_placement.sub_region_origin": "Origine de la région: %s", - "litematica.hud.schematic_placement.sub_regions_modified": "Régions modifiées", - - "litematica.hud.selected_mode": "Mode", - - "litematica.hud.schematic_projects.current_version_date": "Date: %s", - "litematica.hud.schematic_projects.current_version": "Version: %s/%s - name: %s", - "litematica.hud.schematic_projects.no_project_open": "", - "litematica.hud.schematic_projects.no_versions": "", - "litematica.hud.schematic_projects.origin": "Origine du projet: %s", - "litematica.hud.schematic_projects.project_name": "Projet: %s", - "litematica.hud.schematic_projects_mode": "§6Mode Schematic VCS§r", - - "litematica.info.material_list": "- La touche de raccourci de la liste des matériaux ouvrira la dernière liste consultée,\n si elle est sauvegardée\n- Pour basculer vers une liste de matériaux différente, ouvrez-en une via\n le bouton GUI dans la configuration du placement ou\n le navigateur de schémas\n- La liste stockée/dernièrement consultée est également oubliée\n si le Placement Schematic sélectionné est changé\n- S'il n'y a pas encore de liste de matériaux consultée,\n alors le Placement sélectionné est utilisé, s'il y en a un", - - "litematica.label.alignment.center": "Centre", - "litematica.label.alignment.top_center": "Haut Centre", - - "litematica.label.none_lower": "aucun", - "litematica.label.no": "non", - "litematica.label.yes": "oui", - - "litematica.message.error.area_deletion_aborted": "Suppression de la zone interrompue ou annulée", - "litematica.message.error.empty_area_selection": "Sélection de zone vide (pas de boîtes)", - "litematica.message.error.invalid_schematic_name": "Nom de schéma invalide '%s'", - "litematica.message.error.no_area_selected": "§cAucune zone sélectionnée§r", - "litematica.message.error.no_placement_selected": "§cAucun placement sélectionné§r", - "litematica.message.error.only_works_in_single_player": "§cCette opération ne fonctionne que en mode joueur unique§r", - "litematica.message.error.move.pending_tasks": "§cImpossible de démarrer une opération de déplacement tant qu'il y a des tâches en attente§r", - "litematica.message.error.placement_paste_outside_world": "Le placement ne peut pas être collé à la position actuelle, car il dépasse les limites du monde", - "litematica.message.error.schematic_paste_failed": "§cÉchec du collage du schéma dans le monde§r", - "litematica.message.error.schematic_save_failed": "Échec de l'enregistrement du schéma dans le fichier '%s'", - "litematica.message.error.schematic_save_interrupted": "Enregistrement du schéma interrompu ou arrêté", - "litematica.message.error.schematic_save_no_area_selected": "§cÉchec de l'enregistrement du schéma - aucune zone sélectionnée§r", - "litematica.message.warn.pickblock.no_suitable_slot_found": "Aucun emplacement de barre d'accès rapide adapté trouvé pour le bloc à ramasser!\\nVérifiez la configuration Generic -> §epickBlockableSlots§r.\\nDe plus, en fonction des configurations §epickBlockAvoid*§6, la fonction de ramassage peut refuser de remplacer tout outil ou autre élément endommageable dans ces emplacements.", - "litematica.message.warn.pickblock.no_valid_slots_configured": "Aucun emplacement de barre d'accès rapide défini dans la configuration Generic -> §epickBlockableSlots§6 !", - - "litematica.message.added_selection_box": "Ajouté une nouvelle boîte de sélection à %s", - "litematica.message.area_clear_fail": "§cImpossible de vider la ou les zones§r", - "litematica.message.area_cleared": "Zone vidée", - "litematica.message.area_filled": "Zone remplie", - "litematica.message.area_fill_fail": "Échec du remplissage de la zone", - "litematica.message.area_selections.selection_created_from_placement": "Créé une nouvelle sélection à partir du placement '%s'", - "litematica.message.easy_place_fail": "§6Action empêchée par le mode Placement Facile", - "litematica.message.grabbed_element_for_moving": "Élément saisi pour le déplacement", - "litematica.message.in_memory_schematic_created": "Créé un schéma en mémoire en tant que '%s'", - "litematica.message.material_list.material_cache_cleared": "Cache des matériaux effacé", - "litematica.message.material_list_written_to_file": "Liste des matériaux écrite dans le fichier '%s'", - "litematica.message.moved_area_origin": "Déplacé le point d'origine de la zone de %s => %s", - "litematica.message.moved_selection": "Déplacé la sélection actuelle de %s => %s", - "litematica.message.placement.cant_modify_is_locked": "§cLe placement est verrouillé et ne peut pas être modifié§r", - "litematica.message.placement.moved_placement_origin": "Déplacé l'origine du placement de %s => %s", - "litematica.message.placement.moved_subregion_to": "Déplacé la sous-région à %s", - "litematica.message.placement_restriction_fail": "§6Action empêchée par le mode Restriction de Placement", - "litematica.message.removed_area_origin": "Supprimé le point d'origine de la zone explicite/manuelle", - "litematica.message.removed_selection_box": "Boîte de sélection %s supprimée", - "litematica.message.scheduled_task_added": "Tâche planifiée ajoutée...", - "litematica.message.schematic_exported_as": "Schéma exporté en tant que '%s'", - "litematica.message.schematic_pasted": "Schéma collé dans le monde", - "litematica.message.schematic_pasted_using_fill_and_setblock": "Schéma collé en utilisant les commandes fill §b%s§r et setblock §b%s§r", - "litematica.message.schematic_pasted_using_setblock": "Schéma collé en utilisant les commandes setblock §b%s§r", - "litematica.message.schematic_pasted_using_world_edit": "Schéma collé en utilisant les commandes World Edit //set §b%s§r", - "litematica.message.schematic_placement_created": "Placement créé pour '%s'", - "litematica.message.schematic_preview_cancelled": "Tâche d'aperçu annulée", - "litematica.message.schematic_read_from_file_success": "Schéma chargé à partir du fichier '%s'", - "litematica.message.schematic_rendering_refreshed": "Rendu du schéma actualisé", - "litematica.message.schematic_saved_as": "Schéma enregistré en tant que '%s'", - "litematica.message.schematic_save_task_created": "Tâche d'enregistrement du schéma créée", - "litematica.message.set_area_origin": "Définir le point d'origine de la zone à %s", - "litematica.message.set_selection_box_point": "Définir/déplacer le point %d à %s", - "litematica.message.toggled": "Basculé %s %s", - "litematica.message.value.on": "ON", - "litematica.message.value.off": "OFF", - - "litematica.message.schematic_projects.project_created": "Projet '%s' créé", - "litematica.message.schematic_projects.project_loaded": "Projet '%s' chargé", - "litematica.message.schematic_projects.version_saved": "Nouvelle version (#%s) enregistrée en tant que '%s'", - - "litematica.message.warn.area_selection.browser_open_in_simple_mode": "Note : Vous êtes actuellement en mode de sélection de zone simple", - "litematica.message.warn.layer_mode_currently_at": "Note : Vous êtes actuellement en mode de rendu de couche '%s'", - "litematica.message.warn.main_rendering_disabled": "Attention : Le rendu principal est actuellement désactivé\nVoir Visuals -> %s, ou Hotkeys -> %s ['%s']", - "litematica.message.warn.schematic_blocks_rendering_disabled": "Attention : Le rendu des blocs de schéma est actuellement désactivé\nVoir Visuals -> %s, ou Hotkeys -> %s ['%s']", - "litematica.message.warn.schematic_load_non_litematica": "Attention : Lorsque vous chargez directement des schémas non-Litematica, les placements créés ne seront pas persistants.\nDe plus, si vous devez charger le schéma plusieurs fois, la latence de conversion de type de schéma (pour les schémas volumineux) se produira à chaque chargement.\n\nIl est donc recommandé de soit importer le schéma et de l'enregistrer dans le format Litematica via le menu Gestionnaire de schémas, ou mieux encore, de coller le schéma d'origine dans un monde temporaire à l'aide de MCEdit ou du mode Coller dans Litematica, puis de créer un nouveau schéma Litematica à partir de celui-ci, de préférence en utilisant plusieurs sous-régions pour capturer étroitement la construction, le cas échéant.", - "litematica.message.warn.schematic_rebuild_placement_not_selected": "Le placement ciblé n'est actuellement pas sélectionné. La touche de raccourci Remplacer tout ne fonctionne que sur les sous-régions actuellement sélectionnées du placement sur lequel vous cliquez. Ainsi, pour remplacer les blocs dans une seule sous-région, sélectionnez cette sous-région. Pour remplacer dans l'ensemble du schéma (toutes les sous-régions), sélectionnez l'ensemble du placement et non pas une sous-région de celui-ci. Les blocs ne sont également remplacés que dans la zone limitée par le paramètre actuel des couches de rendu.", - "litematica.message.warn.schematic_rendering_disabled": "Attention : Le rendu de schéma est actuellement désactivé\nVoir Visuals -> %s, ou Hotkeys -> %s ['%s']", - "litematica.message.warn.schematic_verifier.overlay_disabled": "Attention : Le rendu de l'overlay du vérificateur est actuellement désactivé ! Voir Infos sur les superpositions -> %s (ou Hotkeys -> %s ['%s'])", - - "litematica.message.warning.invalid_number": "Entrée invalide pour un nombre '%s'", - "litematica.message.warning.schematic_projects_hidden": "Attention : Le système de contrôle de version du schéma est actuellement masqué. En général, vous NE DEVRIEZ PAS utiliser ceci, sauf si vous savez vraiment comment cela fonctionne et modifie certains comportements du mod. Il est destiné à un travail de conception itératif, en place, où il est nécessaire de basculer entre différentes versions de la construction en place (= supprimer et remplacer la version précédente). Si vous souhaitez l'utiliser, activez l'option Generic -> unhideSchematicVCS", - - "litematica.warning.area_editor.area_rendering_disabled": "Note : Le rendu des boîtes de sélection de zone est actuellement désactivé\nVoir Visuals -> %s, ou Hotkeys -> %s ['%s']", - - "litematica.tool_hud.block_1": "Bloc: %s", - "litematica.tool_hud.block_2": "Remplacer: %s", - "litematica.tool_hud.facing": "Orientation: %s", - - "litematica.tool_mode.name.area_selection": "Sélection de zone", - "litematica.tool_mode.name.delete": "Supprimer", - "litematica.tool_mode.name.fill": "Remplir", - "litematica.tool_mode.name.grid_paste": "Coller un schéma en grille dans le monde", - "litematica.tool_mode.name.move": "Déplacer", - "litematica.tool_mode.name.paste_schematic": "Coller un schéma dans le monde", - "litematica.tool_mode.name.rebuild": "Modifier un schéma", - "litematica.tool_mode.name.replace_block": "Remplacer le bloc", - "litematica.tool_mode.name.schematic_placement": "Placement de schéma" -} + "litematica.error.area_selection.copy_failed": "Échec de la copie de la sélection", + "litematica.error.area_selection.create_failed": "Échec de la création d'une nouvelle sélection avec le nom '%s', le fichier existe déjà", + "litematica.error.area_selection.failed_to_load": "Échec du chargement de la sélection de zone", + "litematica.error.area_selection.grow.no_sub_region_selected": "Aucune sous-région sélectionnée !", + "litematica.error.area_selection.no_placement_selected": "Aucun placement de schéma sélectionné !", + "litematica.error.area_selection.rename.already_exists": "Erreur : Une zone existe déjà avec le nom de fichier '%s'", + "litematica.error.area_selection.rename.invalid_safe_file_name": "Nom de fichier sécurisé généré invalide '%s'", + + "litematica.error.duplicate_schematic_placement": "Erreur : Tentative d'ajout d'un placement qui existe déjà", + "litematica.error.generic.creative_mode_only": "Cette action est uniquement disponible en mode Créatif", + "litematica.error.generic.failed_to_delete_file": "Échec de la suppression du fichier '%s'", + "litematica.error.generic.failed_to_sort_list_of_ignored_states": "Échec du tri de la liste des états ignorés", + "litematica.error.generic.schematic_world_not_loaded": "Le monde schématique n'a pas été chargé", + + "litematica.error.area_editor.create_sub_region.exists": "Une sous-région portant le nom '%s' existe déjà", + "litematica.error.area_editor.no_selection": "Aucune sélection de zone active", + "litematica.error.area_editor.open_gui.no_selection": "Actuellement en mode de sélection : Normal, mais aucune zone n'est actuellement sélectionnée", + "litematica.error.area_editor.rename_sub_region.exists": "Échec du renommage de la sous-région:\nUne sous-région existe déjà avec le nom '%s'", + "litematica.error.area_editor.switch_mode.no_selection": "Impossible de passer en mode de sélection : Normal, car aucune zone n'est actuellement sélectionnée.\nSélectionnez une zone ou créez une nouvelle sélection dans le navigateur de sélection de zone", + + "litematica.error.schematic_conversion.schematic_to_litematica.failed_to_create_schematic": "Échec de la création du schéma Litematica", + "litematica.error.schematic_conversion.schematic_to_litematica.failed_to_read_schematic": "Échec du chargement du schéma", + "litematica.error.schematic_conversion.structure_to_litematica_failed": "Échec de la conversion de la structure en schéma Litematica", + + "litematica.error.schematic.create.no_selections": "Aucune région de sélection valide !", + + "litematica.error.schematic_load.cant_read_file": "Impossible de lire le fichier schématique '%s' (n'existe pas ou problème de permission)", + "litematica.error.schematic_load.no_schematic_selected": "Aucun fichier schématique sélectionné !", + "litematica.error.schematic_load.no_schematic_version_information": "Le schéma n'a pas d'informations de version et ne peut pas être chargé en toute sécurité !", + "litematica.error.schematic_load.unsupported_schematic_version": "Version schématique non prise en charge ou future '%d'", + "litematica.error.schematic_load.unsupported_type": "Type de fichier inconnu ou non pris en charge pour '%s'", + + "litematica.error.schematic_manager.schematic_export.unsupported_type": "Seuls les schémas Litematica peuvent être exportés dans d'autres formats !", + "litematica.error.schematic_manager.schematic_import.unsupported_type": "Le type de schéma sélectionné n'est pas pris en charge pour l'importation !", + + "litematica.error.schematic_placements.remove_fail_locked": "Le placement est verrouillé !\n- Maintenez la touche Maj enfoncée pour le supprimer de force", + + "litematica.error.schematic_save.directory_doesnt_exist": "Aucun répertoire tel que '%s'", + "litematica.error.schematic_save.file_already_exists": "Le fichier '%s' existe déjà", + "litematica.error.schematic_save.invalid_directory": "Répertoire invalide '%s'", + "litematica.error.schematic_save.invalid_schematic_name": "Nom de schéma invalide '%s'", + "litematica.error.schematic_save.schematic_creation_failed": "Échec de la création du schéma !", + + "litematica.error.schematic_read_from_file_failed.cant_read": "Échec de la lecture du schéma depuis le fichier '%s'", + "litematica.error.schematic_read_from_file_failed.exception": "Exception lors de la tentative de lecture du schéma depuis le fichier '%s'", + "litematica.error.schematic_read_from_file_failed.no_file": "Échec de la lecture du schéma depuis le fichier : aucun fichier disponible (schéma en mémoire ?)", + + "litematica.error.schematic_projects.empty_selection": "Sélection de zone vide (0 sous-régions)", + "litematica.error.schematic_projects.failed_to_load_project": "Échec du chargement du projet", + "litematica.error.schematic_projects.failed_to_load_schematic": "Échec du chargement du schéma pour la version actuelle", + "litematica.error.schematic_projects.failed_to_rename_project_file_exception": "Échec du renommage du fichier de projet en '%s' (exception)", + "litematica.error.schematic_projects.failed_to_rename_project_file_exists": "Impossible de renommer le projet en '%s', le fichier existe déjà", + "litematica.error.schematic_projects.invalid_project_directory": "Répertoire de projet invalide ou inexistant", + "litematica.error.schematic_projects.no_project_open": "Aucun projet ouvert", + "litematica.error.schematic_projects.in_projects_mode_but_no_project_open": "Actuellement en mode Schematic VCS, mais aucun projet n'est actuellement ouvert", + "litematica.error.schematic_projects.null_player": "Le joueur était nul", + "litematica.error.schematic_projects.project_already_exists": "Le projet '%s' existe déjà", + "litematica.error.schematic_projects.save_already_in_progress": "Sauvegarde déjà en cours", + + "litematica.error.schematic_write_to_file_failed.directory_creation_failed": "Échec de la création du répertoire du schéma '%s'", + "litematica.error.schematic_write_to_file_failed.exception": "Échec de l'écriture du schéma dans le fichier '%s' (exception)", + "litematica.error.schematic_write_to_file_failed.exists": "Échec de l'écriture du schéma dans le fichier '%s', le fichier existe déjà", + "litematica.error.structure_write_to_file_failed.exception": "Échec de l'écriture de la structure dans le fichier '%s' (exception)", + "litematica.error.structure_write_to_file_failed.exists": "Échec de l'écriture de la structure dans le fichier '%s', le fichier existe déjà", + + "litematica.hotkeys.category.generic_hotkeys": "Raccourcis génériques", + + "litematica.info.schematic_load.schematic_loaded": "Schéma '%s' chargé avec succès en mémoire", + "litematica.info.schematic_manager.preview.right_click_to_cancel": "- Clic droit sur le bouton pour annuler une opération d'aperçu en attente\n- Ctrl + Alt + Maj + clic pour définir la vignette à partir d'une image PNG existante\n appelée 'thumb.png' dans le même répertoire que le fichier schématique.", + "litematica.info.schematic_manager.preview.set_preview_by_taking_a_screenshot": "Utilisez la touche normale de capture d'écran pour définir l'aperçu.\nOu faites un clic droit sur le bouton Définir l'aperçu pour annuler la définition de l'aperçu.", + "litematica.info.schematic_manager.preview.success": "Image d'aperçu définie avec succès", + + "litematica.gui.button.area_editor.analyze_area": "Analyser zone", + "litematica.gui.button.area_editor.change_corner_mode": "Mode Coin : %s", + "litematica.gui.button.area_editor.change_selection_mode": "Mode de sélection : %s", + "litematica.gui.button.area_editor.create_schematic": "Enregistrer le schéma", + "litematica.gui.button.area_editor.create_sub_region": "Nouvelle sous-région", + "litematica.gui.button.area_editor.origin_enabled": "Origine manuelle : %s", + "litematica.gui.button.area_editor.set_box_name": "Définir", + "litematica.gui.button.area_editor.set_selection_name": "Définir", + + "litematica.gui.button.area_selection_mode": "Mode de sélection de zone : %s", + "litematica.gui.button.area_selections.create_directory": "Créer un répertoire", + "litematica.gui.button.area_selections.create_new_selection": "Nouvelle sélection", + "litematica.gui.button.area_selections.create_selection_from_placement": "À partir du Placement", + "litematica.gui.button.area_selections.unselect": "Désélectionner", + + "litematica.gui.button.change_menu.area_editor": "Éditeur de zone", + "litematica.gui.button.change_menu.configuration_menu": "Menu de configuration", + "litematica.gui.button.change_menu.load_schematics_to_memory": "Charger les schémas", + "litematica.gui.button.change_menu.schematic_manager": "Gestionnaire de schémas", + "litematica.gui.button.change_menu.schematic_projects_manager": "Schematic VCS", + "litematica.gui.button.change_menu.show_area_selections": "Navigateur de sélection de zone", + "litematica.gui.button.change_menu.show_loaded_schematics": "Schémas chargés", + "litematica.gui.button.change_menu.show_schematic_placements": "Placements de schéma", + "litematica.gui.button.change_menu.task_manager": "Gestionnaire des tâches", + "litematica.gui.button.change_menu.to_main_menu": "Menu Litematica", + + "litematica.gui.button.config_gui.colors": "Couleurs", + "litematica.gui.button.config_gui.generic": "Générique", + "litematica.gui.button.config_gui.hotkeys": "Raccourcis", + "litematica.gui.button.config_gui.info_overlays": "Surimpressions d'informations", + "litematica.gui.button.config_gui.render_layers": "Couches de rendu", + "litematica.gui.button.config_gui.visuals": "Visuels", + + "litematica.gui.button.hover.area_editor.shift_for_in_memory": "Maintenez la touche Shift pour créer un schéma uniquement en mémoire", + "litematica.gui.button.hover.area_selections.unselect": "Désélectionne la sélection de zone actuelle", + "litematica.gui.button.hover.material_list.clear_cache": "Efface le cache des matériaux\nNormalement, cela ne devrait pas être nécessaire\nCela peut être utilisé au lieu de supprimer le fichier 'material_cache.nbt'\nsi le cache contient des données incorrectes, comme des objets\nstockés pour des blocs qui ne devraient pas en avoir, comme les têtes de piston", + "litematica.gui.button.hover.material_list.write_hold_shift_for_csv": "Maintenez la touche Shift enfoncée pour écrire dans un fichier CSV,\nau lieu du fichier texte ASCII standard", + "litematica.gui.button.hover.material_list_shift_to_select_sub_regions": "Maintenez la touche Shift enfoncée pour sélectionner les sous-régions utilisées pour la liste des matériaux", + "litematica.gui.button.hover.plus_minus_tip": "Clic gauche pour augmenter\nClic droit pour diminuer\nMaintenez Maj et/ou Alt pour augmenter la taille du pas", + "litematica.gui.button.hover.plus_minus_tip_ctrl_alt_shift": "Clic gauche pour augmenter\nClic droit pour diminuer\nMaintenez Maj/Alt/Ctrl pour augmenter la taille du pas (multiplicatif)", + "litematica.gui.button.hover.schematic_list.reload_schematic": "Recharge le schéma depuis le fichier.\nCela peut être utile en cas d'erreur\nen mode Édition de schéma.", + "litematica.gui.button.hover.schematic_projects.area_browser_disabled_currently_in_projects_mode": "Un projet Schematic VCS est actuellement ouvert.\nLe mode Schematic VCS remplace la fonctionnalité normale de sélection de zone", + "litematica.gui.button.hover.schematic_projects.delete_area": "§6Supprimer la dernière zone placée ou enregistrée§r", + "litematica.gui.button.hover.schematic_projects.menu_warning": "(Cela s'appelait Schematic Projects auparavant.)\nEn général, vous §6ne devriez pas§r utiliser cette fonctionnalité,\nà moins de savoir vraiment comment elle fonctionne et ce qu'elle fait.\nElle modifie quelque peu le fonctionnement des sélections de zone, des placements et du collage,\nnotamment qu'il y a aussi une opération de suppression de zone lors du collage.\n\nEssentiellement, cette fonctionnalité est destinée à un travail de conception §6itératif, sur place§r,\net elle vous permet de créer plus facilement plusieurs versions/snapshots\nde la même construction, ainsi que de passer entre les versions en supprimant ce qui est\ndans le monde d'abord, puis en collant la version suivante à sa place.", + "litematica.gui.button.hover.schematic_projects.move_origin_to_player": "Déplace l'origine du projet à la position actuelle du joueur\nCela déplacera également la sélection de zone et le placement", + "litematica.gui.button.hover.schematic_projects.place_to_world_warning": "§6Avertissement : Cela supprimera/écrasera les blocs actuels\n§6dans le monde dans la zone qui a été précédemment\n§6placée à partir d'une version, ou enregistrée en tant que version\n§6(en gros, c'est la dernière fois que j'ai vu \"sélection de zone efficace\")", + "litematica.gui.button.hover.schematic_projects.save_new_version": "Enregistre une nouvelle version du schéma/dans le projet actuel", + + "litematica.gui.button.material_list": "Liste des matériaux", + "litematica.gui.button.material_list.clear_cache": "Effacer le cache", + "litematica.gui.button.material_list.clear_ignored": "Effacer les ignorés", + "litematica.gui.button.material_list.hide_available": "Masquer disponible : %s", + "litematica.gui.button.material_list.ignore": "Ignorer", + "litematica.gui.button.material_list.list_type": "Afficher : %s", + "litematica.gui.button.material_list.refresh_list": "Actualiser", + "litematica.gui.button.material_list.toggle_info_hud": "HUD d'informations : %s", + "litematica.gui.button.material_list.write_to_file": "Écrire dans un fichier", + + "litematica.gui.button.placement_sub.placement_configuration": "Configuration du placement", + "litematica.gui.button.placement_sub.reset_sub_region_placement": "Réinitialiser la sous-région", + "litematica.gui.button.placement_sub.slice_type": "Tranche : %s", + + "litematica.gui.button.schematic_manager.export_as": "Exporter en :", + + "litematica.gui.button.schematic_placement.abbr.rendering": "R", + + "litematica.gui.button.schematic_placement.ignore_entities": "Ignorer les entités : %s", + "litematica.gui.button.schematic_placement.region_enabled": "Région : %s", + "litematica.gui.button.schematic_placement.reset_sub_region_placements": "Réinitialiser tous les placements de sous-régions", + "litematica.gui.button.schematic_placement.toggle_all_off": "Tout §cDÉSACTIVɧr", + "litematica.gui.button.schematic_placement.toggle_all_on": "Tout §aACTIVɧr", + + "litematica.gui.button.schematic_placement.hover.enclosing_box": "Rendu de la boîte englobante : %s", + "litematica.gui.button.schematic_placement.hover.lock": "Verrouiller un placement empêche de le déplacer ou de\nle modifier d'une autre manière (accidentellement)", + "litematica.gui.button.schematic_placement.hover.rendering": "Rendu : %s\nNotez que cela fonctionne un peu étrangement\net n'empêche pas le rendu des entités.\nEn général, vous devriez simplement désactiver\nle placement entièrement", + + "litematica.gui.button.schematic_placements.configure": "Configurer", + "litematica.gui.button.schematic_placements.disable": "Désactiver", + "litematica.gui.button.schematic_placements.locked": "Verrouillé : %s", + "litematica.gui.button.schematic_placements.placement_enabled": "Placement : %s", + "litematica.gui.button.schematic_placements.remove": "Supprimer", + "litematica.gui.button.schematic_placements.rendering_enabled": "Rendu : %s", + "litematica.gui.button.schematic_placements.select": "Sélectionner", + + "litematica.gui.button.schematic_projects.close_project": "Fermer le projet actuel", + "litematica.gui.button.schematic_projects.create_project": "Créer un projet", + "litematica.gui.button.schematic_projects.delete_area": "Supprimer la zone", + "litematica.gui.button.schematic_projects.load_project": "Charger le projet", + "litematica.gui.button.schematic_projects.move_origin_to_player": "Déplacer vers toi", + "litematica.gui.button.schematic_projects.open_area_editor": "Éditeur de zone", + "litematica.gui.button.schematic_projects.open_manager_gui": "Ouvrir le gestionnaire", + "litematica.gui.button.schematic_projects.open_project_browser": "Navigateur de projet VCS", + "litematica.gui.button.schematic_projects.place_to_world": "Placer dans le monde", + "litematica.gui.button.schematic_projects.save_version": "Enregistrer la version", + + "litematica.gui.button.schematic_verifier.ignore": "Ignorer", + "litematica.gui.button.schematic_verifier.range_type": "Plage : %s", + "litematica.gui.button.schematic_verifier.reset_ignored": "Réinitialiser les ignorés", + "litematica.gui.button.schematic_verifier.reset_verifier": "Réinitialiser les données", + "litematica.gui.button.schematic_verifier.resume": "Reprendre la vérification", + "litematica.gui.button.schematic_verifier.start": "Démarrer la vérification", + "litematica.gui.button.schematic_verifier.stop": "Arrêter la vérification", + "litematica.gui.button.schematic_verifier.toggle_info_hud": "HUD d'informations : %s", + + "litematica.gui.button.cancel": "Annuler", + "litematica.gui.button.configure": "Configurer", + "litematica.gui.button.copy": "Copier", + "litematica.gui.button.create_directory": "Créer un nouveau répertoire", + "litematica.gui.button.create_placement": "Créer un placement", + "litematica.gui.button.delete": "Supprimer", + "litematica.gui.button.disable": "Désactiver", + "litematica.gui.button.enable": "Activer", + "litematica.gui.button.import": "Importer", + "litematica.gui.button.load_schematic_to_memory": "Charger le schéma", + "litematica.gui.button.mirror_value": "Miroir : %s", + "litematica.gui.button.move_to_player": "Déplacer vers toi", + "litematica.gui.button.ok": "Ok", + "litematica.gui.button.reload": "Recharger", + "litematica.gui.button.remove": "Supprimer", + "litematica.gui.button.remove_placement": "Supprimer le placement", + "litematica.gui.button.rename": "Renommer", + "litematica.gui.button.rotation_value": "Rotation : %s", + "litematica.gui.button.save_new_schematic_version": "Enregistrer la version", + "litematica.gui.button.save_schematic": "Enregistrer le schéma", + "litematica.gui.button.save_to_file": "Enregistrer dans un fichier", + "litematica.gui.button.schematic_verifier": "Vérificateur de schéma", + "litematica.gui.button.set_preview": "Définir l'aperçu", + "litematica.gui.button.tool_mode": "Mode d'outil : %s", + "litematica.gui.button.unload": "Décharger", + "litematica.gui.button.unlocked": "Déverrouillé", + + "litematica.gui.label.area_editor.box_name": "Nom de la boîte de la sous-région", + "litematica.gui.label.area_editor.selection_name": "Nom de la sélection", + "litematica.gui.label.area_editor.corner_1": "Coin 1", + "litematica.gui.label.area_editor.corner_2": "Coin 2", + "litematica.gui.label.area_editor.origin": "Origine", + "litematica.gui.label.area_editor.dimensions": "Dimensions", + "litematica.gui.label.area_editor.pos1": "Coin 1", + "litematica.gui.label.area_editor.pos2": "Coin 2", + "litematica.gui.label.area_editor.sub_regions": "Sous-régions (%s)", + + "litematica.gui.label.area_selection_manager.current_selection": "Zone sélectionnée : %s", + + "litematica.gui.label.area_selection_box_count": "Boîtes : %d", + "litematica.gui.label.area_selection_origin": "Origine : %s", + "litematica.gui.label.area_selection.mode.normal": "Normal", + "litematica.gui.label.area_selection.mode.simple": "Simple", + + "litematica.gui.label.block_info.state_client": "État du bloc dans le monde client", + "litematica.gui.label.block_info.state_schematic": "État du bloc dans le monde schématique", + + "litematica.gui.label.block_info_list_type.all": "Tout", + "litematica.gui.label.block_info_list_type.render_layers": "Couches de rendu", + + "litematica.gui.label.easy_place_protocol.auto": "Auto", + "litematica.gui.label.easy_place_protocol.none": "Aucun", + "litematica.gui.label.easy_place_protocol.slabs_only": "Seulement des dalles", + "litematica.gui.label.easy_place_protocol.v2": "Version 2", + "litematica.gui.label.easy_place_protocol.v3": "Version 3", + + "litematica.gui.label.loaded_schematic.modified_on": "§6Modifié le %s§r", + + "litematica.gui.label.material_list.abbr.shulker_box": "SB", + "litematica.gui.label.material_list.title.available": "Disponible", + "litematica.gui.label.material_list.title.item": "Objet", + "litematica.gui.label.material_list.title.missing": "Manquant", + "litematica.gui.label.material_list.title.total": "Total", + + "litematica.gui.label.material_list.multiplier": "Multiplicateur :", + "litematica.gui.label.material_list.name": "Nom", + "litematica.gui.label.material_list.progress": "Progression : %s", + "litematica.gui.label.material_list.progress.done": "Fait %s", + "litematica.gui.label.material_list.progress.mismatch": "Incompatibilité %s", + "litematica.gui.label.material_list.progress.missing": "Manquant %s", + "litematica.gui.label.material_list.total": "Total : %s objets", + + "litematica.gui.label.origin.auto": "Auto", + "litematica.gui.label.origin.manual": "Manuel", + + "litematica.gui.label.paste_nbt_behavior.none": "Aucun", + "litematica.gui.label.paste_nbt_behavior.place_data_modify": "Placer & Modifier les données", + "litematica.gui.label.paste_nbt_behavior.place_clone": "Placer & Cloner", + + "litematica.gui.label.placement_sub.region_name": "Nom de la région : %s", + "litematica.gui.label.placement_sub.region_position": "Position de la région", + "litematica.gui.label.placement_sub.region_size": "Taille de la région : %s", + + "litematica.gui.label.placement_settings.placement_origin": "Origine du placement", + + "litematica.gui.label.render_layers.hotkey": "Raccourci", + "litematica.gui.label.render_layers.hover.hotkey": "Les raccourcis suivant/précédent de la couche affecteront cette limite.\nSi les deux sont désélectionnés, alors les raccourcis affecteront\nla limite la plus proche du joueur.", + + "litematica.gui.label.replace_behavior.all": "Tout", + "litematica.gui.label.replace_behavior.none": "Aucun", + "litematica.gui.label.replace_behavior.with_non_air": "Avec des blocs non-air", + + "litematica.gui.label.schematic_info.schematic_author": "Schéma créé par : §f%s§r", + "litematica.gui.label.schematic_info.description": "Description :", + "litematica.gui.label.schematic_info.enclosing_size": "Taille de l'enclos :", + "litematica.gui.label.schematic_info.enclosing_size_value": "Taille de l'enclos : §f%s§r", + "litematica.gui.label.schematic_info.name": "Nom :", + "litematica.gui.label.schematic_info.region_count": "Régions : §f%d§r", + "litematica.gui.label.schematic_info.time_created": "Créé : §f%s§r", + "litematica.gui.label.schematic_info.time_modified": "Modifié : §f%s§r", + "litematica.gui.label.schematic_info.total_blocks": "Bloc total : §f%d§r", + "litematica.gui.label.schematic_info.total_blocks_and_volume": "Blocs/Volume : §f%d§r/§f%d§r", + "litematica.gui.label.schematic_info.total_volume": "Volume total : Blocs §f%d§r", + + "litematica.gui.label.schematic_load.checkbox.create_placement": "Créer un placement", + "litematica.gui.label.schematic_load.hoverinfo.create_placement": "Créez immédiatement un nouveau placement\net sélectionnez ce placement", + + "litematica.gui.label.schematic_placement.enclosing_size": "Taille de l'enclos : %s", + "litematica.gui.label.schematic_placement.hoverinfo.hold_shift_to_create_as_disabled": "Maintenez la touche Maj enfoncée pour désactiver le placement lors de sa création", + "litematica.gui.label.schematic_placement.in_memory": "EN MÉMOIRE UNIQUEMENT", + "litematica.gui.label.schematic_placement.origin": "Origine : %s", + "litematica.gui.label.schematic_placement.rename_placement": "Renommer le placement :", + "litematica.gui.label.schematic_placement.schematic_file": "Fichier : %s", + "litematica.gui.label.schematic_placement.schematic_name": "Schéma : %s", + "litematica.gui.label.schematic_placement.sub_region_count": "Sous-régions : %s", + "litematica.gui.label.schematic_placement.sub_regions": "Sous-régions (%s) :", + + "litematica.gui.label.schematic_projects.currently_open_project": "Projet actuellement ouvert : %s", + "litematica.gui.label.schematic_projects.origin": "Origine :", + "litematica.gui.label.schematic_projects.project": "Projet :", + "litematica.gui.label.schematic_projects.version": "Version : %s (sur %s)", + "litematica.gui.label.schematic_projects.version_entry": "Ver. %d - %s", + "litematica.gui.label.schematic_projects.version_name": "Nom de la version :", + + "litematica.gui.label.schematic_save.checkbox.ignore_entities": "Ignorer les entités", + "litematica.gui.label.schematic_save.hoverinfo.hold_shift_to_overwrite": "Maintenez la touche Maj enfoncée pour écraser un fichier existant", + + "litematica.gui.label.schematic_verifier.count": "Compter", + "litematica.gui.label.schematic_verifier.expected": "Attendu", + "litematica.gui.label.schematic_verifier.found": "Trouvé", + "litematica.gui.label.schematic_verifier_display_type.all": "Tous (non ignorés)", + "litematica.gui.label.schematic_verifier_display_type.correct_state": "État correct", + "litematica.gui.label.schematic_verifier_display_type.extra": "Blocs supplémentaires", + "litematica.gui.label.schematic_verifier_display_type.missing": "Blocs manquants", + "litematica.gui.label.schematic_verifier_display_type.wrong_blocks": "Mauvais blocs", + "litematica.gui.label.schematic_verifier_display_type.wrong_state": "États incorrects", + "litematica.gui.label.schematic_verifier.status.done_errors": "Mauvais : §cBloc : %s§r, §6État : %s§r, §bManquants : %s§r, §dSupplémentaires : %s§r", + "litematica.gui.label.schematic_verifier.status.done_correct_total": "§aCorrects : %s§r, Total : %s", + "litematica.gui.label.schematic_verifier.status.verifying": "Chunks non vus : %s / %s", + "litematica.gui.label.schematic_verifier.verifier": "Vérificateur de schéma", + + "litematica.gui.label.task.title.remaining_chunks": "%s, chunks restants (%s)", + "litematica.gui.label.task_name.area_analyzer": "Analyseur de zone", + "litematica.gui.label.task_name.delete": "Supprimer la tâche", + "litematica.gui.label.task_name.fill": "Tâche de remplissage", + "litematica.gui.label.task_name.material_list": "Liste des matériaux", + "litematica.gui.label.task_name.paste": "Coller le schéma", + "litematica.gui.label.task_name.save_schematic": "Enregistrer le schéma", + "litematica.gui.label.task_name.verifier": "Vérificateur", + + "litematica.gui.message.confirm_file_deletion": "Voulez-vous supprimer le fichier '%s' ?", + "litematica.gui.message.schematic_projects.confirm_delete_area": "Voulez-vous supprimer la zone \"dernièrement affectée\" ?\nCela supprimera les blocs et entités présents dans la zone que le gestionnaire de projet a récemment placée dans le monde, ou sauvegardée en tant que version. (Essentiellement la \"zone affectée vue en dernier\", de sorte que si vous deviez changer de version, cela ne laisserait pas de blocs derrière de la version précédente.)", + "litematica.gui.message.schematic_projects.confirm_place_to_world": "Voulez-vous placer cette version dans le monde ?\nCela supprimera les blocs présents dans la zone que le gestionnaire de projet a récemment placée dans le monde, ou sauvegardée en tant que version. (Essentiellement la \"zone affectée vue en dernier\", de sorte que si vous deviez changer de version, cela ne laisserait pas de blocs derrière de la version précédente.)", + + "litematica.gui.title.area_editor_normal": "Éditeur de zone (Mode normal/Multi-boîtes)", + "litematica.gui.title.area_editor_normal_schematic_projects": "Éditeur de zone (Zone de schéma §6§lVCS§r)", + "litematica.gui.title.area_editor_simple": "Éditeur de zone (Mode simple)", + "litematica.gui.title.area_editor_sub_region": "Éditeur de zone (Sous-région)", + "litematica.gui.title.area_editor.sub_region_name": "Nom de la sous-région", + "litematica.gui.title.area_selection_manager": "Gestionnaire de sélection de zone", + "litematica.gui.title.configure_schematic_placement": "Configurer le placement du schéma", + "litematica.gui.title.configure_schematic_sub_region": "Configurer la sous-région de placement", + "litematica.gui.title.configs": "Configurations Litematica - %s", + "litematica.gui.title.confirm_file_deletion": "Confirmer la suppression de fichier", + "litematica.gui.title.copy_area_selection": "Copier la sélection de zone '%s'", + "litematica.gui.title.create_area_selection": "Créer une nouvelle sélection de zone", + "litematica.gui.title.create_area_selection_from_placement": "Créer une nouvelle sélection de zone à partir d'un placement de schéma", + "litematica.gui.title.create_directory": "Créer un nouveau répertoire", + "litematica.gui.title.create_in_memory_schematic": "Créer un schéma en mémoire", + "litematica.gui.title.create_schematic_project": "Créer un nouveau projet de schéma", + "litematica.gui.title.litematica_main_menu": "Litematica %s", + "litematica.gui.title.load_schematic": "Charger le schéma", + "litematica.gui.title.manage_loaded_schematics": "Gérer les schémas chargés", + "litematica.gui.title.manage_schematic_placements": "Gérer les placements de schémas", + "litematica.gui.title.material_list.area_analyzer": "Analyse de zone pour la sélection '%s'", + "litematica.gui.title.material_list.placement": "Liste des matériaux pour le placement '%s'", + "litematica.gui.title.material_list.schematic": "Liste des matériaux pour le schéma '%s' (%s sur %s régions)", + "litematica.gui.title.material_list.select_schematic_regions": "Sélectionnez les sous-régions pour la liste des matériaux de '%s'", + "litematica.gui.title.rename_area_selection": "Renommer la sélection de zone", + "litematica.gui.title.rename_area_sub_region": "Renommer la sous-région", + "litematica.gui.title.rename_schematic": "Renommer le schéma", + "litematica.gui.title.create_schematic_from_selection": "Enregistrer la zone actuellement sélectionnée comme schéma", + "litematica.gui.title.save_exported_schematic": "Enregistrer un %s exporté de '%s'", + "litematica.gui.title.save_imported_schematic": "Enregistrer un schéma importé", + "litematica.gui.title.save_schematic_from_memory": "Enregistrer un schéma en mémoire dans un fichier", + "litematica.gui.title.save_schematic_filename": "Nom du fichier du schéma", + "litematica.gui.title.schematic_browser": "Navigateur de schémas", + "litematica.gui.title.schematic_manager": "Gestionnaire de schémas", + "litematica.gui.title.schematic_project_manager": "Gestionnaire de projets de schémas VCS", + "litematica.gui.title.schematic_projects.confirm_delete_area": "Confirmer la suppression de la zone", + "litematica.gui.title.schematic_projects.confirm_place_to_world": "Confirmer l'action de placement dans le monde", + "litematica.gui.title.schematic_projects.save_new_version": "Enregistrer une nouvelle version de schéma", + "litematica.gui.title.schematic_projects_browser": "Navigateur de projets de schémas VCS", + "litematica.gui.title.schematic_verifier": "Vérificateur de schéma pour '%s'", + "litematica.gui.title.schematic_verifier_errors": "Erreurs de vérificateur de schéma", + "litematica.gui.title.task_manager": "Gestionnaire de tâches", + + "litematica.hud.area_selection.box_count": "Boîtes: %s", + "litematica.hud.area_selection.dimensions_position": "Dim: %s - p1: %s, p2: %s", + "litematica.hud.area_selection.mode.corners": "Coins", + "litematica.hud.area_selection.mode.expand": "Étendre", + "litematica.hud.area_selection.origin": "Origine: %s", + "litematica.hud.area_selection.selected_area_normal": "Zone: %s", + "litematica.hud.area_selection.selected_area_simple": "Zone [§6Mode simple§r]: %s", + "litematica.hud.area_selection.selected_sub_region": "Sous-région: %s", + "litematica.hud.area_selection.selection_corners_mode": "Mode Coins: %s", + + "litematica.hud.delete.target_mode": "Mode cible de suppression: %s", + "litematica.hud.delete.target_mode.area": "Zone actuelle", + "litematica.hud.delete.target_mode.placement": "Placement actuel", + + "litematica.hud.misc.easy_place_mode_enabled": "Mode Placement Facile §aON§r", + "litematica.hud.misc.none_brackets": "", + "litematica.hud.misc.placement_restriction_mode_enabled": "Mode Restriction de Placement §aON§r", + "litematica.hud.misc.render_layer_mode": "Mode de calque: %s - %s", + "litematica.hud.misc.render_layer_mode_all": "Mode de calque: %s", + "litematica.hud.misc.renderer_status": "Rendus: A: %s S: %s B: %s O: %s SEL: %s", + "litematica.hud.misc.schematic_paste.data_restore_mode": "Mode de restauration des données: §b%s", + "litematica.hud.misc.schematic_paste.replace_mode": "Remplacer les blocs: %s", + + "litematica.hud.schematic_placement.hover_info.lock_coordinate": "Verrouiller cette coordonnée\nCela permet de modifier les autres coordonnées\nsans affecter les coordonnées verrouillées", + "litematica.hud.schematic_placement.hover_info.placement_locked": "Ce placement a été verrouillé et ne peut pas\nêtre modifié sans être déverrouillé au préalable", + "litematica.hud.schematic_placement.hover_info.placement_modified": "Ce placement a été modifié", + "litematica.hud.schematic_placement.hover_info.placement_sub_region_modified": "Cette sous-région a été modifiée", + "litematica.hud.schematic_placement.selected_placement": "Placement", + "litematica.hud.schematic_placement.selected_sub_region": "Sous-région", + "litematica.hud.schematic_placement.sub_region_count": "Régions", + "litematica.hud.schematic_placement.sub_region_modified": "Modifié", + "litematica.hud.schematic_placement.sub_region_origin": "Origine de la région: %s", + "litematica.hud.schematic_placement.sub_regions_modified": "Régions modifiées", + + "litematica.hud.selected_mode": "Mode", + + "litematica.hud.schematic_projects.current_version_date": "Date: %s", + "litematica.hud.schematic_projects.current_version": "Version: %s/%s - name: %s", + "litematica.hud.schematic_projects.no_project_open": "", + "litematica.hud.schematic_projects.no_versions": "", + "litematica.hud.schematic_projects.origin": "Origine du projet: %s", + "litematica.hud.schematic_projects.project_name": "Projet: %s", + "litematica.hud.schematic_projects_mode": "§6Mode Schematic VCS§r", + + "litematica.info.material_list": "- La touche de raccourci de la liste des matériaux ouvrira la dernière liste consultée,\n si elle est sauvegardée\n- Pour basculer vers une liste de matériaux différente, ouvrez-en une via\n le bouton GUI dans la configuration du placement ou\n le navigateur de schémas\n- La liste stockée/dernièrement consultée est également oubliée\n si le Placement Schematic sélectionné est changé\n- S'il n'y a pas encore de liste de matériaux consultée,\n alors le Placement sélectionné est utilisé, s'il y en a un", + + "litematica.label.alignment.center": "Centre", + "litematica.label.alignment.top_center": "Haut Centre", + + "litematica.label.none_lower": "aucun", + "litematica.label.no": "non", + "litematica.label.yes": "oui", + + "litematica.message.error.area_deletion_aborted": "Suppression de la zone interrompue ou annulée", + "litematica.message.error.empty_area_selection": "Sélection de zone vide (pas de boîtes)", + "litematica.message.error.invalid_schematic_name": "Nom de schéma invalide '%s'", + "litematica.message.error.no_area_selected": "§cAucune zone sélectionnée§r", + "litematica.message.error.no_placement_selected": "§cAucun placement sélectionné§r", + "litematica.message.error.only_works_in_single_player": "§cCette opération ne fonctionne que en mode joueur unique§r", + "litematica.message.error.move.pending_tasks": "§cImpossible de démarrer une opération de déplacement tant qu'il y a des tâches en attente§r", + "litematica.message.error.placement_paste_outside_world": "Le placement ne peut pas être collé à la position actuelle, car il dépasse les limites du monde", + "litematica.message.error.schematic_paste_failed": "§cÉchec du collage du schéma dans le monde§r", + "litematica.message.error.schematic_save_failed": "Échec de l'enregistrement du schéma dans le fichier '%s'", + "litematica.message.error.schematic_save_interrupted": "Enregistrement du schéma interrompu ou arrêté", + "litematica.message.error.schematic_save_no_area_selected": "§cÉchec de l'enregistrement du schéma - aucune zone sélectionnée§r", + "litematica.message.warn.pickblock.no_suitable_slot_found": "Aucun emplacement de barre d'accès rapide adapté trouvé pour le bloc à ramasser!\\nVérifiez la configuration Generic -> §epickBlockableSlots§r.\\nDe plus, en fonction des configurations §epickBlockAvoid*§6, la fonction de ramassage peut refuser de remplacer tout outil ou autre élément endommageable dans ces emplacements.", + "litematica.message.warn.pickblock.no_valid_slots_configured": "Aucun emplacement de barre d'accès rapide défini dans la configuration Generic -> §epickBlockableSlots§6 !", + + "litematica.message.added_selection_box": "Ajouté une nouvelle boîte de sélection à %s", + "litematica.message.area_clear_fail": "§cImpossible de vider la ou les zones§r", + "litematica.message.area_cleared": "Zone vidée", + "litematica.message.area_filled": "Zone remplie", + "litematica.message.area_fill_fail": "Échec du remplissage de la zone", + "litematica.message.area_selections.selection_created_from_placement": "Créé une nouvelle sélection à partir du placement '%s'", + "litematica.message.easy_place_fail": "§6Action empêchée par le mode Placement Facile", + "litematica.message.grabbed_element_for_moving": "Élément saisi pour le déplacement", + "litematica.message.in_memory_schematic_created": "Créé un schéma en mémoire en tant que '%s'", + "litematica.message.material_list.material_cache_cleared": "Cache des matériaux effacé", + "litematica.message.material_list_written_to_file": "Liste des matériaux écrite dans le fichier '%s'", + "litematica.message.moved_area_origin": "Déplacé le point d'origine de la zone de %s => %s", + "litematica.message.moved_selection": "Déplacé la sélection actuelle de %s => %s", + "litematica.message.placement.cant_modify_is_locked": "§cLe placement est verrouillé et ne peut pas être modifié§r", + "litematica.message.placement.moved_placement_origin": "Déplacé l'origine du placement de %s => %s", + "litematica.message.placement.moved_subregion_to": "Déplacé la sous-région à %s", + "litematica.message.placement_restriction_fail": "§6Action empêchée par le mode Restriction de Placement", + "litematica.message.removed_area_origin": "Supprimé le point d'origine de la zone explicite/manuelle", + "litematica.message.removed_selection_box": "Boîte de sélection %s supprimée", + "litematica.message.scheduled_task_added": "Tâche planifiée ajoutée...", + "litematica.message.schematic_exported_as": "Schéma exporté en tant que '%s'", + "litematica.message.schematic_pasted": "Schéma collé dans le monde", + "litematica.message.schematic_pasted_using_fill_and_setblock": "Schéma collé en utilisant les commandes fill §b%s§r et setblock §b%s§r", + "litematica.message.schematic_pasted_using_setblock": "Schéma collé en utilisant les commandes setblock §b%s§r", + "litematica.message.schematic_pasted_using_world_edit": "Schéma collé en utilisant les commandes World Edit //set §b%s§r", + "litematica.message.schematic_placement_created": "Placement créé pour '%s'", + "litematica.message.schematic_preview_cancelled": "Tâche d'aperçu annulée", + "litematica.message.schematic_read_from_file_success": "Schéma chargé à partir du fichier '%s'", + "litematica.message.schematic_rendering_refreshed": "Rendu du schéma actualisé", + "litematica.message.schematic_saved_as": "Schéma enregistré en tant que '%s'", + "litematica.message.schematic_save_task_created": "Tâche d'enregistrement du schéma créée", + "litematica.message.set_area_origin": "Définir le point d'origine de la zone à %s", + "litematica.message.set_selection_box_point": "Définir/déplacer le point %d à %s", + "litematica.message.toggled": "Basculé %s %s", + "litematica.message.value.on": "ON", + "litematica.message.value.off": "OFF", + + "litematica.message.schematic_projects.project_created": "Projet '%s' créé", + "litematica.message.schematic_projects.project_loaded": "Projet '%s' chargé", + "litematica.message.schematic_projects.version_saved": "Nouvelle version (#%s) enregistrée en tant que '%s'", + + "litematica.message.warn.area_selection.browser_open_in_simple_mode": "Note : Vous êtes actuellement en mode de sélection de zone simple", + "litematica.message.warn.layer_mode_currently_at": "Note : Vous êtes actuellement en mode de rendu de couche '%s'", + "litematica.message.warn.main_rendering_disabled": "Attention : Le rendu principal est actuellement désactivé\nVoir Visuals -> %s, ou Hotkeys -> %s ['%s']", + "litematica.message.warn.schematic_blocks_rendering_disabled": "Attention : Le rendu des blocs de schéma est actuellement désactivé\nVoir Visuals -> %s, ou Hotkeys -> %s ['%s']", + "litematica.message.warn.schematic_load_non_litematica": "Attention : Lorsque vous chargez directement des schémas non-Litematica, les placements créés ne seront pas persistants.\nDe plus, si vous devez charger le schéma plusieurs fois, la latence de conversion de type de schéma (pour les schémas volumineux) se produira à chaque chargement.\n\nIl est donc recommandé de soit importer le schéma et de l'enregistrer dans le format Litematica via le menu Gestionnaire de schémas, ou mieux encore, de coller le schéma d'origine dans un monde temporaire à l'aide de MCEdit ou du mode Coller dans Litematica, puis de créer un nouveau schéma Litematica à partir de celui-ci, de préférence en utilisant plusieurs sous-régions pour capturer étroitement la construction, le cas échéant.", + "litematica.message.warn.schematic_rebuild_placement_not_selected": "Le placement ciblé n'est actuellement pas sélectionné. La touche de raccourci Remplacer tout ne fonctionne que sur les sous-régions actuellement sélectionnées du placement sur lequel vous cliquez. Ainsi, pour remplacer les blocs dans une seule sous-région, sélectionnez cette sous-région. Pour remplacer dans l'ensemble du schéma (toutes les sous-régions), sélectionnez l'ensemble du placement et non pas une sous-région de celui-ci. Les blocs ne sont également remplacés que dans la zone limitée par le paramètre actuel des couches de rendu.", + "litematica.message.warn.schematic_rendering_disabled": "Attention : Le rendu de schéma est actuellement désactivé\nVoir Visuals -> %s, ou Hotkeys -> %s ['%s']", + "litematica.message.warn.schematic_verifier.overlay_disabled": "Attention : Le rendu de l'overlay du vérificateur est actuellement désactivé ! Voir Infos sur les superpositions -> %s (ou Hotkeys -> %s ['%s'])", + + "litematica.message.warning.invalid_number": "Entrée invalide pour un nombre '%s'", + "litematica.message.warning.schematic_projects_hidden": "Attention : Le système de contrôle de version du schéma est actuellement masqué. En général, vous NE DEVRIEZ PAS utiliser ceci, sauf si vous savez vraiment comment cela fonctionne et modifie certains comportements du mod. Il est destiné à un travail de conception itératif, en place, où il est nécessaire de basculer entre différentes versions de la construction en place (= supprimer et remplacer la version précédente). Si vous souhaitez l'utiliser, activez l'option Generic -> unhideSchematicVCS", + + "litematica.warning.area_editor.area_rendering_disabled": "Note : Le rendu des boîtes de sélection de zone est actuellement désactivé\nVoir Visuals -> %s, ou Hotkeys -> %s ['%s']", + + "litematica.tool_hud.block_1": "Bloc: %s", + "litematica.tool_hud.block_2": "Remplacer: %s", + "litematica.tool_hud.facing": "Orientation: %s", + + "litematica.tool_mode.name.area_selection": "Sélection de zone", + "litematica.tool_mode.name.delete": "Supprimer", + "litematica.tool_mode.name.fill": "Remplir", + "litematica.tool_mode.name.grid_paste": "Coller un schéma en grille dans le monde", + "litematica.tool_mode.name.move": "Déplacer", + "litematica.tool_mode.name.paste_schematic": "Coller un schéma dans le monde", + "litematica.tool_mode.name.rebuild": "Modifier un schéma", + "litematica.tool_mode.name.replace_block": "Remplacer le bloc", + "litematica.tool_mode.name.schematic_placement": "Placement de schéma" +} \ No newline at end of file diff --git a/src/main/resources/assets/litematica/lang/ru_ru.json b/src/main/resources/assets/litematica/lang/ru_ru.json index 7800ffb20a..59011e523b 100644 --- a/src/main/resources/assets/litematica/lang/ru_ru.json +++ b/src/main/resources/assets/litematica/lang/ru_ru.json @@ -337,7 +337,7 @@ "litematica.gui.title.area_selection_manager": "Менеджер областей выделения", "litematica.gui.title.configure_schematic_placement": "Настройка размещения схемы", "litematica.gui.title.configure_schematic_sub_region": "Настройка размещения подрегиона", - "litematica.gui.title.configs": "Настройки Litematica", + "litematica.gui.title.configs": "Настройки Litematica - %s", "litematica.gui.title.confirm_file_deletion": "Подтвердите удаление файла", "litematica.gui.title.copy_area_selection": "Копировать область выделения \"%s\"", "litematica.gui.title.create_area_selection": "Создать новую область выделения", diff --git a/src/main/resources/assets/litematica/lang/uk_ua.json b/src/main/resources/assets/litematica/lang/uk_ua.json index 93444a1584..56815178b9 100644 --- a/src/main/resources/assets/litematica/lang/uk_ua.json +++ b/src/main/resources/assets/litematica/lang/uk_ua.json @@ -285,7 +285,7 @@ "litematica.gui.title.area_selection_manager": "Менеджер з вибору району", "litematica.gui.title.configure_schematic_placement": "Налаштувати розташування схеми", "litematica.gui.title.configure_schematic_sub_region": "Налаштувати підрегіон розміщення", - "litematica.gui.title.configs": "Конфігурації Litematica", + "litematica.gui.title.configs": "Конфігурації Litematica - %s", "litematica.gui.title.confirm_file_deletion": "Підтвердити видалення файлу", "litematica.gui.title.copy_area_selection": "Копіювати виділення області \"%s\"", "litematica.gui.title.create_area_selection": "Створіть нове виділення області", diff --git a/src/main/resources/assets/litematica/lang/zh_cn.json b/src/main/resources/assets/litematica/lang/zh_cn.json index 569b618961..ec0839248e 100644 --- a/src/main/resources/assets/litematica/lang/zh_cn.json +++ b/src/main/resources/assets/litematica/lang/zh_cn.json @@ -337,7 +337,7 @@ "litematica.gui.title.area_selection_manager": "区域选择管理器", "litematica.gui.title.configure_schematic_placement": "配置原理图放置", "litematica.gui.title.configure_schematic_sub_region": "配置放置子区域", - "litematica.gui.title.configs": "投影配置", + "litematica.gui.title.configs": "投影配置 - %s", "litematica.gui.title.confirm_file_deletion": "确认文件删除", "litematica.gui.title.copy_area_selection": "复制区域选择 '%s'", "litematica.gui.title.create_area_selection": "新建区域选择", diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 4b4383d971..3b4ab2b74c 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -34,7 +34,7 @@ ], "depends": { - "minecraft": ">=1.20.3 <=1.20.4", - "malilib": ">=0.18.0" + "minecraft": ">=1.20.5", + "malilib": ">=0.19.0" } }