diff --git a/.github/workflows/build-prs.yml b/.github/workflows/build-prs.yml index 32717e93ef..275a91f5d0 100644 --- a/.github/workflows/build-prs.yml +++ b/.github/workflows/build-prs.yml @@ -31,17 +31,13 @@ jobs: run: git switch -C pr-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.ref }} - - name: Validate wrapper - uses: gradle/actions/wrapper-validation@v3 - - name: Setup JDK 21 - uses: actions/setup-java@v2 + uses: neoforged/actions/setup-java@main with: - java-version: '21' - distribution: 'temurin' + java-version: 21 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: false @@ -52,10 +48,12 @@ jobs: run: ./gradlew assemble checkFormatting - name: Run JCC + if: ${{ ! startsWith(github.event.pull_request.head.ref, 'refs/heads/port/') }} run: ./gradlew checkJarCompatibility - name: Upload JCC + if: ${{ ! startsWith(github.event.pull_request.head.ref, 'refs/heads/port/') }} uses: neoforged/action-jar-compatibility/upload@v1 - name: Publish artifacts - uses: neoforged/action-pr-publishing/upload@v1 + uses: neoforged/action-pr-publishing/upload@v1 \ No newline at end of file diff --git a/.github/workflows/check-local-changes.yml b/.github/workflows/check-local-changes.yml index f40a77a4cf..ef101ceacd 100644 --- a/.github/workflows/check-local-changes.yml +++ b/.github/workflows/check-local-changes.yml @@ -25,13 +25,12 @@ jobs: git switch -C pr-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.ref }} - name: Setup JDK 21 - uses: actions/setup-java@v2 + uses: neoforged/actions/setup-java@main with: - java-version: '21' - distribution: 'temurin' + java-version: 21 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: false diff --git a/.github/workflows/publish-jcc.yml b/.github/workflows/publish-jcc.yml index f4c78789bc..477bf720c7 100644 --- a/.github/workflows/publish-jcc.yml +++ b/.github/workflows/publish-jcc.yml @@ -11,7 +11,7 @@ on: jobs: publish-jcc: - if: true + if: ${{ ! startsWith(github.event.workflow_run.head_branch, 'port/') }} uses: neoforged/actions/.github/workflows/publish-jcc.yml@main with: beta_version_pattern: .*-beta.* diff --git a/.github/workflows/test-prs.yml b/.github/workflows/test-prs.yml index 0fff8674c4..51afdcddad 100644 --- a/.github/workflows/test-prs.yml +++ b/.github/workflows/test-prs.yml @@ -29,13 +29,12 @@ jobs: git switch -C pr-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.ref }} - name: Setup JDK 21 - uses: actions/setup-java@v2 + uses: neoforged/actions/setup-java@main with: - java-version: '21' - distribution: 'temurin' + java-version: 21 - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 with: cache-read-only: false diff --git a/coremods/build.gradle b/coremods/build.gradle new file mode 100644 index 0000000000..3d942a4701 --- /dev/null +++ b/coremods/build.gradle @@ -0,0 +1,46 @@ +plugins { + id 'java-library' + id 'com.diffplug.spotless' + id 'net.neoforged.licenser' + id 'neoforge.formatting-conventions' +} + +repositories { + maven { url = 'https://maven.neoforged.net/releases' } + maven { + name 'Mojang' + url 'https://libraries.minecraft.net' + } + mavenCentral() +} + +jar { + manifest { + attributes( + "Automatic-Module-Name": "neoforge.coremods", + FMLModType: "LIBRARY", + ) + } +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(project.java_version)) + } +} + +dependencies { + compileOnly "org.jetbrains:annotations:${project.jetbrains_annotations_version}" + compileOnly "com.google.code.gson:gson:${gson_version}" + compileOnly "org.slf4j:slf4j-api:${slf4j_api_version}" + compileOnly "net.neoforged.fancymodloader:loader:${project.fancy_mod_loader_version}" +} + +license { + header = rootProject.file('codeformat/HEADER.txt') + include '**/*.java' +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' +} diff --git a/coremods/src/main/java/net/neoforged/neoforge/coremods/CoremodUtils.java b/coremods/src/main/java/net/neoforged/neoforge/coremods/CoremodUtils.java new file mode 100644 index 0000000000..52a63c2ee4 --- /dev/null +++ b/coremods/src/main/java/net/neoforged/neoforge/coremods/CoremodUtils.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.coremods; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodNode; + +final class CoremodUtils { + private static final Gson GSON = new Gson(); + + CoremodUtils() {} + + static T loadResource(String filename, TypeToken type) { + var stream = NeoForgeCoreMod.class.getResourceAsStream(filename); + if (stream == null) { + throw new IllegalStateException("Missing resource: " + filename); + } + try (var reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) { + return GSON.fromJson(reader, type); + } catch (IOException e) { + throw new IllegalStateException("Failed to read JSON resource " + filename); + } + } + + static T loadResource(String filename, Class type) { + return loadResource(filename, TypeToken.get(type)); + } + + static FieldNode getFieldByName(ClassNode classNode, String fieldName) { + FieldNode foundField = null; + for (var fieldNode : classNode.fields) { + if (Objects.equals(fieldNode.name, fieldName)) { + if (foundField == null) { + foundField = fieldNode; + } else { + throw new IllegalStateException("Found multiple fields with name " + fieldName + " in " + classNode.name); + } + } + } + if (foundField == null) { + throw new IllegalStateException("No field with name " + fieldName + " found in class " + classNode.name); + } + return foundField; + } + + static MethodNode getMethodByDescriptor(ClassNode classNode, @Nullable String methodName, String methodSignature) { + MethodNode foundMethod = null; + for (var methodNode : classNode.methods) { + if (Objects.equals(methodNode.desc, methodSignature) + && (methodName == null || Objects.equals(methodNode.name, methodName))) { + if (foundMethod == null) { + foundMethod = methodNode; + } else { + throw new IllegalStateException("Found duplicate method with signature " + methodSignature + " in " + classNode.name); + } + } + } + + if (foundMethod == null) { + if (methodName != null) { + throw new IllegalStateException("Unable to find method " + methodSignature + " with name " + methodName + " in " + classNode.name); + } else { + throw new IllegalStateException("Unable to find method " + methodSignature + " in " + classNode.name); + } + } + return foundMethod; + } +} diff --git a/coremods/src/main/java/net/neoforged/neoforge/coremods/MethodRedirector.java b/coremods/src/main/java/net/neoforged/neoforge/coremods/MethodRedirector.java new file mode 100644 index 0000000000..8db3d7486d --- /dev/null +++ b/coremods/src/main/java/net/neoforged/neoforge/coremods/MethodRedirector.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.coremods; + +import cpw.mods.modlauncher.api.ITransformer; +import cpw.mods.modlauncher.api.ITransformerVotingContext; +import cpw.mods.modlauncher.api.TargetType; +import cpw.mods.modlauncher.api.TransformerVoteResult; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodInsnNode; + +/** + * Redirect calls to one method to another. + */ +public class MethodRedirector implements ITransformer { + private final Map> redirectionsByClass = new HashMap<>(); + private final Set> targets = new HashSet<>(); + + private static final List REDIRECTIONS = List.of( + new MethodRedirection( + Opcodes.INVOKEVIRTUAL, + "finalizeSpawn", + "(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/MobSpawnType;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;", + "finalize_spawn_targets.json", + methodInsnNode -> new MethodInsnNode( + Opcodes.INVOKESTATIC, + "net/neoforged/neoforge/event/EventHooks", + "finalizeMobSpawn", + "(Lnet/minecraft/world/entity/Mob;Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/MobSpawnType;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;", + false))); + + public MethodRedirector() { + for (var redirection : REDIRECTIONS) { + var targetClassNames = CoremodUtils.loadResource(redirection.targetClassListFile, String[].class); + for (var targetClassName : targetClassNames) { + targets.add(Target.targetClass(targetClassName)); + var redirections = redirectionsByClass.computeIfAbsent(targetClassName, s -> new ArrayList<>()); + redirections.add(redirection); + } + } + } + + @Override + public TargetType getTargetType() { + return TargetType.CLASS; + } + + @Override + public Set> targets() { + return targets; + } + + @Override + public ClassNode transform(ClassNode classNode, ITransformerVotingContext votingContext) { + var redirections = redirectionsByClass.getOrDefault(classNode.name, Collections.emptyList()); + + var methods = classNode.methods; + for (var method : methods) { + var instr = method.instructions; + for (var i = 0; i < instr.size(); i++) { + var node = instr.get(i); + if (node instanceof MethodInsnNode methodInsnNode) { + for (var redirection : redirections) { + if (redirection.invokeOpCode == methodInsnNode.getOpcode() + && redirection.methodName.equals(methodInsnNode.name) + && redirection.methodDescriptor.equals(methodInsnNode.desc)) { + // Found a match for the target method + instr.set( + methodInsnNode, + redirection.redirector.apply(methodInsnNode)); + } + } + } + } + } + return classNode; + } + + @Override + public TransformerVoteResult castVote(ITransformerVotingContext context) { + return TransformerVoteResult.YES; + } + + private record MethodRedirection( + int invokeOpCode, + String methodName, + String methodDescriptor, + String targetClassListFile, + Function redirector) {} +} diff --git a/coremods/src/main/java/net/neoforged/neoforge/coremods/NeoForgeCoreMod.java b/coremods/src/main/java/net/neoforged/neoforge/coremods/NeoForgeCoreMod.java new file mode 100644 index 0000000000..ba68da09ff --- /dev/null +++ b/coremods/src/main/java/net/neoforged/neoforge/coremods/NeoForgeCoreMod.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.coremods; + +import cpw.mods.modlauncher.api.ITransformer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import net.neoforged.neoforgespi.coremod.ICoreMod; + +public class NeoForgeCoreMod implements ICoreMod { + @Override + public Iterable> getTransformers() { + List> transformers = new ArrayList<>(); + transformers.add(new ReplaceFieldWithGetterAccess("net.minecraft.world.level.biome.Biome", Map.of( + "climateSettings", "getModifiedClimateSettings", + "specialEffects", "getModifiedSpecialEffects"))); + transformers.add(new ReplaceFieldWithGetterAccess("net.minecraft.world.level.levelgen.structure.Structure", Map.of( + "settings", "getModifiedStructureSettings"))); + transformers.add(new ReplaceFieldWithGetterAccess("net.minecraft.world.level.block.FlowerPotBlock", Map.of( + "potted", "getPotted"))); + + transformers.add(new MethodRedirector()); + + return transformers; + } +} diff --git a/coremods/src/main/java/net/neoforged/neoforge/coremods/ReplaceFieldComparisonWithInstanceOf.java b/coremods/src/main/java/net/neoforged/neoforge/coremods/ReplaceFieldComparisonWithInstanceOf.java new file mode 100644 index 0000000000..6c8e9ff121 --- /dev/null +++ b/coremods/src/main/java/net/neoforged/neoforge/coremods/ReplaceFieldComparisonWithInstanceOf.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.coremods; + +import cpw.mods.modlauncher.api.ITransformer; +import cpw.mods.modlauncher.api.ITransformerVotingContext; +import cpw.mods.modlauncher.api.TargetType; +import cpw.mods.modlauncher.api.TransformerVoteResult; +import java.util.List; +import java.util.Set; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TypeInsnNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Replaces code such as {@code itemstack.getItem() == Items.CROSSBOW} with instanceof checks such + * as {@code itemstack.getItem() instanceof CrossbowItem}. + * This transformer targets a set of methods to replace the occurrence of a single field-comparison. + */ +public class ReplaceFieldComparisonWithInstanceOf implements ITransformer { + private static final Logger LOG = LoggerFactory.getLogger(ReplaceFieldComparisonWithInstanceOf.class); + + private final Set> targets; + private final String fieldOwner; + private final String fieldName; + private final String replacementClassName; + + /** + * @param fieldOwner The class that owns {@code fieldName} + * @param fieldName The name of a field in {@code fieldOwner} + * @param replacementClassName Reference comparisons against {@code fieldName} in {@code fieldOwner} are replaced + * by instanceof checks against this class. + * @param methodsToScan The methods to scan + */ + public ReplaceFieldComparisonWithInstanceOf(String fieldOwner, + String fieldName, + String replacementClassName, + List> methodsToScan) { + this.targets = Set.copyOf(methodsToScan); + + this.fieldOwner = fieldOwner; + this.fieldName = fieldName; + this.replacementClassName = replacementClassName; + } + + @Override + public TargetType getTargetType() { + return TargetType.METHOD; + } + + @Override + public Set> targets() { + return targets; + } + + @Override + public MethodNode transform(MethodNode methodNode, ITransformerVotingContext votingContext) { + var count = 0; + for (var node = methodNode.instructions.getFirst(); node != null; node = node.getNext()) { + if (node instanceof JumpInsnNode jumpNode && (jumpNode.getOpcode() == Opcodes.IF_ACMPEQ || jumpNode.getOpcode() == Opcodes.IF_ACMPNE)) { + if (node.getPrevious() instanceof FieldInsnNode fieldAccessNode && (fieldAccessNode.getOpcode() == Opcodes.GETSTATIC || fieldAccessNode.getOpcode() == Opcodes.GETFIELD)) { + if (fieldAccessNode.owner.equals(fieldOwner) && fieldAccessNode.name.equals(fieldName)) { + methodNode.instructions.set(fieldAccessNode, new TypeInsnNode(Opcodes.INSTANCEOF, replacementClassName)); + methodNode.instructions.set(jumpNode, new JumpInsnNode(jumpNode.getOpcode() == Opcodes.IF_ACMPEQ ? Opcodes.IFNE : Opcodes.IFEQ, jumpNode.label)); + count++; + } + } + } + } + + LOG.trace("Transforming: {}.", methodNode.name); + LOG.trace("field_to_instance: Replaced {} checks", count); + + return methodNode; + } + + @Override + public TransformerVoteResult castVote(ITransformerVotingContext context) { + return TransformerVoteResult.YES; + } +} diff --git a/coremods/src/main/java/net/neoforged/neoforge/coremods/ReplaceFieldWithGetterAccess.java b/coremods/src/main/java/net/neoforged/neoforge/coremods/ReplaceFieldWithGetterAccess.java new file mode 100644 index 0000000000..44c8f8a57e --- /dev/null +++ b/coremods/src/main/java/net/neoforged/neoforge/coremods/ReplaceFieldWithGetterAccess.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.coremods; + +import cpw.mods.modlauncher.api.ITransformer; +import cpw.mods.modlauncher.api.ITransformerVotingContext; +import cpw.mods.modlauncher.api.TargetType; +import cpw.mods.modlauncher.api.TransformerVoteResult; +import java.lang.reflect.Modifier; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; + +/** + * Replaces direct field access in a class with access to the getter. + *

+ * The field specified by fieldName must be private and non-static. + * The method-call the field-access is redirected to does not take any parameters and returns an object of the + * same type as the field. + * If no methodName is passed, any method matching the described signature will be used as callable method. + */ +public class ReplaceFieldWithGetterAccess implements ITransformer { + private final Map fieldToMethod; + private final Set> targets; + + public ReplaceFieldWithGetterAccess(String className, Map fieldToMethod) { + this.targets = Set.of(Target.targetClass(className)); + this.fieldToMethod = fieldToMethod; + } + + @Override + public TargetType getTargetType() { + return TargetType.CLASS; + } + + @Override + public Set> targets() { + return targets; + } + + @Override + public ClassNode transform(ClassNode input, ITransformerVotingContext context) { + for (var entry : fieldToMethod.entrySet()) { + redirectFieldToMethod(input, entry.getKey(), entry.getValue()); + } + + return input; + } + + @Override + public TransformerVoteResult castVote(ITransformerVotingContext context) { + return TransformerVoteResult.YES; + } + + private static void redirectFieldToMethod(ClassNode classNode, String fieldName, @Nullable String methodName) { + var foundField = CoremodUtils.getFieldByName(classNode, fieldName); + + if (!Modifier.isPrivate(foundField.access) || Modifier.isStatic(foundField.access)) { + throw new IllegalStateException("Field " + fieldName + " in " + classNode.name + " is not private and an instance field"); + } + + String methodDescriptor = "()" + foundField.desc; + + var foundMethod = CoremodUtils.getMethodByDescriptor(classNode, methodName, methodDescriptor); + + for (var methodNode : classNode.methods) { + // skip the found getter method + if (methodNode != foundMethod && !Objects.equals(methodNode.desc, methodDescriptor)) { + var iterator = methodNode.instructions.iterator(); + while (iterator.hasNext()) { + var insnNode = iterator.next(); + if (insnNode.getOpcode() == Opcodes.GETFIELD) { + FieldInsnNode fieldInsnNode = (FieldInsnNode) insnNode; + if (Objects.equals(fieldInsnNode.name, fieldName)) { + iterator.remove(); + MethodInsnNode replace = new MethodInsnNode(Opcodes.INVOKEVIRTUAL, classNode.name, foundMethod.name, foundMethod.desc, false); + iterator.add(replace); + } + } + } + } + } + } +} diff --git a/coremods/src/main/java/net/neoforged/neoforge/coremods/package-info.java b/coremods/src/main/java/net/neoforged/neoforge/coremods/package-info.java new file mode 100644 index 0000000000..4bf00aa98a --- /dev/null +++ b/coremods/src/main/java/net/neoforged/neoforge/coremods/package-info.java @@ -0,0 +1,11 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +@ParametersAreNonnullByDefault +@ApiStatus.Internal +package net.neoforged.neoforge.coremods; + +import javax.annotation.ParametersAreNonnullByDefault; +import org.jetbrains.annotations.ApiStatus; diff --git a/coremods/src/main/resources/META-INF/MANIFEST.MF b/coremods/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..72a31477b2 --- /dev/null +++ b/coremods/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: neoforge.coremods +FMLModType: LIBRARY diff --git a/coremods/src/main/resources/META-INF/services/net.neoforged.neoforgespi.coremod.ICoreMod b/coremods/src/main/resources/META-INF/services/net.neoforged.neoforgespi.coremod.ICoreMod new file mode 100644 index 0000000000..a1990f6369 --- /dev/null +++ b/coremods/src/main/resources/META-INF/services/net.neoforged.neoforgespi.coremod.ICoreMod @@ -0,0 +1 @@ +net.neoforged.neoforge.coremods.NeoForgeCoreMod \ No newline at end of file diff --git a/src/main/resources/coremods/finalize_spawn_targets.json b/coremods/src/main/resources/net/neoforged/neoforge/coremods/finalize_spawn_targets.json similarity index 100% rename from src/main/resources/coremods/finalize_spawn_targets.json rename to coremods/src/main/resources/net/neoforged/neoforge/coremods/finalize_spawn_targets.json diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index d34d06f231..eea2cf6d4b 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -12,20 +12,21 @@ Contributing to NeoForge 1. Have preliminary discussions on Discord (`#neoforge-github`) 2. Fork the repository 3. Check out your fork -4. Make a branch -5. Run `gradlew setup` from the project root to decompile sources and apply current patches -6. Import project into your IDE (IntelliJ/Eclipse) or Reload Gradle Project -7. Modify the patched Minecraft sources in `projects/neoforge/src/main/java` as needed. The unmodified sources are available in `projects/base/src/main/java` for your reference. Do not modify these. -8. Test your changes +4. Fetch tags from the upstream repository by running `git remote add upstream https://github.com/neoforged/NeoForge.git` followed by `git fetch upstream --tags` +5. Make a branch +6. Run `gradlew setup` from the project root to decompile sources and apply current patches +7. Import project into your IDE (IntelliJ/Eclipse) or Reload Gradle Project +8. Modify the patched Minecraft sources in `projects/neoforge/src/main/java` as needed. The unmodified sources are available in `projects/base/src/main/java` for your reference. Do not modify these. +9. Test your changes - Run the game (Runs are available in the IDE) - Run `gradlew :tests:runGameTestServer` or `Tests: GameTestServer` from IDE - Run `gradlew :tests:runGameTestClient` or `Tests: GameTestClient` from IDE - If possible, write an automated test under the tests project. See [NEOGAMETESTS.md](NEOGAMETESTS.md) for more info. -9. Run `gradlew unpackSourcePatches` to generate patch-files from the patched sources -10. Run `gradlew applyAllFormatting` to automatically format sources -11. Check correct formatting with `gradlew spotlessCheck` -12. Commit & Push -13. Make PR +10. Run `gradlew unpackSourcePatches` to generate patch-files from the patched sources +11. Run `gradlew applyAllFormatting` to automatically format sources +12. Check correct formatting with `gradlew spotlessCheck` +13. Commit & Push +14. Make PR ## Porting diff --git a/gradle.properties b/gradle.properties index 22de2778cd..d65d2d4d71 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,20 +17,20 @@ neoforge_snapshot_next_stable=22.0 mergetool_version=2.0.0 accesstransformers_version=10.0.1 coremods_version=6.0.4 -eventbus_version=8.0.1 +eventbus_version=8.0.2 modlauncher_version=11.0.4 securejarhandler_version=3.0.8 bootstraplauncher_version=2.0.2 -asm_version=9.5 +asm_version=9.7 installer_version=2.1.+ -mixin_version=0.14.0+mixin.0.8.6 +mixin_version=0.15.2+mixin.0.8.7 terminalconsoleappender_version=1.3.0 nightconfig_version=3.8.0 jetbrains_annotations_version=24.0.1 slf4j_api_version=2.0.7 apache_maven_artifact_version=3.8.5 jarjar_version=0.4.1 -fancy_mod_loader_version=4.0.24 +fancy_mod_loader_version=4.0.29 mojang_logging_version=1.1.1 log4j_version=2.22.1 guava_version=31.1.2-jre diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3..a4b76b9530 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 b82aa23a4f..9355b41557 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a4269..f5feea6d6b 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # 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 +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # 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 +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 25da30dbde..9d21a21834 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/patches/net/minecraft/CrashReportCategory.java.patch b/patches/net/minecraft/CrashReportCategory.java.patch index 50c9e7294b..e8b649ffb5 100644 --- a/patches/net/minecraft/CrashReportCategory.java.patch +++ b/patches/net/minecraft/CrashReportCategory.java.patch @@ -13,7 +13,7 @@ return this.stackTrace.length; } } -@@ -165,16 +_,16 @@ +@@ -165,16 +_,22 @@ if (this.stackTrace != null && this.stackTrace.length > 0) { p_128169_.append("\nStacktrace:"); @@ -30,8 +30,14 @@ return this.stackTrace; + } + ++ /** @deprecated Neo: Use {@link #setStackTrace(StackTraceElement[])} instead. */ ++ @Deprecated(forRemoval = true, since = "1.21.1") + public void applyStackTrace(Throwable t) { -+ this.stackTrace = t.getStackTrace(); ++ setStackTrace(t.getStackTrace()); ++ } ++ ++ public void setStackTrace(StackTraceElement[] stackTrace) { ++ this.stackTrace = stackTrace; } public static void populateBlockDetails(CrashReportCategory p_178951_, LevelHeightAccessor p_178952_, BlockPos p_178953_, @Nullable BlockState p_178954_) { diff --git a/patches/net/minecraft/client/Minecraft.java.patch b/patches/net/minecraft/client/Minecraft.java.patch index f87e63c9f3..13ff259e92 100644 --- a/patches/net/minecraft/client/Minecraft.java.patch +++ b/patches/net/minecraft/client/Minecraft.java.patch @@ -326,14 +326,16 @@ } private boolean isLevelRunningNormally() { -@@ -2056,6 +_,7 @@ +@@ -2056,7 +_,8 @@ } public void setLevel(ClientLevel p_91157_, ReceivingLevelScreen.Reason p_341652_) { +- this.updateScreenAndTick(new ReceivingLevelScreen(() -> false, p_341652_)); + if (this.level != null) net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.level.LevelEvent.Unload(this.level)); - this.updateScreenAndTick(new ReceivingLevelScreen(() -> false, p_341652_)); ++ this.updateScreenAndTick(net.neoforged.neoforge.client.DimensionTransitionScreenManager.getScreenFromLevel(p_91157_, this.level).create(() -> false, p_341652_)); this.level = p_91157_; this.updateLevelInEngines(p_91157_); + if (!this.isLocalServer) { @@ -2093,6 +_,7 @@ IntegratedServer integratedserver = this.singleplayerServer; this.singleplayerServer = null; diff --git a/patches/net/minecraft/client/gui/screens/inventory/CreativeModeInventoryScreen.java.patch b/patches/net/minecraft/client/gui/screens/inventory/CreativeModeInventoryScreen.java.patch index 67ef56cafb..525825a442 100644 --- a/patches/net/minecraft/client/gui/screens/inventory/CreativeModeInventoryScreen.java.patch +++ b/patches/net/minecraft/client/gui/screens/inventory/CreativeModeInventoryScreen.java.patch @@ -160,16 +160,19 @@ this.refreshSearchResults(); } else { -@@ -665,7 +_,7 @@ +@@ -665,18 +_,27 @@ public void render(GuiGraphics p_283000_, int p_281317_, int p_282770_, float p_281295_) { super.render(p_283000_, p_281317_, p_282770_, p_281295_); - for (CreativeModeTab creativemodetab : CreativeModeTabs.tabs()) { -+ for(CreativeModeTab creativemodetab : currentPage.getVisibleTabs()) { - if (this.checkTabHovering(p_283000_, creativemodetab, p_281317_, p_282770_)) { - break; - } -@@ -677,6 +_,15 @@ +- if (this.checkTabHovering(p_283000_, creativemodetab, p_281317_, p_282770_)) { +- break; +- } +- } +- + if (this.destroyItemSlot != null + && selectedTab.getType() == CreativeModeTab.Type.INVENTORY + && this.isHovering(this.destroyItemSlot.x, this.destroyItemSlot.y, 16, 16, (double)p_281317_, (double)p_282770_)) { p_283000_.renderTooltip(this.font, TRASH_SLOT_TOOLTIP, p_281317_, p_282770_); } @@ -181,6 +184,12 @@ + p_283000_.pose().popPose(); + } + ++ for (CreativeModeTab creativemodetab : currentPage.getVisibleTabs()) { ++ if (this.checkTabHovering(p_283000_, creativemodetab, p_281317_, p_282770_)) { ++ break; ++ } ++ } ++ + com.mojang.blaze3d.systems.RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); this.renderTooltip(p_283000_, p_281317_, p_282770_); } diff --git a/patches/net/minecraft/client/model/HierarchicalModel.java.patch b/patches/net/minecraft/client/model/HierarchicalModel.java.patch new file mode 100644 index 0000000000..b9e5a58ff6 --- /dev/null +++ b/patches/net/minecraft/client/model/HierarchicalModel.java.patch @@ -0,0 +1,48 @@ +--- a/net/minecraft/client/model/HierarchicalModel.java ++++ b/net/minecraft/client/model/HierarchicalModel.java +@@ -27,6 +_,10 @@ + super(p_170623_); + } + ++ protected static net.neoforged.neoforge.client.entity.animation.json.AnimationHolder getAnimation(ResourceLocation key) { ++ return net.neoforged.neoforge.client.entity.animation.json.AnimationLoader.INSTANCE.getAnimationHolder(key); ++ } ++ + @Override + public void renderToBuffer(PoseStack p_170625_, VertexConsumer p_170626_, int p_170627_, int p_170628_, int p_350603_) { + this.root().render(p_170625_, p_170626_, p_170627_, p_170628_, p_350603_); +@@ -44,18 +_,34 @@ + this.animate(p_233382_, p_233383_, p_233384_, 1.0F); + } + ++ protected void animate(AnimationState animationState, net.neoforged.neoforge.client.entity.animation.json.AnimationHolder animation, float ageInTicks) { ++ this.animate(animationState, animation.get(), ageInTicks); ++ } ++ + protected void animateWalk(AnimationDefinition p_268159_, float p_268057_, float p_268347_, float p_268138_, float p_268165_) { + long i = (long)(p_268057_ * 50.0F * p_268138_); + float f = Math.min(p_268347_ * p_268165_, 1.0F); + KeyframeAnimations.animate(this, p_268159_, i, f, ANIMATION_VECTOR_CACHE); + } + ++ protected void animateWalk(net.neoforged.neoforge.client.entity.animation.json.AnimationHolder animation, float limbSwing, float limbSwingAmount, float maxAnimationSpeed, float animationScaleFactor) { ++ this.animateWalk(animation.get(), limbSwing, limbSwingAmount, maxAnimationSpeed, animationScaleFactor); ++ } ++ + protected void animate(AnimationState p_233386_, AnimationDefinition p_233387_, float p_233388_, float p_233389_) { + p_233386_.updateTime(p_233388_, p_233389_); + p_233386_.ifStarted(p_233392_ -> KeyframeAnimations.animate(this, p_233387_, p_233392_.getAccumulatedTime(), 1.0F, ANIMATION_VECTOR_CACHE)); + } + ++ protected void animate(AnimationState animationState, net.neoforged.neoforge.client.entity.animation.json.AnimationHolder animation, float ageInTicks, float speed) { ++ this.animate(animationState, animation.get(), ageInTicks, speed); ++ } ++ + protected void applyStatic(AnimationDefinition p_288996_) { + KeyframeAnimations.animate(this, p_288996_, 0L, 1.0F, ANIMATION_VECTOR_CACHE); ++ } ++ ++ protected void applyStatic(net.neoforged.neoforge.client.entity.animation.json.AnimationHolder animation) { ++ this.applyStatic(animation.get()); + } + } diff --git a/patches/net/minecraft/client/multiplayer/ClientCommonPacketListenerImpl.java.patch b/patches/net/minecraft/client/multiplayer/ClientCommonPacketListenerImpl.java.patch index fa6437a7c7..8bc8fe4f9c 100644 --- a/patches/net/minecraft/client/multiplayer/ClientCommonPacketListenerImpl.java.patch +++ b/patches/net/minecraft/client/multiplayer/ClientCommonPacketListenerImpl.java.patch @@ -36,12 +36,12 @@ + } + + if (p_295727_.payload() instanceof net.neoforged.neoforge.network.payload.CommonVersionPayload commonVersionPayload) { -+ net.neoforged.neoforge.network.registration.NetworkRegistry.checkCommonVersion(this.getConnection(), commonVersionPayload); ++ net.neoforged.neoforge.network.registration.NetworkRegistry.checkCommonVersion(this, commonVersionPayload); + return; + } + + if (p_295727_.payload() instanceof net.neoforged.neoforge.network.payload.CommonRegisterPayload commonRegisterPayload) { -+ net.neoforged.neoforge.network.registration.NetworkRegistry.onCommonRegister(this.getConnection(), commonRegisterPayload); ++ net.neoforged.neoforge.network.registration.NetworkRegistry.onCommonRegister(this, commonRegisterPayload); + return; + } + diff --git a/patches/net/minecraft/client/multiplayer/ClientPacketListener.java.patch b/patches/net/minecraft/client/multiplayer/ClientPacketListener.java.patch index 4ca1a328ab..c244326521 100644 --- a/patches/net/minecraft/client/multiplayer/ClientPacketListener.java.patch +++ b/patches/net/minecraft/client/multiplayer/ClientPacketListener.java.patch @@ -8,15 +8,17 @@ @Nullable private LevelLoadStatusManager levelLoadStatusManager; private boolean serverEnforcesSecureChat; -@@ -366,6 +_,7 @@ +@@ -366,7 +_,8 @@ p_253924_.gui.getChat().restoreState(p_295121_.chatState()); } +- this.potionBrewing = PotionBrewing.bootstrap(this.enabledFeatures); + this.connectionType = p_295121_.connectionType(); - this.potionBrewing = PotionBrewing.bootstrap(this.enabledFeatures); ++ this.potionBrewing = PotionBrewing.bootstrap(this.enabledFeatures, this.registryAccess); } -@@ -427,6 +_,7 @@ + public ClientSuggestionProvider getSuggestionsProvider() { +@@ -427,12 +_,13 @@ this.minecraft.debugRenderer.clear(); this.minecraft.player.resetPos(); @@ -24,6 +26,13 @@ this.minecraft.player.setId(p_105030_.playerId()); this.level.addEntity(this.minecraft.player); this.minecraft.player.input = new KeyboardInput(this.minecraft.options); + this.minecraft.gameMode.adjustPlayer(this.minecraft.player); + this.minecraft.cameraEntity = this.minecraft.player; +- this.startWaitingForNewLevel(this.minecraft.player, this.level, ReceivingLevelScreen.Reason.OTHER); ++ this.startWaitingForNewLevel(this.minecraft.player, this.level, ReceivingLevelScreen.Reason.OTHER, null, null); + this.minecraft.player.setReducedDebugInfo(p_105030_.reducedDebugInfo()); + this.minecraft.player.setShowDeathScreen(p_105030_.showDeathScreen()); + this.minecraft.player.setDoLimitedCrafting(p_105030_.doLimitedCrafting()); @@ -828,7 +_,8 @@ chatcomponent$state, this.strictErrorHandling, @@ -34,6 +43,15 @@ ) ) ); +@@ -1142,7 +_,7 @@ + localplayer1 = this.minecraft.gameMode.createPlayer(this.level, localplayer.getStats(), localplayer.getRecipeBook()); + } + +- this.startWaitingForNewLevel(localplayer1, this.level, receivinglevelscreen$reason); ++ this.startWaitingForNewLevel(localplayer1, this.level, receivinglevelscreen$reason, localplayer.isDeadOrDying() ? null : resourcekey, localplayer.isDeadOrDying() ? null : resourcekey1); + localplayer1.setId(localplayer.getId()); + this.minecraft.player = localplayer1; + if (flag) { @@ -1164,6 +_,7 @@ } @@ -54,6 +72,23 @@ if (p_337415_ instanceof CommandBlockEntity && this.minecraft.screen instanceof CommandBlockEditScreen) { ((CommandBlockEditScreen)this.minecraft.screen).updateGui(); +@@ -1420,9 +_,15 @@ + } + } + ++ /** @deprecated Neo: use {@link #startWaitingForNewLevel(LocalPlayer, ClientLevel, ReceivingLevelScreen.Reason, ResourceKey, ResourceKey)} instead. */ ++ @Deprecated + private void startWaitingForNewLevel(LocalPlayer p_304688_, ClientLevel p_304528_, ReceivingLevelScreen.Reason p_341690_) { ++ this.startWaitingForNewLevel(p_304688_, p_304528_, p_341690_, null, null); ++ } ++ ++ private void startWaitingForNewLevel(LocalPlayer p_304688_, ClientLevel p_304528_, ReceivingLevelScreen.Reason p_341690_, @Nullable ResourceKey toDimension, @Nullable ResourceKey fromDimension) { + this.levelLoadStatusManager = new LevelLoadStatusManager(p_304688_, p_304528_, this.minecraft.levelRenderer); +- this.minecraft.setScreen(new ReceivingLevelScreen(this.levelLoadStatusManager::levelReady, p_341690_)); ++ this.minecraft.setScreen(net.neoforged.neoforge.client.DimensionTransitionScreenManager.getScreen(toDimension, fromDimension).create(this.levelLoadStatusManager::levelReady, p_341690_)); + } + + @Override @@ -1471,7 +_,9 @@ @Override public void handleCommands(ClientboundCommandsPacket p_104990_) { diff --git a/patches/net/minecraft/client/renderer/LevelRenderer.java.patch b/patches/net/minecraft/client/renderer/LevelRenderer.java.patch index 07706e5c30..82e084e8b4 100644 --- a/patches/net/minecraft/client/renderer/LevelRenderer.java.patch +++ b/patches/net/minecraft/client/renderer/LevelRenderer.java.patch @@ -1,5 +1,16 @@ --- a/net/minecraft/client/renderer/LevelRenderer.java +++ b/net/minecraft/client/renderer/LevelRenderer.java +@@ -233,6 +_,10 @@ + private int rainSoundTime; + private final float[] rainSizeX = new float[1024]; + private final float[] rainSizeZ = new float[1024]; ++ /** ++ * Neo: Indicates whether outline effect post-processing was requested for the current frame outside of vanilla codepaths ++ */ ++ private boolean outlineEffectRequested = false; + + public LevelRenderer(Minecraft p_234245_, EntityRenderDispatcher p_234246_, BlockEntityRenderDispatcher p_234247_, RenderBuffers p_234248_) { + this.minecraft = p_234245_; @@ -256,6 +_,8 @@ } @@ -98,7 +109,17 @@ this.blockEntityRenderDispatcher.render(blockentity, f, posestack, multibuffersource$buffersource); posestack.popPose(); } -@@ -1085,6 +_,7 @@ +@@ -1080,11 +_,17 @@ + multibuffersource$buffersource.endBatch(Sheets.hangingSignSheet()); + multibuffersource$buffersource.endBatch(Sheets.chestSheet()); + this.renderBuffers.outlineBufferSource().endOutlineBatch(); ++ // Neo: handle outline effect requests outside glowing entities ++ if (this.outlineEffectRequested) { ++ flag2 |= this.shouldShowEntityOutlines(); ++ this.outlineEffectRequested = false; ++ } + if (flag2) { + this.entityEffect.process(p_348530_.getGameTimeDeltaTicks()); this.minecraft.getMainRenderTarget().bindWrite(false); } @@ -199,7 +220,7 @@ float f = this.level.effects().getCloudHeight(); if (!Float.isNaN(f)) { float f1 = 12.0F; -@@ -2488,6 +_,23 @@ +@@ -2488,6 +_,31 @@ this.viewArea.setDirty(p_109502_, p_109503_, p_109504_, p_109505_); } @@ -219,6 +240,14 @@ + this.globalBlockEntities.forEach(blockEntityConsumer); + } + } ++ ++ /** ++ * Neo: Request outline effect post-processing to be enabled for the current frame. Must be called before block ++ * entities are done rendering, ideally early during the frame ++ */ ++ public void requestOutlineEffect() { ++ this.outlineEffectRequested = true; ++ } + public void playJukeboxSong(Holder p_350918_, BlockPos p_350830_) { if (this.level != null) { diff --git a/patches/net/minecraft/client/renderer/entity/layers/HumanoidArmorLayer.java.patch b/patches/net/minecraft/client/renderer/entity/layers/HumanoidArmorLayer.java.patch index 545f030b2f..b6db566e31 100644 --- a/patches/net/minecraft/client/renderer/entity/layers/HumanoidArmorLayer.java.patch +++ b/patches/net/minecraft/client/renderer/entity/layers/HumanoidArmorLayer.java.patch @@ -1,6 +1,28 @@ --- a/net/minecraft/client/renderer/entity/layers/HumanoidArmorLayer.java +++ b/net/minecraft/client/renderer/entity/layers/HumanoidArmorLayer.java -@@ -66,22 +_,28 @@ +@@ -54,34 +_,47 @@ + float p_117104_, + float p_117105_ + ) { +- this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.CHEST, p_117098_, this.getArmorModel(EquipmentSlot.CHEST)); +- this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.LEGS, p_117098_, this.getArmorModel(EquipmentSlot.LEGS)); +- this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.FEET, p_117098_, this.getArmorModel(EquipmentSlot.FEET)); +- this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.HEAD, p_117098_, this.getArmorModel(EquipmentSlot.HEAD)); ++ this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.CHEST, p_117098_, this.getArmorModel(EquipmentSlot.CHEST), p_117100_, p_117101_, p_117102_, p_117103_, p_117104_, p_117105_); ++ this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.LEGS, p_117098_, this.getArmorModel(EquipmentSlot.LEGS), p_117100_, p_117101_, p_117102_, p_117103_, p_117104_, p_117105_); ++ this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.FEET, p_117098_, this.getArmorModel(EquipmentSlot.FEET), p_117100_, p_117101_, p_117102_, p_117103_, p_117104_, p_117105_); ++ this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.HEAD, p_117098_, this.getArmorModel(EquipmentSlot.HEAD), p_117100_, p_117101_, p_117102_, p_117103_, p_117104_, p_117105_); + } + ++ /** @deprecated Neo: use {@link #renderArmorPiece(PoseStack, MultiBufferSource, LivingEntity, EquipmentSlot, int, HumanoidModel, float, float, float, float, float, float)} instead. */ ++ @Deprecated + private void renderArmorPiece(PoseStack p_117119_, MultiBufferSource p_117120_, T p_117121_, EquipmentSlot p_117122_, int p_117123_, A p_117124_) { ++ this.renderArmorPiece(p_117119_, p_117120_, p_117121_, p_117122_, p_117123_, p_117124_, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F); ++ } ++ ++ private void renderArmorPiece(PoseStack p_117119_, MultiBufferSource p_117120_, T p_117121_, EquipmentSlot p_117122_, int p_117123_, A p_117124_, float limbSwing, float limbSwingAmount, float partialTick, float ageInTicks, float netHeadYaw, float headPitch) { + ItemStack itemstack = p_117121_.getItemBySlot(p_117122_); + if (itemstack.getItem() instanceof ArmorItem armoritem) { if (armoritem.getEquipmentSlot() == p_117122_) { this.getParentModel().copyPropertiesTo(p_117124_); this.setPartVisibility(p_117124_, p_117122_); @@ -13,6 +35,7 @@ - int j = armormaterial$layer.dyeable() ? i : -1; - this.renderModel(p_117119_, p_117120_, p_117123_, p_117124_, j, armormaterial$layer.texture(flag)); + net.neoforged.neoforge.client.extensions.common.IClientItemExtensions extensions = net.neoforged.neoforge.client.extensions.common.IClientItemExtensions.of(itemstack); ++ extensions.setupModelAnimations(p_117121_, itemstack, p_117122_, model, limbSwing, limbSwingAmount, partialTick, ageInTicks, netHeadYaw, headPitch); + int fallbackColor = extensions.getDefaultDyeColor(itemstack); + for (int layerIdx = 0; layerIdx < armormaterial.layers().size(); layerIdx++) { + ArmorMaterial.Layer armormaterial$layer = armormaterial.layers().get(layerIdx); diff --git a/patches/net/minecraft/client/resources/model/WeightedBakedModel.java.patch b/patches/net/minecraft/client/resources/model/WeightedBakedModel.java.patch index f96aeedb0e..3483772f34 100644 --- a/patches/net/minecraft/client/resources/model/WeightedBakedModel.java.patch +++ b/patches/net/minecraft/client/resources/model/WeightedBakedModel.java.patch @@ -34,7 +34,7 @@ public boolean isGui3d() { return this.wrapped.isGui3d(); } -@@ -61,8 +_,25 @@ +@@ -61,8 +_,30 @@ } @Override @@ -57,6 +57,11 @@ + return WeightedRandom.getWeightedItem(this.list, Math.abs((int)rand.nextLong()) % this.totalWeight) + .map((p_235065_) -> p_235065_.data().getRenderTypes(state, rand, data)) + .orElse(net.neoforged.neoforge.client.ChunkRenderTypeSet.none()); ++ } ++ ++ @Override ++ public net.neoforged.neoforge.client.model.data.ModelData getModelData(net.minecraft.world.level.BlockAndTintGetter level, net.minecraft.core.BlockPos pos, BlockState state, net.neoforged.neoforge.client.model.data.ModelData modelData) { ++ return this.wrapped.getModelData(level, pos, state, modelData); } @Override diff --git a/patches/net/minecraft/data/tags/TagsProvider.java.patch b/patches/net/minecraft/data/tags/TagsProvider.java.patch index f52c3bdce5..7cf15ff1f6 100644 --- a/patches/net/minecraft/data/tags/TagsProvider.java.patch +++ b/patches/net/minecraft/data/tags/TagsProvider.java.patch @@ -108,24 +108,28 @@ return this.builders.computeIfAbsent(p_236452_.location(), p_236442_ -> TagBuilder.create()); } -@@ -127,11 +_,13 @@ +@@ -127,11 +_,19 @@ }); } - public static class TagAppender { + public static class TagAppender implements net.neoforged.neoforge.common.extensions.ITagAppenderExtension { private final TagBuilder builder; -+ private final String modId; -- protected TagAppender(TagBuilder p_256426_) { -- this.builder = p_256426_; -+ protected TagAppender(TagBuilder p_236454_, String modId) { -+ this.builder = p_236454_; + protected TagAppender(TagBuilder p_256426_) { ++ this(p_256426_, ""); ++ } ++ ++ private final String modId; ++ /** @deprecated Neo: The additional mod ID parameter is unused; use the one-parameter constructor instead. */ ++ @Deprecated(forRemoval = true, since = "1.21.1") ++ protected TagAppender(TagBuilder p_256426_, String modId) { + this.builder = p_256426_; + this.modId = modId; } public final TagsProvider.TagAppender add(ResourceKey p_256138_) { -@@ -169,6 +_,19 @@ +@@ -169,6 +_,22 @@ public TagsProvider.TagAppender addOptionalTag(ResourceLocation p_176842_) { this.builder.addOptionalTag(p_176842_); return this; @@ -136,10 +140,13 @@ + return this; + } + ++ // TODO: In 1.21.2, mark this as @ApiStatus.Internal + public TagBuilder getInternalBuilder() { + return builder; + } + ++ /** @deprecated Neo: Avoid using this method to get the mod ID, as this method will be removed in 1.21.2. */ ++ @Deprecated(forRemoval = true, since = "1.21.1") + public String getModID() { + return modId; } diff --git a/patches/net/minecraft/resources/FileToIdConverter.java.patch b/patches/net/minecraft/resources/FileToIdConverter.java.patch new file mode 100644 index 0000000000..f908144107 --- /dev/null +++ b/patches/net/minecraft/resources/FileToIdConverter.java.patch @@ -0,0 +1,29 @@ +--- a/net/minecraft/resources/FileToIdConverter.java ++++ b/net/minecraft/resources/FileToIdConverter.java +@@ -34,4 +_,26 @@ + public Map> listMatchingResourceStacks(ResourceManager p_249881_) { + return p_249881_.listResourceStacks(this.prefix, p_248700_ -> p_248700_.getPath().endsWith(this.extension)); + } ++ ++ /** ++ * List all resources under the given namespace which match this converter ++ * ++ * @param manager The resource manager to collect the resources from ++ * @param namespace The namespace to search under ++ * @return All resources from the given namespace which match this converter ++ */ ++ public Map listMatchingResourcesFromNamespace(ResourceManager manager, String namespace) { ++ return manager.listResources(this.prefix, path -> path.getNamespace().equals(namespace) && path.getPath().endsWith(this.extension)); ++ } ++ ++ /** ++ * List all resource stacks under the given namespace which match this converter ++ * ++ * @param manager The resource manager to collect the resources from ++ * @param namespace The namespace to search under ++ * @return All resource stacks from the given namespace which match this converter ++ */ ++ public Map> listMatchingResourceStacksFromNamespace(ResourceManager manager, String namespace) { ++ return manager.listResourceStacks(this.prefix, path -> path.getNamespace().equals(namespace) && path.getPath().endsWith(this.extension)); ++ } + } diff --git a/patches/net/minecraft/resources/RegistryDataLoader.java.patch b/patches/net/minecraft/resources/RegistryDataLoader.java.patch index 0453b55915..13d15f4bb3 100644 --- a/patches/net/minecraft/resources/RegistryDataLoader.java.patch +++ b/patches/net/minecraft/resources/RegistryDataLoader.java.patch @@ -46,3 +46,26 @@ for (Entry entry : filetoidconverter.listMatchingResources(p_321535_).entrySet()) { ResourceLocation resourcelocation = entry.getKey(); +@@ -304,13 +_,20 @@ + void apply(RegistryDataLoader.Loader p_321864_, RegistryOps.RegistryInfoLookup p_321656_); + } + +- public static record RegistryData(ResourceKey> key, Codec elementCodec, boolean requiredNonEmpty) { ++ public static record RegistryData(ResourceKey> key, Codec elementCodec, boolean requiredNonEmpty, java.util.function.Consumer> registryBuilderConsumer) { ++ public RegistryData(ResourceKey> key, Codec elementCodec, boolean requiredNonEmpty) { ++ this(key, elementCodec, requiredNonEmpty, registryBuilder -> {}); ++ } ++ + RegistryData(ResourceKey> p_251360_, Codec p_248976_) { + this(p_251360_, p_248976_, false); + } + + RegistryDataLoader.Loader create(Lifecycle p_251662_, Map, Exception> p_251565_) { +- WritableRegistry writableregistry = new MappedRegistry<>(this.key, p_251662_); ++ net.neoforged.neoforge.registries.RegistryBuilder registryBuilder = new net.neoforged.neoforge.registries.RegistryBuilder<>(key); ++ registryBuilderConsumer.accept(registryBuilder); ++ ++ WritableRegistry writableregistry = (WritableRegistry) registryBuilder.disableRegistrationCheck().create(); + return new RegistryDataLoader.Loader<>(this, writableregistry, p_251565_); + } + diff --git a/patches/net/minecraft/server/MinecraftServer.java.patch b/patches/net/minecraft/server/MinecraftServer.java.patch index 5d60f55f4d..cebd24b556 100644 --- a/patches/net/minecraft/server/MinecraftServer.java.patch +++ b/patches/net/minecraft/server/MinecraftServer.java.patch @@ -9,6 +9,15 @@ thread.setUncaughtExceptionHandler((p_177909_, p_177910_) -> LOGGER.error("Uncaught exception in server thread", p_177910_)); if (Runtime.getRuntime().availableProcessors() > 4) { thread.setPriority(8); +@@ -315,7 +_,7 @@ + this.structureTemplateManager = new StructureTemplateManager(p_236726_.resourceManager(), p_236724_, p_236728_, holdergetter); + this.serverThread = p_236723_; + this.executor = Util.backgroundExecutor(); +- this.potionBrewing = PotionBrewing.bootstrap(this.worldData.enabledFeatures()); ++ this.potionBrewing = PotionBrewing.bootstrap(this.worldData.enabledFeatures(), this.registryAccess()); + } + } + @@ -372,6 +_,7 @@ this.readScoreboard(dimensiondatastorage); this.commandStorage = new CommandStorage(dimensiondatastorage); diff --git a/patches/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch b/patches/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch index d289270c98..bc534702f9 100644 --- a/patches/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch +++ b/patches/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch @@ -36,12 +36,12 @@ + } + + if (p_294276_.payload() instanceof net.neoforged.neoforge.network.payload.CommonVersionPayload commonVersionPayload) { -+ net.neoforged.neoforge.network.registration.NetworkRegistry.checkCommonVersion(this.getConnection(), commonVersionPayload); ++ net.neoforged.neoforge.network.registration.NetworkRegistry.checkCommonVersion(this, commonVersionPayload); + return; + } + + if (p_294276_.payload() instanceof net.neoforged.neoforge.network.payload.CommonRegisterPayload commonRegisterPayload) { -+ net.neoforged.neoforge.network.registration.NetworkRegistry.onCommonRegister(this.getConnection(), commonRegisterPayload); ++ net.neoforged.neoforge.network.registration.NetworkRegistry.onCommonRegister(this, commonRegisterPayload); + return; + } + diff --git a/patches/net/minecraft/world/entity/LivingEntity.java.patch b/patches/net/minecraft/world/entity/LivingEntity.java.patch index eb260531d3..b22fc4915b 100644 --- a/patches/net/minecraft/world/entity/LivingEntity.java.patch +++ b/patches/net/minecraft/world/entity/LivingEntity.java.patch @@ -440,7 +440,7 @@ public void swing(InteractionHand p_21012_, boolean p_21013_) { + ItemStack stack = this.getItemInHand(p_21012_); -+ if (!stack.isEmpty() && stack.onEntitySwing(this)) return; ++ if (!stack.isEmpty() && stack.onEntitySwing(this, p_21012_)) return; if (!this.swinging || this.swingTime >= this.getCurrentSwingDuration() / 2 || this.swingTime < 0) { this.swingTime = -1; this.swinging = true; diff --git a/patches/net/minecraft/world/entity/ai/attributes/Attribute.java.patch b/patches/net/minecraft/world/entity/ai/attributes/Attribute.java.patch new file mode 100644 index 0000000000..3863a37e98 --- /dev/null +++ b/patches/net/minecraft/world/entity/ai/attributes/Attribute.java.patch @@ -0,0 +1,33 @@ +--- a/net/minecraft/world/entity/ai/attributes/Attribute.java ++++ b/net/minecraft/world/entity/ai/attributes/Attribute.java +@@ -9,7 +_,7 @@ + import net.minecraft.network.codec.ByteBufCodecs; + import net.minecraft.network.codec.StreamCodec; + +-public class Attribute { ++public class Attribute implements net.neoforged.neoforge.common.extensions.IAttributeExtension { + public static final Codec> CODEC = BuiltInRegistries.ATTRIBUTE.holderByNameCodec(); + public static final StreamCodec> STREAM_CODEC = ByteBufCodecs.holderRegistry(Registries.ATTRIBUTE); + private final double defaultValue; +@@ -50,6 +_,21 @@ + + public ChatFormatting getStyle(boolean p_347715_) { + return this.sentiment.getStyle(p_347715_); ++ } ++ ++ // Neo: Patch in the default implementation of IAttributeExtension#getMergedStyle since we need access to Attribute#sentiment ++ ++ protected static final net.minecraft.network.chat.TextColor MERGED_RED = net.minecraft.network.chat.TextColor.fromRgb(0xF93131); ++ protected static final net.minecraft.network.chat.TextColor MERGED_BLUE = net.minecraft.network.chat.TextColor.fromRgb(0x7A7AF9); ++ protected static final net.minecraft.network.chat.TextColor MERGED_GRAY = net.minecraft.network.chat.TextColor.fromRgb(0xCCCCCC); ++ ++ @Override ++ public net.minecraft.network.chat.TextColor getMergedStyle(boolean isPositive) { ++ return switch (this.sentiment) { ++ case POSITIVE -> isPositive ? MERGED_BLUE : MERGED_RED; ++ case NEGATIVE -> isPositive ? MERGED_RED : MERGED_BLUE; ++ case NEUTRAL -> MERGED_GRAY; ++ }; + } + + public static enum Sentiment { diff --git a/patches/net/minecraft/world/entity/ai/attributes/Attributes.java.patch b/patches/net/minecraft/world/entity/ai/attributes/Attributes.java.patch new file mode 100644 index 0000000000..ebf3e8fe30 --- /dev/null +++ b/patches/net/minecraft/world/entity/ai/attributes/Attributes.java.patch @@ -0,0 +1,22 @@ +--- a/net/minecraft/world/entity/ai/attributes/Attributes.java ++++ b/net/minecraft/world/entity/ai/attributes/Attributes.java +@@ -54,7 +_,8 @@ + "generic.jump_strength", new RangedAttribute("attribute.name.generic.jump_strength", 0.42F, 0.0, 32.0).setSyncable(true) + ); + public static final Holder KNOCKBACK_RESISTANCE = register( +- "generic.knockback_resistance", new RangedAttribute("attribute.name.generic.knockback_resistance", 0.0, 0.0, 1.0) ++ // Neo: Convert Knockback Resistance to percent-based for more appropriate display using IAttributeExtension. ++ "generic.knockback_resistance", new net.neoforged.neoforge.common.PercentageAttribute("attribute.name.generic.knockback_resistance", 0.0, 0.0, 1.0) + ); + public static final Holder LUCK = register( + "generic.luck", new RangedAttribute("attribute.name.generic.luck", 0.0, -1024.0, 1024.0).setSyncable(true) +@@ -72,7 +_,8 @@ + "generic.movement_efficiency", new RangedAttribute("attribute.name.generic.movement_efficiency", 0.0, 0.0, 1.0).setSyncable(true) + ); + public static final Holder MOVEMENT_SPEED = register( +- "generic.movement_speed", new RangedAttribute("attribute.name.generic.movement_speed", 0.7, 0.0, 1024.0).setSyncable(true) ++ // Neo: Convert Movement Speed to percent-based for more appropriate display using IAttributeExtension. Use a scale factor of 1000 since movement speed has 0.001 units. ++ "generic.movement_speed", new net.neoforged.neoforge.common.PercentageAttribute("attribute.name.generic.movement_speed", 0.7, 0.0, 1024.0, 1000).setSyncable(true) + ); + public static final Holder OXYGEN_BONUS = register( + "generic.oxygen_bonus", new RangedAttribute("attribute.name.generic.oxygen_bonus", 0.0, 0.0, 1024.0).setSyncable(true) diff --git a/patches/net/minecraft/world/entity/player/Player.java.patch b/patches/net/minecraft/world/entity/player/Player.java.patch index f3804ed582..b56eec23b3 100644 --- a/patches/net/minecraft/world/entity/player/Player.java.patch +++ b/patches/net/minecraft/world/entity/player/Player.java.patch @@ -254,12 +254,12 @@ if (p_36347_.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) && p_36347_ instanceof Projectile projectile && projectile.deflect(ProjectileDeflection.AIM_DEFLECT, this, this, true)) { -@@ -1170,8 +_,12 @@ +@@ -1170,19 +_,28 @@ && !this.isPassenger() && p_36347_ instanceof LivingEntity && !this.isSprinting(); + // Neo: Fire the critical hit event and override the critical hit status and damage multiplier based on the event. -+ // The boolean local above (flag2) is the vanilla critical hit result. ++ // The boolean local above (flag1) is the vanilla critical hit result. + var critEvent = net.neoforged.neoforge.common.CommonHooks.fireCriticalHit(this, p_36347_, flag1, flag1 ? 1.5F : 1.0F); + flag1 = critEvent.isCriticalHit(); if (flag1) { @@ -268,17 +268,26 @@ } float f3 = f + f1; -@@ -1179,9 +_,7 @@ + boolean flag2 = false; double d0 = (double)(this.walkDist - this.walkDistO); - if (flag4 && !flag1 && !flag && this.onGround() && d0 < (double)this.getSpeed()) { +- if (flag4 && !flag1 && !flag && this.onGround() && d0 < (double)this.getSpeed()) { ++ // Neo: Replace !flag1 (!isCriticalHit) with the logic from the CriticalHitEvent. ++ boolean critBlocksSweep = critEvent.isCriticalHit() && critEvent.disableSweep(); ++ if (flag4 && !critBlocksSweep && !flag && this.onGround() && d0 < (double)this.getSpeed()) { ++ // Neo: Make sweep attacks check SWORD_SWEEP instead of instanceof SwordItem. ItemStack itemstack1 = this.getItemInHand(InteractionHand.MAIN_HAND); - if (itemstack1.getItem() instanceof SwordItem) { - flag2 = true; - } + flag2 = itemstack1.canPerformAction(net.neoforged.neoforge.common.ItemAbilities.SWORD_SWEEP); } ++ ++ // Neo: Fire the SweepAttackEvent and overwrite the value of flag2 (the local controlling if a sweep will occur). ++ var sweepEvent = net.neoforged.neoforge.common.CommonHooks.fireSweepAttack(this, p_36347_, flag2); ++ flag2 = sweepEvent.isSweeping(); float f6 = 0.0F; + if (p_36347_ instanceof LivingEntity livingentity) { @@ -1217,11 +_,12 @@ for (LivingEntity livingentity2 : this.level() diff --git a/patches/net/minecraft/world/inventory/GrindstoneMenu.java.patch b/patches/net/minecraft/world/inventory/GrindstoneMenu.java.patch index 55e782bb5c..9c769897c2 100644 --- a/patches/net/minecraft/world/inventory/GrindstoneMenu.java.patch +++ b/patches/net/minecraft/world/inventory/GrindstoneMenu.java.patch @@ -40,15 +40,15 @@ int l = 0; l += this.getExperienceFromItem(GrindstoneMenu.this.repairSlots.getItem(0)); l += this.getExperienceFromItem(GrindstoneMenu.this.repairSlots.getItem(1)); -@@ -131,6 +_,8 @@ +@@ -125,6 +_,8 @@ + } - private ItemStack computeResult(ItemStack p_332654_, ItemStack p_332736_) { - boolean flag = !p_332654_.isEmpty() || !p_332736_.isEmpty(); -+ this.xp = net.neoforged.neoforge.common.CommonHooks.onGrindstoneChange(p_332654_, p_332736_, this.resultSlots, -1); -+ if (this.xp != Integer.MIN_VALUE) return ItemStack.EMPTY; // Porting 1.20.5 check if this is correct - if (!flag) { - return ItemStack.EMPTY; - } else if (p_332654_.getCount() <= 1 && p_332736_.getCount() <= 1) { + private void createResult() { ++ this.xp = net.neoforged.neoforge.common.CommonHooks.onGrindstoneChange(this.repairSlots.getItem(0), this.repairSlots.getItem(1), this.resultSlots, -1); ++ if (this.xp == Integer.MIN_VALUE) + this.resultSlots.setItem(0, this.computeResult(this.repairSlots.getItem(0), this.repairSlots.getItem(1))); + this.broadcastChanges(); + } @@ -155,7 +_,7 @@ int k = p_332686_.getMaxDamage() - p_332686_.getDamageValue(); int l = j + k + i * 5 / 100; diff --git a/patches/net/minecraft/world/item/BlockItem.java.patch b/patches/net/minecraft/world/item/BlockItem.java.patch index a8ef2e4e88..eed7cf8eb1 100644 --- a/patches/net/minecraft/world/item/BlockItem.java.patch +++ b/patches/net/minecraft/world/item/BlockItem.java.patch @@ -31,12 +31,14 @@ @Nullable public BlockPlaceContext updatePlacementContext(BlockPlaceContext p_40609_) { return p_40609_; -@@ -193,6 +_,10 @@ +@@ -193,6 +_,12 @@ public void registerBlocks(Map p_40607_, Item p_40608_) { p_40607_.put(this.getBlock(), p_40608_); + } + ++ /** @deprecated Neo: To be removed without replacement since registry replacement is not a feature anymore. */ ++ @Deprecated(forRemoval = true, since = "1.21.1") + public void removeFromBlockToItemMap(Map blockToItemMap, Item itemIn) { + blockToItemMap.remove(this.getBlock()); } diff --git a/patches/net/minecraft/world/item/ItemStack.java.patch b/patches/net/minecraft/world/item/ItemStack.java.patch index 4c1f77b59b..7f753b99da 100644 --- a/patches/net/minecraft/world/item/ItemStack.java.patch +++ b/patches/net/minecraft/world/item/ItemStack.java.patch @@ -148,7 +148,18 @@ if (this.has(DataComponents.CUSTOM_NAME)) { mutablecomponent.withStyle(ChatFormatting.ITALIC); } -@@ -784,12 +_,14 @@ +@@ -752,7 +_,9 @@ + this.addToTooltip(DataComponents.ENCHANTMENTS, p_339637_, consumer, p_41653_); + this.addToTooltip(DataComponents.DYED_COLOR, p_339637_, consumer, p_41653_); + this.addToTooltip(DataComponents.LORE, p_339637_, consumer, p_41653_); +- this.addAttributeTooltips(consumer, p_41652_); ++ // Neo: Replace attribute tooltips with custom handling ++ net.neoforged.neoforge.common.util.AttributeUtil.addAttributeTooltips(this, consumer, ++ net.neoforged.neoforge.common.util.AttributeTooltipContext.of(p_41652_, p_339637_, p_41653_)); + this.addToTooltip(DataComponents.UNBREAKABLE, p_339637_, consumer, p_41653_); + AdventureModePredicate adventuremodepredicate = this.get(DataComponents.CAN_BREAK); + if (adventuremodepredicate != null && adventuremodepredicate.showInTooltip()) { +@@ -784,10 +_,15 @@ list.add(DISABLED_ITEM_TOOLTIP); } @@ -157,12 +168,13 @@ } } ++ /** ++ * @deprecated Neo: Use {@link net.neoforged.neoforge.client.util.TooltipUtil#addAttributeTooltips} ++ */ ++ @Deprecated private void addAttributeTooltips(Consumer p_330796_, @Nullable Player p_330530_) { ItemAttributeModifiers itemattributemodifiers = this.getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.EMPTY); -+ // Neo: We don't need to call IItemStackExtension#getAttributeModifiers here, since it will be done in forEachModifier. if (itemattributemodifiers.showInTooltip()) { - for (EquipmentSlotGroup equipmentslotgroup : EquipmentSlotGroup.values()) { - MutableBoolean mutableboolean = new MutableBoolean(true); @@ -897,6 +_,17 @@ return !this.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY).isEmpty(); } diff --git a/patches/net/minecraft/world/item/Items.java.patch b/patches/net/minecraft/world/item/Items.java.patch index 64125c3d73..5967553b88 100644 --- a/patches/net/minecraft/world/item/Items.java.patch +++ b/patches/net/minecraft/world/item/Items.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/item/Items.java +++ b/net/minecraft/world/item/Items.java -@@ -2092,11 +_,23 @@ +@@ -2092,11 +_,25 @@ } public static Item registerBlock(Block p_252092_, Block... p_248886_) { @@ -17,6 +17,8 @@ - for (Block block : p_248886_) { - Item.BY_BLOCK.put(block, blockitem); - } ++ /** @deprecated Neo: To be removed without replacement since registry replacement is not a feature anymore. */ ++ @Deprecated(forRemoval = true, since = "1.21.1") + @Override + public void removeFromBlockToItemMap(java.util.Map map, Item self) { + super.removeFromBlockToItemMap(map, self); diff --git a/patches/net/minecraft/world/item/StandingAndWallBlockItem.java.patch b/patches/net/minecraft/world/item/StandingAndWallBlockItem.java.patch index 781b756bc0..c119b7fac0 100644 --- a/patches/net/minecraft/world/item/StandingAndWallBlockItem.java.patch +++ b/patches/net/minecraft/world/item/StandingAndWallBlockItem.java.patch @@ -1,10 +1,12 @@ --- a/net/minecraft/world/item/StandingAndWallBlockItem.java +++ b/net/minecraft/world/item/StandingAndWallBlockItem.java -@@ -50,4 +_,9 @@ +@@ -50,4 +_,11 @@ super.registerBlocks(p_43252_, p_43253_); p_43252_.put(this.wallBlock, p_43253_); } + ++ /** @deprecated Neo: To be removed without replacement since registry replacement is not a feature anymore. */ ++ @Deprecated(forRemoval = true, since = "1.21.1") + public void removeFromBlockToItemMap(Map blockToItemMap, Item itemIn) { + super.removeFromBlockToItemMap(blockToItemMap, itemIn); + blockToItemMap.remove(this.wallBlock); diff --git a/patches/net/minecraft/world/item/alchemy/PotionBrewing.java.patch b/patches/net/minecraft/world/item/alchemy/PotionBrewing.java.patch index 9c3be6f23f..7612a5fff4 100644 --- a/patches/net/minecraft/world/item/alchemy/PotionBrewing.java.patch +++ b/patches/net/minecraft/world/item/alchemy/PotionBrewing.java.patch @@ -56,11 +56,22 @@ Optional> optional = p_43531_.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY).potion(); if (optional.isEmpty()) { return p_43531_; -@@ -127,6 +_,7 @@ +@@ -124,9 +_,18 @@ + } + } + ++ /** ++ * @deprecated Use {@link #bootstrap(FeatureFlagSet, net.minecraft.core.RegistryAccess)} instead ++ */ ++ @Deprecated public static PotionBrewing bootstrap(FeatureFlagSet p_341301_) { ++ return bootstrap(p_341301_, net.minecraft.core.RegistryAccess.EMPTY); ++ } ++ ++ public static PotionBrewing bootstrap(FeatureFlagSet p_341301_, net.minecraft.core.RegistryAccess registryAccess) { PotionBrewing.Builder potionbrewing$builder = new PotionBrewing.Builder(p_341301_); addVanillaMixes(potionbrewing$builder); -+ net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.brewing.RegisterBrewingRecipesEvent(potionbrewing$builder)); ++ net.neoforged.neoforge.common.NeoForge.EVENT_BUS.post(new net.neoforged.neoforge.event.brewing.RegisterBrewingRecipesEvent(potionbrewing$builder, registryAccess)); return potionbrewing$builder.build(); } diff --git a/patches/net/minecraft/world/item/alchemy/PotionContents.java.patch b/patches/net/minecraft/world/item/alchemy/PotionContents.java.patch new file mode 100644 index 0000000000..90c51e7d35 --- /dev/null +++ b/patches/net/minecraft/world/item/alchemy/PotionContents.java.patch @@ -0,0 +1,13 @@ +--- a/net/minecraft/world/item/alchemy/PotionContents.java ++++ b/net/minecraft/world/item/alchemy/PotionContents.java +@@ -173,6 +_,10 @@ + p_331296_.accept(CommonComponents.EMPTY); + p_331296_.accept(Component.translatable("potion.whenDrank").withStyle(ChatFormatting.DARK_PURPLE)); + ++ // Neo: Override handling of potion attribute tooltips to support IAttributeExtension ++ net.neoforged.neoforge.common.util.AttributeUtil.addPotionTooltip(list, p_331296_); ++ if (true) return; ++ + for (Pair, AttributeModifier> pair : list) { + AttributeModifier attributemodifier = pair.getSecond(); + double d1 = attributemodifier.amount(); diff --git a/patches/net/minecraft/world/item/enchantment/Enchantment.java.patch b/patches/net/minecraft/world/item/enchantment/Enchantment.java.patch index 8237cc26e6..86a3a016cf 100644 --- a/patches/net/minecraft/world/item/enchantment/Enchantment.java.patch +++ b/patches/net/minecraft/world/item/enchantment/Enchantment.java.patch @@ -43,11 +43,10 @@ public boolean canEnchant(ItemStack p_44689_) { return this.definition.supportedItems().contains(p_44689_.getItemHolder()); } -@@ -503,6 +_,15 @@ - public static Enchantment.Builder enchantment(Enchantment.EnchantmentDefinition p_345873_) { +@@ -504,12 +_,26 @@ return new Enchantment.Builder(p_345873_); } -+ + +// TODO: Reimplement. Not sure if we want to patch EnchantmentDefinition or hack this in as an EnchantmentEffectComponent. +// /** +// * Is this enchantment allowed to be enchanted on books via Enchantment Table @@ -56,6 +55,46 @@ +// public boolean isAllowedOnBooks() { +// return true; +// } - ++ public static class Builder { private final Enchantment.EnchantmentDefinition definition; + private HolderSet exclusiveSet = HolderSet.direct(); + private final Map, List> effectLists = new HashMap<>(); + private final DataComponentMap.Builder effectMapBuilder = DataComponentMap.builder(); + ++ /** ++ * Neo: Allow customizing or changing the {@link Component} created by the enchantment builder. ++ */ ++ protected java.util.function.UnaryOperator nameFactory = java.util.function.UnaryOperator.identity(); ++ + public Builder(Enchantment.EnchantmentDefinition p_345317_) { + this.definition = p_345317_; + } +@@ -562,6 +_,16 @@ + return this; + } + ++ /** ++ * Allows specifying an operator that can customize the default {@link Component} created by {@link #build(ResourceLocation)}. ++ * ++ * @return this ++ */ ++ public Enchantment.Builder withCustomName(java.util.function.UnaryOperator nameFactory) { ++ this.nameFactory = nameFactory; ++ return this; ++ } ++ + private List getEffectsList(DataComponentType> p_344770_) { + return (List)this.effectLists.computeIfAbsent(p_344770_, p_346247_ -> { + ArrayList arraylist = new ArrayList<>(); +@@ -572,7 +_,9 @@ + + public Enchantment build(ResourceLocation p_344988_) { + return new Enchantment( +- Component.translatable(Util.makeDescriptionId("enchantment", p_344988_)), this.definition, this.exclusiveSet, this.effectMapBuilder.build() ++ // Neo: permit custom name components instead of a single hardcoded translatable component. ++ this.nameFactory.apply(Component.translatable(Util.makeDescriptionId("enchantment", p_344988_))), ++ this.definition, this.exclusiveSet, this.effectMapBuilder.build() + ); + } + } diff --git a/patches/net/minecraft/world/level/block/CrafterBlock.java.patch b/patches/net/minecraft/world/level/block/CrafterBlock.java.patch new file mode 100644 index 0000000000..ac39be323e --- /dev/null +++ b/patches/net/minecraft/world/level/block/CrafterBlock.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/block/CrafterBlock.java ++++ b/net/minecraft/world/level/block/CrafterBlock.java +@@ -221,6 +_,8 @@ + break; + } + } ++ } else { ++ itemstack = net.neoforged.neoforge.items.VanillaInventoryCodeHooks.insertCrafterOutput(p_335887_, p_307620_, p_307387_, itemstack); + } + + if (!itemstack.isEmpty()) { diff --git a/projects/neoforge/build.gradle b/projects/neoforge/build.gradle index 0393b5455b..669b21be2a 100644 --- a/projects/neoforge/build.gradle +++ b/projects/neoforge/build.gradle @@ -1,10 +1,11 @@ import net.neoforged.jarcompatibilitychecker.gradle.JCCPlugin +import net.neoforged.jarcompatibilitychecker.gradle.CompatibilityTask import net.neoforged.jarcompatibilitychecker.gradle.ProvideNeoForgeJarTask plugins { id 'java-library' id 'maven-publish' - id 'net.neoforged.jarcompatibilitychecker' version '0.1.9' + id 'net.neoforged.jarcompatibilitychecker' version '0.1.12' id 'net.neoforged.gradleutils' id 'neoforge.versioning' } @@ -23,7 +24,8 @@ dynamicProject { } final checkVersion = JCCPlugin.providePreviousVersion( - project.providers, project.providers.provider({['https://maven.neoforged.net/releases']}), project.providers.provider({'net.neoforged:neoforge'}) + project.providers, project.providers.provider({['https://maven.neoforged.net/releases']}), project.providers.provider({'net.neoforged:neoforge'}), + project.provider { project.version }.map { ver -> CompatibilityTask.VersionComponentTest.MINOR.predicate(ver) } ) final createCompatJar = tasks.register('createCompatibilityCheckJar', ProvideNeoForgeJarTask) { // Use the same jar that the patches were generated against @@ -133,6 +135,7 @@ dependencies { } userdevTestImplementation("net.neoforged.fancymodloader:junit-fml:${project.fancy_mod_loader_version}") + compileOnly(jarJar(project(":neoforge-coremods"))) } runTypes { @@ -192,7 +195,7 @@ runs { gameTestServer { } gameTestClient { } data { - programArguments.addAll '--mod', 'neoforge' + arguments.addAll '--mod', 'neoforge' modSources.add project.sourceSets.main @@ -203,11 +206,13 @@ runs { } runs.configureEach { it -> + modSources.add project(":neoforge-coremods").sourceSets.main + final File gameDir = project.file("run/${it.name}") as File gameDir.mkdirs(); it.workingDirectory.set gameDir - it.programArguments.addAll '--gameDir', gameDir.absolutePath + it.arguments.addAll '--gameDir', gameDir.absolutePath } launcherProfile { diff --git a/settings.gradle b/settings.gradle index 33563e5350..74b177945e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,7 +7,7 @@ pluginManagement { } plugins { - id 'net.neoforged.gradle.platform' version '7.0.150' + id 'net.neoforged.gradle.platform' version '7.0.163' } rootProject.name = rootDir.name @@ -24,3 +24,7 @@ include ':tests' project(":tests").projectDir = file("tests") include ':testframework' +include ':coremods' +// Ensure a unique artifact id within JIJ that does not conflict with net.neoforged:coremods, which is +// another external dependency. +project(":coremods").name = "neoforge-coremods" diff --git a/src/generated/resources/assets/c/lang/en_us.json b/src/generated/resources/assets/c/lang/en_us.json index 172b6898c8..3c27e29b49 100644 --- a/src/generated/resources/assets/c/lang/en_us.json +++ b/src/generated/resources/assets/c/lang/en_us.json @@ -53,6 +53,8 @@ "tag.block.c.hidden_from_recipe_viewers": "Hidden From Recipe Viewers", "tag.block.c.netherracks": "Netherracks", "tag.block.c.obsidians": "Obsidians", + "tag.block.c.obsidians.crying": "Crying Obsidians", + "tag.block.c.obsidians.normal": "Normal Obsidians", "tag.block.c.ore_bearing_ground.deepslate": "Deepslate Ore Bearing Ground", "tag.block.c.ore_bearing_ground.netherrack": "Netherrack Ore Bearing Ground", "tag.block.c.ore_bearing_ground.stone": "Stone Ore Bearing Ground", @@ -108,6 +110,8 @@ "tag.block.c.storage_blocks.redstone": "Redstone Storage Blocks", "tag.block.c.storage_blocks.slime": "Slime Storage Blocks", "tag.block.c.storage_blocks.wheat": "Wheat Storage Blocks", + "tag.block.c.stripped_logs": "Stripped Logs", + "tag.block.c.stripped_woods": "Stripped Woods", "tag.block.c.villager_job_sites": "Villager Job Sites", "tag.block.neoforge.enderman_place_on_blacklist": "Enderman Place On Blacklist", "tag.block.neoforge.needs_gold_tool": "Needs Gold Tools", @@ -126,6 +130,7 @@ "tag.entity_type.c.minecarts": "Minecarts", "tag.entity_type.c.teleporting_not_supported": "Teleporting Not Supported", "tag.fluid.c.beetroot_soup": "Beetroot Soup", + "tag.fluid.c.experience": "Experience", "tag.fluid.c.gaseous": "Gaseous", "tag.fluid.c.hidden_from_recipe_viewers": "Hidden From Recipe Viewers", "tag.fluid.c.honey": "Honey", @@ -136,6 +141,7 @@ "tag.fluid.c.rabbit_stew": "Rabbit Stew", "tag.fluid.c.suspicious_stew": "Suspicious Stew", "tag.fluid.c.water": "Water", + "tag.item.c.animal_foods": "Animal Foods", "tag.item.c.armors": "Armors", "tag.item.c.barrels": "Barrels", "tag.item.c.barrels.wooden": "Wooden Barrels", @@ -236,6 +242,7 @@ "tag.item.c.foods.food_poisoning": "Food Poisoning Foods", "tag.item.c.foods.fruit": "Fruits", "tag.item.c.foods.golden": "Golden Foods", + "tag.item.c.foods.pie": "Pies", "tag.item.c.foods.raw_fish": "Raw Fishes", "tag.item.c.foods.raw_meat": "Raw Meats", "tag.item.c.foods.soup": "Soups", @@ -271,6 +278,8 @@ "tag.item.c.nuggets.gold": "Gold Nuggets", "tag.item.c.nuggets.iron": "Iron Nuggets", "tag.item.c.obsidians": "Obsidians", + "tag.item.c.obsidians.crying": "Crying Obsidians", + "tag.item.c.obsidians.normal": "Normal Obsidians", "tag.item.c.ore_bearing_ground.deepslate": "Deepslate Ore Bearing Ground", "tag.item.c.ore_bearing_ground.netherrack": "Netherrack Ore Bearing Ground", "tag.item.c.ore_bearing_ground.stone": "Stone Ore Bearing Ground", @@ -341,6 +350,8 @@ "tag.item.c.storage_blocks.slime": "Slime Storage Blocks", "tag.item.c.storage_blocks.wheat": "Wheat Storage Blocks", "tag.item.c.strings": "Strings", + "tag.item.c.stripped_logs": "Stripped Log Blocks", + "tag.item.c.stripped_woods": "Stripped Wood Blocks", "tag.item.c.tools": "Tools", "tag.item.c.tools.bow": "Bows", "tag.item.c.tools.brush": "Brushes", diff --git a/src/generated/resources/data/c/tags/block/obsidians.json b/src/generated/resources/data/c/tags/block/obsidians.json index aa3315f6bf..3986b73df1 100644 --- a/src/generated/resources/data/c/tags/block/obsidians.json +++ b/src/generated/resources/data/c/tags/block/obsidians.json @@ -1,6 +1,7 @@ { "values": [ - "minecraft:obsidian", + "#c:obsidians/normal", + "#c:obsidians/crying", { "id": "#forge:obsidian", "required": false diff --git a/src/generated/resources/data/c/tags/block/obsidians/crying.json b/src/generated/resources/data/c/tags/block/obsidians/crying.json new file mode 100644 index 0000000000..2e8b37a1bc --- /dev/null +++ b/src/generated/resources/data/c/tags/block/obsidians/crying.json @@ -0,0 +1,5 @@ +{ + "values": [ + "minecraft:crying_obsidian" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/block/obsidians/normal.json b/src/generated/resources/data/c/tags/block/obsidians/normal.json new file mode 100644 index 0000000000..170248454b --- /dev/null +++ b/src/generated/resources/data/c/tags/block/obsidians/normal.json @@ -0,0 +1,5 @@ +{ + "values": [ + "minecraft:obsidian" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/block/stripped_logs.json b/src/generated/resources/data/c/tags/block/stripped_logs.json new file mode 100644 index 0000000000..ae69c996ad --- /dev/null +++ b/src/generated/resources/data/c/tags/block/stripped_logs.json @@ -0,0 +1,13 @@ +{ + "values": [ + "minecraft:stripped_acacia_log", + "minecraft:stripped_bamboo_block", + "minecraft:stripped_birch_log", + "minecraft:stripped_cherry_log", + "minecraft:stripped_dark_oak_log", + "minecraft:stripped_jungle_log", + "minecraft:stripped_mangrove_log", + "minecraft:stripped_oak_log", + "minecraft:stripped_spruce_log" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/block/stripped_woods.json b/src/generated/resources/data/c/tags/block/stripped_woods.json new file mode 100644 index 0000000000..197542891d --- /dev/null +++ b/src/generated/resources/data/c/tags/block/stripped_woods.json @@ -0,0 +1,12 @@ +{ + "values": [ + "minecraft:stripped_acacia_wood", + "minecraft:stripped_birch_wood", + "minecraft:stripped_cherry_wood", + "minecraft:stripped_dark_oak_wood", + "minecraft:stripped_jungle_wood", + "minecraft:stripped_mangrove_wood", + "minecraft:stripped_oak_wood", + "minecraft:stripped_spruce_wood" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/fluid/experience.json b/src/generated/resources/data/c/tags/fluid/experience.json new file mode 100644 index 0000000000..f72d209df7 --- /dev/null +++ b/src/generated/resources/data/c/tags/fluid/experience.json @@ -0,0 +1,3 @@ +{ + "values": [] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/item/animal_foods.json b/src/generated/resources/data/c/tags/item/animal_foods.json new file mode 100644 index 0000000000..f302cacb92 --- /dev/null +++ b/src/generated/resources/data/c/tags/item/animal_foods.json @@ -0,0 +1,28 @@ +{ + "values": [ + "#minecraft:armadillo_food", + "#minecraft:axolotl_food", + "#minecraft:bee_food", + "#minecraft:camel_food", + "#minecraft:cat_food", + "#minecraft:chicken_food", + "#minecraft:cow_food", + "#minecraft:fox_food", + "#minecraft:frog_food", + "#minecraft:goat_food", + "#minecraft:hoglin_food", + "#minecraft:horse_food", + "#minecraft:llama_food", + "#minecraft:ocelot_food", + "#minecraft:panda_food", + "#minecraft:parrot_food", + "#minecraft:pig_food", + "#minecraft:piglin_food", + "#minecraft:rabbit_food", + "#minecraft:sheep_food", + "#minecraft:sniffer_food", + "#minecraft:strider_food", + "#minecraft:turtle_food", + "#minecraft:wolf_food" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/item/enchantables.json b/src/generated/resources/data/c/tags/item/enchantables.json index 71d26a252b..f33d6e0c2d 100644 --- a/src/generated/resources/data/c/tags/item/enchantables.json +++ b/src/generated/resources/data/c/tags/item/enchantables.json @@ -10,11 +10,9 @@ "#minecraft:enchantable/trident", "#minecraft:enchantable/bow", "#minecraft:enchantable/crossbow", + "#minecraft:enchantable/mace", "#minecraft:enchantable/fire_aspect", "#minecraft:enchantable/durability", - { - "id": "#minecraft:enchantable/mace", - "required": false - } + "#minecraft:enchantable/vanishing" ] } \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/item/foods.json b/src/generated/resources/data/c/tags/item/foods.json index 78e6a1945b..401cd7e0e9 100644 --- a/src/generated/resources/data/c/tags/item/foods.json +++ b/src/generated/resources/data/c/tags/item/foods.json @@ -16,6 +16,7 @@ "#c:foods/cooked_fish", "#c:foods/soup", "#c:foods/candy", + "#c:foods/pie", "#c:foods/golden", "#c:foods/edible_when_placed", "#c:foods/food_poisoning" diff --git a/src/generated/resources/data/c/tags/item/foods/pie.json b/src/generated/resources/data/c/tags/item/foods/pie.json new file mode 100644 index 0000000000..7589c5f241 --- /dev/null +++ b/src/generated/resources/data/c/tags/item/foods/pie.json @@ -0,0 +1,5 @@ +{ + "values": [ + "minecraft:pumpkin_pie" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/item/obsidians.json b/src/generated/resources/data/c/tags/item/obsidians.json index aa3315f6bf..3986b73df1 100644 --- a/src/generated/resources/data/c/tags/item/obsidians.json +++ b/src/generated/resources/data/c/tags/item/obsidians.json @@ -1,6 +1,7 @@ { "values": [ - "minecraft:obsidian", + "#c:obsidians/normal", + "#c:obsidians/crying", { "id": "#forge:obsidian", "required": false diff --git a/src/generated/resources/data/c/tags/item/obsidians/crying.json b/src/generated/resources/data/c/tags/item/obsidians/crying.json new file mode 100644 index 0000000000..2e8b37a1bc --- /dev/null +++ b/src/generated/resources/data/c/tags/item/obsidians/crying.json @@ -0,0 +1,5 @@ +{ + "values": [ + "minecraft:crying_obsidian" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/item/obsidians/normal.json b/src/generated/resources/data/c/tags/item/obsidians/normal.json new file mode 100644 index 0000000000..170248454b --- /dev/null +++ b/src/generated/resources/data/c/tags/item/obsidians/normal.json @@ -0,0 +1,5 @@ +{ + "values": [ + "minecraft:obsidian" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/item/stripped_logs.json b/src/generated/resources/data/c/tags/item/stripped_logs.json new file mode 100644 index 0000000000..ae69c996ad --- /dev/null +++ b/src/generated/resources/data/c/tags/item/stripped_logs.json @@ -0,0 +1,13 @@ +{ + "values": [ + "minecraft:stripped_acacia_log", + "minecraft:stripped_bamboo_block", + "minecraft:stripped_birch_log", + "minecraft:stripped_cherry_log", + "minecraft:stripped_dark_oak_log", + "minecraft:stripped_jungle_log", + "minecraft:stripped_mangrove_log", + "minecraft:stripped_oak_log", + "minecraft:stripped_spruce_log" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/c/tags/item/stripped_woods.json b/src/generated/resources/data/c/tags/item/stripped_woods.json new file mode 100644 index 0000000000..197542891d --- /dev/null +++ b/src/generated/resources/data/c/tags/item/stripped_woods.json @@ -0,0 +1,12 @@ +{ + "values": [ + "minecraft:stripped_acacia_wood", + "minecraft:stripped_birch_wood", + "minecraft:stripped_cherry_wood", + "minecraft:stripped_dark_oak_wood", + "minecraft:stripped_jungle_wood", + "minecraft:stripped_mangrove_wood", + "minecraft:stripped_oak_wood", + "minecraft:stripped_spruce_wood" + ] +} \ No newline at end of file diff --git a/src/main/java/net/neoforged/neoforge/capabilities/CapabilityListenerHolder.java b/src/main/java/net/neoforged/neoforge/capabilities/CapabilityListenerHolder.java index 7f8a20494b..69cf58b33a 100644 --- a/src/main/java/net/neoforged/neoforge/capabilities/CapabilityListenerHolder.java +++ b/src/main/java/net/neoforged/neoforge/capabilities/CapabilityListenerHolder.java @@ -93,6 +93,8 @@ public void clean() { continue; var set = chunkHolder.get(ref.pos.asLong()); + if (set == null) + continue; // We might remove a different garbage-collected reference, // or we might remove nothing if the reference was already removed. // Because the hash codes will match, that is fine. diff --git a/src/main/java/net/neoforged/neoforge/client/ClientHooks.java b/src/main/java/net/neoforged/neoforge/client/ClientHooks.java index 2349977464..8bc74f258c 100644 --- a/src/main/java/net/neoforged/neoforge/client/ClientHooks.java +++ b/src/main/java/net/neoforged/neoforge/client/ClientHooks.java @@ -137,6 +137,7 @@ import net.neoforged.fml.ModLoader; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.common.asm.enumextension.ExtensionInfo; +import net.neoforged.neoforge.client.entity.animation.json.AnimationTypeManager; import net.neoforged.neoforge.client.event.AddSectionGeometryEvent; import net.neoforged.neoforge.client.event.CalculateDetachedCameraDistanceEvent; import net.neoforged.neoforge.client.event.CalculatePlayerTurnEvent; @@ -950,7 +951,7 @@ public static boolean isBlockEntityRendererVisible(Block /** * Modify the position and UVs of the edge quads of generated item models to account for sprite expansion of the * front and back quad. Fixes MC-73186 on generated item models. - * + * * @param elements The generated elements, may include the front and back face * @param sprite The texture from which the elements were generated * @return the original elements list @@ -1035,13 +1036,15 @@ public static void initClientHooks(Minecraft mc, ReloadableResourceManager resou ItemDecoratorHandler.init(); PresetEditorManager.init(); MapDecorationRendererManager.init(); + DimensionTransitionScreenManager.init(); + AnimationTypeManager.init(); } /** * Fires {@link RenderFrameEvent.Pre}. Called just before {@link GameRenderer#render(float, long, boolean)} in {@link Minecraft#runTick(boolean)}. *

* Fired before the profiler section for "gameRenderer" is started. - * + * * @param partialTick The current partial tick */ public static void fireRenderFramePre(DeltaTracker partialTick) { @@ -1052,7 +1055,7 @@ public static void fireRenderFramePre(DeltaTracker partialTick) { * Fires {@link RenderFrameEvent.Post}. Called just after {@link GameRenderer#render(float, long, boolean)} in {@link Minecraft#runTick(boolean)}. *

* Fired after the profiler section for "gameRenderer" is ended. - * + * * @param partialTick The current partial tick */ public static void fireRenderFramePost(DeltaTracker partialRick) { @@ -1087,7 +1090,7 @@ public static RegistryLookup resolveLookup(ResourceKey * Called from {@link EffectRenderingInventoryScreen#renderEffects} just before {@link GuiGraphics#renderTooltip(Font, List, Optional, int, int)} is called. - * + * * @param screen The screen rendering the tooltip. * @param effectInst The effect instance whose tooltip is being rendered. * @param tooltip An immutable list containing the existing tooltip lines, which consist of the name and the duration. diff --git a/src/main/java/net/neoforged/neoforge/client/ClientNeoForgeMod.java b/src/main/java/net/neoforged/neoforge/client/ClientNeoForgeMod.java index cdf8b961d4..071977233d 100644 --- a/src/main/java/net/neoforged/neoforge/client/ClientNeoForgeMod.java +++ b/src/main/java/net/neoforged/neoforge/client/ClientNeoForgeMod.java @@ -18,10 +18,12 @@ import net.neoforged.fml.ModContainer; import net.neoforged.fml.common.Mod; import net.neoforged.fml.config.ModConfigs; +import net.neoforged.neoforge.client.entity.animation.json.AnimationLoader; import net.neoforged.neoforge.client.event.ClientPlayerNetworkEvent; import net.neoforged.neoforge.client.event.ModelEvent; import net.neoforged.neoforge.client.event.RegisterClientReloadListenersEvent; import net.neoforged.neoforge.client.event.RegisterNamedRenderTypesEvent; +import net.neoforged.neoforge.client.event.RegisterSpriteSourceTypesEvent; import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; import net.neoforged.neoforge.client.extensions.common.RegisterClientExtensionsEvent; import net.neoforged.neoforge.client.gui.ConfigurationScreen; @@ -33,6 +35,7 @@ import net.neoforged.neoforge.client.model.ItemLayerModel; import net.neoforged.neoforge.client.model.SeparateTransformsModel; import net.neoforged.neoforge.client.model.obj.ObjLoader; +import net.neoforged.neoforge.client.textures.NamespacedDirectoryLister; import net.neoforged.neoforge.common.ModConfigSpec; import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.common.NeoForgeMod; @@ -74,6 +77,7 @@ static void onRegisterGeometryLoaders(ModelEvent.RegisterGeometryLoaders event) @SubscribeEvent static void onRegisterReloadListeners(RegisterClientReloadListenersEvent event) { event.registerReloadListener(ObjLoader.INSTANCE); + event.registerReloadListener(AnimationLoader.INSTANCE); } @SubscribeEvent @@ -81,6 +85,11 @@ static void onRegisterNamedRenderTypes(RegisterNamedRenderTypesEvent event) { event.register(ResourceLocation.fromNamespaceAndPath("neoforge", "item_unlit"), RenderType.translucent(), NeoForgeRenderTypes.ITEM_UNSORTED_UNLIT_TRANSLUCENT.get()); } + @SubscribeEvent + static void onRegisterSpriteSourceTypes(RegisterSpriteSourceTypesEvent event) { + event.register(NamespacedDirectoryLister.ID, NamespacedDirectoryLister.TYPE); + } + @SubscribeEvent static void onRegisterClientExtensions(RegisterClientExtensionsEvent event) { event.registerFluidType(new IClientFluidTypeExtensions() { diff --git a/src/main/java/net/neoforged/neoforge/client/DimensionTransitionScreenManager.java b/src/main/java/net/neoforged/neoforge/client/DimensionTransitionScreenManager.java new file mode 100644 index 0000000000..86a69eaa1e --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/DimensionTransitionScreenManager.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client; + +import com.mojang.datafixers.util.Pair; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BooleanSupplier; +import net.minecraft.client.gui.screens.ReceivingLevelScreen; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; +import net.neoforged.fml.ModLoader; +import net.neoforged.neoforge.client.event.RegisterDimensionTransitionScreenEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +public class DimensionTransitionScreenManager { + private static final Map, ResourceKey>, ReceivingLevelScreenFactory> conditionalDimensionEffects = new HashMap<>(); + private static final Map, ReceivingLevelScreenFactory> toDimensionTransitions = new HashMap<>(); + private static final Map, ReceivingLevelScreenFactory> fromDimensionTransitions = new HashMap<>(); + + @ApiStatus.Internal + static void init() { + ModLoader.postEventWrapContainerInModOrder(new RegisterDimensionTransitionScreenEvent(conditionalDimensionEffects, toDimensionTransitions, fromDimensionTransitions)); + } + + public static ReceivingLevelScreenFactory getScreenFromLevel(@Nullable Level target, @Nullable Level source) { + if (source == null) { //source level is null on login: transition screen should not appear in this case + return getScreen(null, null); + } else if (target == null) { //the target level shouldn't ever be null, but anyone could call Minecraft.setLevel and pass null in + return getScreen(null, source.dimension()); + } + return getScreen(target.dimension(), source.dimension()); + } + + public static ReceivingLevelScreenFactory getScreen(@Nullable ResourceKey toDimension, @Nullable ResourceKey fromDimension) { + var conditionalScreen = conditionalDimensionEffects.get(Pair.of(toDimension, fromDimension)); + if (conditionalScreen != null) { + return conditionalScreen; + } + var toDim = toDimensionTransitions.get(toDimension); + if (toDim != null) { + return toDim; + } + var fromDim = fromDimensionTransitions.get(fromDimension); + if (fromDim != null) { + return fromDim; + } + return ReceivingLevelScreen::new; + } + + public interface ReceivingLevelScreenFactory { + ReceivingLevelScreen create(BooleanSupplier supplier, ReceivingLevelScreen.Reason reason); + } +} diff --git a/src/main/java/net/neoforged/neoforge/client/entity/animation/AnimationKeyframeTarget.java b/src/main/java/net/neoforged/neoforge/client/entity/animation/AnimationKeyframeTarget.java new file mode 100644 index 0000000000..cbbac5b2ca --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/entity/animation/AnimationKeyframeTarget.java @@ -0,0 +1,16 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.entity.animation; + +import org.joml.Vector3f; + +/** + * A function for transforming vectors into values that make sense to their keyframe's target. + */ +@FunctionalInterface +public interface AnimationKeyframeTarget { + Vector3f apply(float x, float y, float z); +} diff --git a/src/main/java/net/neoforged/neoforge/client/entity/animation/AnimationTarget.java b/src/main/java/net/neoforged/neoforge/client/entity/animation/AnimationTarget.java new file mode 100644 index 0000000000..a4d093e9af --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/entity/animation/AnimationTarget.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.entity.animation; + +import net.minecraft.client.animation.AnimationChannel; +import net.minecraft.client.animation.KeyframeAnimations; +import org.joml.Vector3f; + +/** + * Wrapper for a {@link AnimationChannel.Target} and a way to transform a simple keyframe vector into a vector that + * makes sense for the given target. + * + * @param channelTarget The associated {@link AnimationChannel.Target}. + * @param keyframeTarget An {@link AnimationKeyframeTarget} that transforms simple vectors into ones that make sense + * for the {@link #channelTarget}. + * @param inverseKeyframeTarget The inverse function of {@link #keyframeTarget}, used for serialization. + */ +public record AnimationTarget( + AnimationChannel.Target channelTarget, + AnimationKeyframeTarget keyframeTarget, + AnimationKeyframeTarget inverseKeyframeTarget) { + + public static final AnimationTarget POSITION = new AnimationTarget( + AnimationChannel.Targets.POSITION, + KeyframeAnimations::posVec, + KeyframeAnimations::posVec // It's its own inverse + ); + public static final AnimationTarget ROTATION = new AnimationTarget( + AnimationChannel.Targets.ROTATION, + KeyframeAnimations::degreeVec, + AnimationTarget::inverseDegreeVec); + public static final AnimationTarget SCALE = new AnimationTarget( + AnimationChannel.Targets.SCALE, + KeyframeAnimations::scaleVec, + AnimationTarget::inverseScaleVec); + private static Vector3f inverseDegreeVec(float x, float y, float z) { + return new Vector3f( + x / (float) (Math.PI / 180.0), + y / (float) (Math.PI / 180.0), + z / (float) (Math.PI / 180.0)); + } + + private static Vector3f inverseScaleVec(double x, double y, double z) { + return new Vector3f((float) (x + 1f), (float) (y + 1f), (float) (z + 1f)); + } + + @Override + public boolean equals(Object obj) { + return this == obj; + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } +} diff --git a/src/main/java/net/neoforged/neoforge/client/entity/animation/json/AnimationHolder.java b/src/main/java/net/neoforged/neoforge/client/entity/animation/json/AnimationHolder.java new file mode 100644 index 0000000000..1222a7efe3 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/entity/animation/json/AnimationHolder.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.entity.animation.json; + +import com.mojang.logging.LogUtils; +import java.util.Map; +import net.minecraft.client.animation.AnimationDefinition; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; + +/** + * Holds a single {@link AnimationDefinition} loaded from resource packs. Objects of this class will be automatically updated with new + * {@link AnimationDefinition}s on reload. + */ +public final class AnimationHolder { + public static final AnimationDefinition EMPTY_ANIMATION = new AnimationDefinition(0f, false, Map.of()); + + private static final Logger LOGGER = LogUtils.getLogger(); + + private final ResourceLocation key; + @Nullable + private AnimationDefinition value; + private boolean absentWarned; + + AnimationHolder(ResourceLocation key) { + this.key = key; + } + + void unbind() { + value = null; + absentWarned = false; + } + + void bind(AnimationDefinition value) { + this.value = value; + } + + /** + * Gets the key associated with this animation. + */ + public ResourceLocation key() { + return key; + } + + /** + * Gets the currently loaded animation. If the animation has not been loaded, returns {@link #EMPTY_ANIMATION}. + */ + public AnimationDefinition get() { + final var result = value; + if (result == null) { + if (!absentWarned) { + absentWarned = true; + LOGGER.warn("Missing entity animation {}", key); + } + return EMPTY_ANIMATION; + } + return result; + } + + /** + * Gets the currently loaded animation or null if it has not been loaded. + */ + @Nullable + public AnimationDefinition getOrNull() { + return value; + } + + /** + * Returns whether the animation has been loaded. + */ + public boolean isBound() { + return value != null; + } +} diff --git a/src/main/java/net/neoforged/neoforge/client/entity/animation/json/AnimationLoader.java b/src/main/java/net/neoforged/neoforge/client/entity/animation/json/AnimationLoader.java new file mode 100644 index 0000000000..8fd278c8fc --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/entity/animation/json/AnimationLoader.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.entity.animation.json; + +import com.google.common.collect.MapMaker; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.mojang.logging.LogUtils; +import com.mojang.serialization.JsonOps; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import net.minecraft.client.animation.AnimationDefinition; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener; +import net.minecraft.util.profiling.ProfilerFiller; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; + +/** + * A loader for entity animations written in JSON. You can also get parsed animations from this class. + */ +public final class AnimationLoader extends SimpleJsonResourceReloadListener { + private static final Logger LOGGER = LogUtils.getLogger(); + + public static final AnimationLoader INSTANCE = new AnimationLoader(); + + private final Map animations = new MapMaker().weakValues().concurrencyLevel(1).makeMap(); + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + private final List strongHolderReferences = new ArrayList<>(); + + private AnimationLoader() { + super(new Gson(), "neoforge/animations/entity"); + } + + /** + * Gets a loaded {@link AnimationDefinition} with the specified {@code key}. + */ + @Nullable + public AnimationDefinition getAnimation(ResourceLocation key) { + final var holder = animations.get(key); + return holder != null ? holder.getOrNull() : null; + } + + /** + * Returns an {@link AnimationHolder} for an animation. If the specified animation has not been loaded, the holder + * will be unbound, but may be bound in the future. + */ + public AnimationHolder getAnimationHolder(ResourceLocation key) { + return animations.computeIfAbsent(key, AnimationHolder::new); + } + + @Override + protected void apply(Map animationJsons, ResourceManager resourceManager, ProfilerFiller profiler) { + animations.values().forEach(AnimationHolder::unbind); + strongHolderReferences.clear(); + int loaded = 0; + for (final var entry : animationJsons.entrySet()) { + try { + final var animation = AnimationParser.CODEC.parse(JsonOps.INSTANCE, entry.getValue()) + .getOrThrow(JsonParseException::new); + final var holder = getAnimationHolder(entry.getKey()); + holder.bind(animation); + strongHolderReferences.add(holder); + loaded++; + } catch (Exception e) { + LOGGER.error("Failed to load animation {}", entry.getKey(), e); + } + } + LOGGER.info("Loaded {} entity animations", loaded); + } +} diff --git a/src/main/java/net/neoforged/neoforge/client/entity/animation/json/AnimationParser.java b/src/main/java/net/neoforged/neoforge/client/entity/animation/json/AnimationParser.java new file mode 100644 index 0000000000..463f4da7b8 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/entity/animation/json/AnimationParser.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.entity.animation.json; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.KeyDispatchCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import it.unimi.dsi.fastutil.Pair; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.function.UnaryOperator; +import net.minecraft.client.animation.AnimationChannel; +import net.minecraft.client.animation.AnimationDefinition; +import net.minecraft.client.animation.Keyframe; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.ExtraCodecs; +import net.neoforged.neoforge.client.entity.animation.AnimationKeyframeTarget; +import net.neoforged.neoforge.client.entity.animation.AnimationTarget; +import org.joml.Vector3f; + +/** + * A parser for parsing JSON-based entity animation files. + */ +public final class AnimationParser { + /** + * {@snippet lang = JSON : "minecraft:rotation" + * } + */ + private static final Codec TARGET_CODEC = ResourceLocation.CODEC + .flatXmap( + name -> Optional.ofNullable(AnimationTypeManager.getTarget(name)) + .map(DataResult::success) + .orElseGet(() -> DataResult.error(() -> String.format( + Locale.ENGLISH, "Animation target '%s' not found. Registered targets: %s", + name, AnimationTypeManager.getTargetList()))), + target -> Optional.ofNullable(AnimationTypeManager.getTargetName(target)) + .map(DataResult::success) + .orElseGet(() -> DataResult.error(() -> String.format( + Locale.ENGLISH, "Unregistered animation target '%s'. Registered targets: %s", + target, AnimationTypeManager.getTargetList())))); + + /** + * {@snippet lang = JSON : "minecraft:linear" + * } + */ + private static final Codec INTERPOLATION_CODEC = ResourceLocation.CODEC + .flatXmap( + name -> Optional.ofNullable(AnimationTypeManager.getInterpolation(name)) + .map(DataResult::success) + .orElseGet(() -> DataResult.error(() -> String.format( + Locale.ENGLISH, "Animation interpolation '%s' not found. Registered interpolations: %s", + name, AnimationTypeManager.getInterpolationList()))), + target -> Optional.ofNullable(AnimationTypeManager.getInterpolationName(target)) + .map(DataResult::success) + .orElseGet(() -> DataResult.error(() -> String.format( + Locale.ENGLISH, "Unregistered animation interpolation '%s'. Registered interpolations: %s", + target, AnimationTypeManager.getInterpolationList())))); + + /** + * {@snippet lang = JSON : + * { + * "keyframes": [ + * { + * "timestamp": 0.5, + * "target": [22.5, 0.0, 0.0], + * "interpolation": "minecraft:linear" + * } + * ], + * "target": "minecraft:rotation" + * } + * } + */ + public static final MapCodec CHANNEL_CODEC = new KeyDispatchCodec<>( + "target", + TARGET_CODEC, + channel -> Optional.ofNullable(AnimationTypeManager.getTargetFromChannelTarget(channel.target())) + .map(DataResult::success) + .orElseGet(() -> DataResult.error(() -> String.format( + Locale.ENGLISH, "Unregistered animation channel target '%s'. Registered targets: %s", + channel.target(), AnimationTypeManager.getTargetList()))), + target -> DataResult.success( + Optional.ofNullable(AnimationTypeManager.getKeyframeCodec(target)) + .orElseGet(() -> keyframeCodec(target)) + .listOf() + .xmap( + keyframes -> new AnimationChannel(target.channelTarget(), keyframes.toArray(Keyframe[]::new)), + channel -> Arrays.asList(channel.keyframes())) + .fieldOf("keyframes"))); + + /** + * {@snippet lang = JSON : + * { + * "bone": "head", + * "keyframes": [ + * { + * "timestamp": 0.5, + * "target": [22.5, 0.0, 0.0], + * "interpolation": "minecraft:linear" + * } + * ], + * "target": "minecraft:rotation" + * } + * } + */ + private static final Codec> NAMED_CHANNEL_CODEC = RecordCodecBuilder.create( + instance -> instance.group( + Codec.STRING.fieldOf("bone").forGetter(Pair::key), + CHANNEL_CODEC.forGetter(Pair::value)).apply(instance, Pair::of)); + + /** + * {@snippet lang = JSON : + * { + * "length": 1.125, + * "loop": true, + * "animations": [ + * { + * "bone": "head", + * "keyframes": [ + * { + * "timestamp": 0.5, + * "target": [22.5, 0.0, 0.0], + * "interpolation": "minecraft:linear" + * } + * ] + * } + * ] + * } + * } + */ + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + Codec.FLOAT.fieldOf("length").forGetter(AnimationDefinition::lengthInSeconds), + Codec.BOOL.optionalFieldOf("loop", false).forGetter(AnimationDefinition::looping), + NAMED_CHANNEL_CODEC.listOf() + .>>xmap( + list -> { + final var result = new HashMap>(); + for (final var animation : list) { + result.computeIfAbsent(animation.key(), k -> new ArrayList<>()).add(animation.value()); + } + return result; + }, + map -> { + final var result = new ArrayList>(); + for (final var entry : map.entrySet()) { + for (final var channel : entry.getValue()) { + result.add(Pair.of(entry.getKey(), channel)); + } + } + return result; + }) + .fieldOf("animations") + .forGetter(AnimationDefinition::boneAnimations)) + .apply(instance, AnimationDefinition::new)); + + private AnimationParser() {} + + /** + * {@snippet lang = JSON : + * { + * "timestamp": 0.5, + * "target": [22.5, 0.0, 0.0], + * "interpolation": "minecraft:linear" + * } + * } + */ + static Codec keyframeCodec(AnimationTarget target) { + return RecordCodecBuilder.create( + instance -> instance.group( + Codec.FLOAT.fieldOf("timestamp").forGetter(Keyframe::timestamp), + ExtraCodecs.VECTOR3F + .xmap( + keyframeTargetToUnaryOp(target.keyframeTarget()), + keyframeTargetToUnaryOp(target.inverseKeyframeTarget())) + .fieldOf("target") + .forGetter(Keyframe::target), + INTERPOLATION_CODEC.fieldOf("interpolation").forGetter(Keyframe::interpolation)).apply(instance, Keyframe::new)); + } + + private static UnaryOperator keyframeTargetToUnaryOp(AnimationKeyframeTarget target) { + return vec -> target.apply(vec.x, vec.y, vec.z); + } +} diff --git a/src/main/java/net/neoforged/neoforge/client/entity/animation/json/AnimationTypeManager.java b/src/main/java/net/neoforged/neoforge/client/entity/animation/json/AnimationTypeManager.java new file mode 100644 index 0000000000..7e309bcdab --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/entity/animation/json/AnimationTypeManager.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.entity.animation.json; + +import com.google.common.collect.ImmutableBiMap; +import com.google.common.collect.ImmutableMap; +import com.mojang.serialization.Codec; +import java.util.function.Function; +import java.util.stream.Collectors; +import net.minecraft.client.animation.AnimationChannel; +import net.minecraft.client.animation.Keyframe; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.fml.ModLoader; +import net.neoforged.neoforge.client.entity.animation.AnimationTarget; +import net.neoforged.neoforge.client.event.RegisterJsonAnimationTypesEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +/** + * Manager for custom {@link AnimationTarget}s and {@link AnimationChannel.Interpolation interpolation function}s. + *

+ * The built-in {@link AnimationTarget}s are: {@code minecraft:position}, {@code minecraft:rotation}, and + * {@code minecraft:scale}. + *

+ * The built-in {@link AnimationChannel.Interpolation interpolation function}s are {@code minecraft:linear} and + * {@code minecraft:catmullrom}. + */ +public final class AnimationTypeManager { + private static final ImmutableBiMap DEFAULT_TARGETS = ImmutableBiMap.of( + ResourceLocation.withDefaultNamespace("position"), AnimationTarget.POSITION, + ResourceLocation.withDefaultNamespace("rotation"), AnimationTarget.ROTATION, + ResourceLocation.withDefaultNamespace("scale"), AnimationTarget.SCALE); + private static final ImmutableBiMap DEFAULT_INTERPOLATIONS = ImmutableBiMap.of( + ResourceLocation.withDefaultNamespace("linear"), AnimationChannel.Interpolations.LINEAR, + ResourceLocation.withDefaultNamespace("catmullrom"), AnimationChannel.Interpolations.CATMULLROM); + + private static ImmutableBiMap TARGETS = DEFAULT_TARGETS; + private static ImmutableMap TARGETS_BY_CHANNEL_TARGET = ImmutableMap.of(); + private static ImmutableMap> KEYFRAME_CODECS = ImmutableMap.of(); + private static ImmutableBiMap INTERPOLATIONS = DEFAULT_INTERPOLATIONS; + private static String TARGET_LIST = ""; + private static String INTERPOLATION_LIST = ""; + + static { + recomputeDerivedFields(); + } + + private AnimationTypeManager() {} + + /** + * Gets the {@link AnimationTarget} associated with the given {@code name}. + */ + @Nullable + public static AnimationTarget getTarget(ResourceLocation name) { + return TARGETS.get(name); + } + + /** + * Gets the {@link ResourceLocation} associated with the given {@code target}. + */ + @Nullable + public static ResourceLocation getTargetName(AnimationTarget target) { + return TARGETS.inverse().get(target); + } + + /** + * Gets the full {@link AnimationTarget} from its {@link AnimationTarget#channelTarget() channelTarget}. + */ + @Nullable + public static AnimationTarget getTargetFromChannelTarget(AnimationChannel.Target target) { + return TARGETS_BY_CHANNEL_TARGET.get(target); + } + + /** + * Gets the {@link Codec} used to decode a {@link Keyframe} with the specified {@link AnimationTarget}. + */ + @Nullable + public static Codec getKeyframeCodec(AnimationTarget target) { + return KEYFRAME_CODECS.get(target); + } + + /** + * Gets the {@link AnimationChannel.Interpolation interpolation function} associated with the given {@code name}. + */ + @Nullable + public static AnimationChannel.Interpolation getInterpolation(ResourceLocation name) { + return INTERPOLATIONS.get(name); + } + + /** + * Gets the {@link ResourceLocation} associated with the given {@code interpolation}. + */ + @Nullable + public static ResourceLocation getInterpolationName(AnimationChannel.Interpolation interpolation) { + return INTERPOLATIONS.inverse().get(interpolation); + } + + /** + * Retrieves a comma-separated list of all available {@link AnimationTarget}s, for use in error messages. + */ + public static String getTargetList() { + return TARGET_LIST; + } + + /** + * Retrieves a comma-separated list of all available + * {@link AnimationChannel.Interpolation interpolation function}s, for use in error messages. + */ + public static String getInterpolationList() { + return INTERPOLATION_LIST; + } + + @ApiStatus.Internal + public static void init() { + final var targets = ImmutableBiMap.builder().putAll(DEFAULT_TARGETS); + final var interpolations = ImmutableBiMap.builder().putAll(DEFAULT_INTERPOLATIONS); + final var event = new RegisterJsonAnimationTypesEvent(targets, interpolations); + ModLoader.postEventWrapContainerInModOrder(event); + TARGETS = targets.buildOrThrow(); + INTERPOLATIONS = interpolations.buildOrThrow(); + recomputeDerivedFields(); + } + + private static void recomputeDerivedFields() { + TARGETS_BY_CHANNEL_TARGET = TARGETS.values() + .stream() + .collect(ImmutableMap.toImmutableMap(AnimationTarget::channelTarget, Function.identity())); + KEYFRAME_CODECS = TARGETS.values() + .stream() + .collect(ImmutableMap.toImmutableMap(Function.identity(), AnimationParser::keyframeCodec)); + TARGET_LIST = TARGETS.keySet() + .stream() + .map(ResourceLocation::toString) + .collect(Collectors.joining(", ")); + INTERPOLATION_LIST = INTERPOLATIONS.keySet() + .stream() + .map(ResourceLocation::toString) + .collect(Collectors.joining(", ")); + } +} diff --git a/src/main/java/net/neoforged/neoforge/client/entity/animation/json/package-info.java b/src/main/java/net/neoforged/neoforge/client/entity/animation/json/package-info.java new file mode 100644 index 0000000000..1f3500287e --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/entity/animation/json/package-info.java @@ -0,0 +1,13 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +@FieldsAreNonnullByDefault +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +package net.neoforged.neoforge.client.entity.animation.json; + +import javax.annotation.ParametersAreNonnullByDefault; +import net.minecraft.FieldsAreNonnullByDefault; +import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/net/neoforged/neoforge/client/entity/animation/package-info.java b/src/main/java/net/neoforged/neoforge/client/entity/animation/package-info.java new file mode 100644 index 0000000000..c8fda9c36c --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/entity/animation/package-info.java @@ -0,0 +1,13 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +@FieldsAreNonnullByDefault +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +package net.neoforged.neoforge.client.entity.animation; + +import javax.annotation.ParametersAreNonnullByDefault; +import net.minecraft.FieldsAreNonnullByDefault; +import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/net/neoforged/neoforge/client/event/AddAttributeTooltipsEvent.java b/src/main/java/net/neoforged/neoforge/client/event/AddAttributeTooltipsEvent.java new file mode 100644 index 0000000000..b39ffb1fe5 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/event/AddAttributeTooltipsEvent.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.event; + +import java.util.function.Consumer; +import net.minecraft.core.component.DataComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.ItemAttributeModifiers; +import net.neoforged.bus.api.Event; +import net.neoforged.neoforge.common.util.AttributeTooltipContext; +import net.neoforged.neoforge.common.util.AttributeUtil; + +/** + * This event is fired after attribute tooltip lines have been added to an item stack's tooltip in {@link AttributeUtil#addAttributeTooltips}. + *

+ * It can be used to add additional tooltip lines adjacent to the attribute lines without having to manually locate the inject point. + *

+ * This event may be fired on both the logical client and logical server. + */ +public class AddAttributeTooltipsEvent extends Event { + protected final ItemStack stack; + protected final Consumer tooltip; + protected final AttributeTooltipContext ctx; + + public AddAttributeTooltipsEvent(ItemStack stack, Consumer tooltip, AttributeTooltipContext ctx) { + this.stack = stack; + this.tooltip = tooltip; + this.ctx = ctx; + } + + /** + * The current tooltip context. + */ + public AttributeTooltipContext getContext() { + return this.ctx; + } + + /** + * The {@link ItemStack} with the tooltip. + */ + public ItemStack getStack() { + return this.stack; + } + + /** + * Adds one or more {@link Component}s to the tooltip. + */ + public void addTooltipLines(Component... comps) { + for (Component comp : comps) { + this.tooltip.accept(comp); + } + } + + /** + * Checks if the attribute tooltips should be shown on the current item stack. + *

+ * This event is fired even if the component would prevent the normal tooltip lines from showing. + */ + public boolean shouldShow() { + return this.stack.getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.EMPTY).showInTooltip(); + } +} diff --git a/src/main/java/net/neoforged/neoforge/client/event/GatherSkippedAttributeTooltipsEvent.java b/src/main/java/net/neoforged/neoforge/client/event/GatherSkippedAttributeTooltipsEvent.java new file mode 100644 index 0000000000..851439e16d --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/event/GatherSkippedAttributeTooltipsEvent.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.event; + +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EquipmentSlotGroup; +import net.minecraft.world.item.ItemStack; +import net.neoforged.bus.api.Event; +import net.neoforged.neoforge.common.util.AttributeTooltipContext; +import org.jetbrains.annotations.Nullable; + +/** + * This event is used to collect the IDs of attribute modifiers that will not be displayed in item tooltips. + *

+ * It allows hiding some (or all) of the modifiers, potentially for displaying them in an alternative way (or for hiding information from the player). + *

+ * This event may be fired on both the logical client and logical server. + */ +public class GatherSkippedAttributeTooltipsEvent extends Event { + protected final ItemStack stack; + protected final AttributeTooltipContext ctx; + + @Nullable + private Set skippedIds = null; + + @Nullable + private Set skippedGroups = null; + + private boolean skipAll = false; + + public GatherSkippedAttributeTooltipsEvent(ItemStack stack, AttributeTooltipContext ctx) { + this.stack = stack; + this.ctx = ctx; + // Skip sets are lazily initialized by the getter functions to avoid memory churn + } + + /** + * The current tooltip context. + */ + public AttributeTooltipContext getContext() { + return this.ctx; + } + + /** + * The {@link ItemStack} with the tooltip. + */ + public ItemStack getStack() { + return this.stack; + } + + /** + * Marks the id of a specific attribute modifier as skipped, causing it to not be displayed in the tooltip. + */ + public void skipId(ResourceLocation id) { + this.getSkippedIds().add(id); + } + + /** + * Marks an entire {@link EquipmentSlotGroup} as skipped, preventing all modifiers for that group from showing. + */ + public void skipGroup(EquipmentSlotGroup group) { + this.getSkippedGroups().add(group); + } + + /** + * Checks if a given id is skipped or not. If all modifiers are skipped, this method always returns true. + */ + public boolean isSkipped(ResourceLocation id) { + return this.skipAll || (this.skippedIds != null && this.skippedIds.contains(id)); + } + + /** + * Checks if a given group is skipped or not. If all modifiers are skipped, this method always returns true. + */ + public boolean isSkipped(EquipmentSlotGroup group) { + return this.skipAll || (this.skippedGroups != null && this.skippedGroups.contains(group)); + } + + /** + * Sets if the event should skip displaying all attribute modifiers. + */ + public void setSkipAll(boolean skip) { + this.skipAll = skip; + } + + /** + * Checks if the event will cause all attribute modifiers to be skipped. + */ + public boolean isSkippingAll() { + return this.skipAll; + } + + /** + * Initializes {@link #skippedIds} if necessary, and returns it. + */ + protected Set getSkippedIds() { + if (this.skippedIds == null) { + this.skippedIds = new HashSet<>(); + } + return this.skippedIds; + } + + /** + * Initializes {@link #skippedGroups} if necessary, and returns it. + */ + protected Set getSkippedGroups() { + if (this.skippedGroups == null) { + this.skippedGroups = EnumSet.noneOf(EquipmentSlotGroup.class); + } + return this.skippedGroups; + } +} diff --git a/src/main/java/net/neoforged/neoforge/client/event/RegisterDimensionTransitionScreenEvent.java b/src/main/java/net/neoforged/neoforge/client/event/RegisterDimensionTransitionScreenEvent.java new file mode 100644 index 0000000000..bf4e500f39 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/event/RegisterDimensionTransitionScreenEvent.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.event; + +import com.mojang.datafixers.util.Pair; +import java.util.Map; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; +import net.neoforged.bus.api.Event; +import net.neoforged.bus.api.ICancellableEvent; +import net.neoforged.fml.LogicalSide; +import net.neoforged.fml.event.IModBusEvent; +import net.neoforged.neoforge.client.DimensionTransitionScreenManager.ReceivingLevelScreenFactory; +import org.jetbrains.annotations.ApiStatus; + +/** + *

Event for registering screen effects when transitioning across dimensions. + * Note that there is a priority order when it comes to what screens are displayed:
+ * - Using registerConditionalEffect has priority over the usual transition effects, and will only fire when travelling to the specified dimension coming from a certain dimension.
+ * - If a dimension has a screen that displays when entering it, that will have priority over a dimension that has one when you leave it.

+ * + *

This event is not {@linkplain ICancellableEvent cancellable}, and does not {@linkplain HasResult have a result}. + * + *

This event is fired on the mod-specific event bus, only on the {@linkplain LogicalSide#CLIENT logical client}.

+ */ +public class RegisterDimensionTransitionScreenEvent extends Event implements IModBusEvent { + private final Map, ResourceKey>, ReceivingLevelScreenFactory> conditionalDimensionEffects; + private final Map, ReceivingLevelScreenFactory> toEffects; + private final Map, ReceivingLevelScreenFactory> fromEffects; + + @ApiStatus.Internal + public RegisterDimensionTransitionScreenEvent(Map, ResourceKey>, ReceivingLevelScreenFactory> conditionalDimensionEffects, + Map, ReceivingLevelScreenFactory> toEffects, + Map, ReceivingLevelScreenFactory> fromEffects) { + this.conditionalDimensionEffects = conditionalDimensionEffects; + this.toEffects = toEffects; + this.fromEffects = fromEffects; + } + + /** + * Registers a dimension transition when traveling to a dimension. + * + * @return {@code true} if the screen was registered, {@code false} otherwise. + */ + public boolean registerIncomingEffect(ResourceKey dimension, ReceivingLevelScreenFactory screen) { + return this.toEffects.putIfAbsent(dimension, screen) == null; + } + + /** + * Registers a dimension transition when traveling from a dimension. + * + * @return {@code true} if the screen was registered, {@code false} otherwise. + */ + public boolean registerOutgoingEffect(ResourceKey dimension, ReceivingLevelScreenFactory screen) { + return this.fromEffects.putIfAbsent(dimension, screen) == null; + } + + /** + * Registers a dimension transition when traveling to a dimension from a certain dimension. + * This registration method takes priority over the normal to and from dimension checks. + * + * @return {@code true} if the screen was registered, {@code false} otherwise. + */ + public boolean registerConditionalEffect(ResourceKey toDimension, ResourceKey fromDimension, ReceivingLevelScreenFactory screen) { + return this.conditionalDimensionEffects.putIfAbsent(Pair.of(toDimension, fromDimension), screen) == null; + } +} diff --git a/src/main/java/net/neoforged/neoforge/client/event/RegisterJsonAnimationTypesEvent.java b/src/main/java/net/neoforged/neoforge/client/event/RegisterJsonAnimationTypesEvent.java new file mode 100644 index 0000000000..7bbcf12031 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/event/RegisterJsonAnimationTypesEvent.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.event; + +import com.google.common.collect.ImmutableMap; +import java.util.HashMap; +import java.util.Map; +import net.minecraft.client.animation.AnimationChannel; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.bus.api.Event; +import net.neoforged.fml.event.IModBusEvent; +import net.neoforged.neoforge.client.entity.animation.AnimationTarget; +import org.jetbrains.annotations.ApiStatus; + +/** + * Allows registering custom {@link AnimationTarget}s and + * {@link AnimationChannel.Interpolation interpolation function}s for loading JSON entity animation files. + */ +public class RegisterJsonAnimationTypesEvent extends Event implements IModBusEvent { + private final ImmutableMap.Builder targets; + private final ImmutableMap.Builder interpolations; + private final Map registeredTargets = new HashMap<>(); + private final Map registeredInterpolations = new HashMap<>(); + + @ApiStatus.Internal + public RegisterJsonAnimationTypesEvent( + ImmutableMap.Builder targets, + ImmutableMap.Builder interpolations) { + this.targets = targets; + this.interpolations = interpolations; + } + + /** + * Register a custom {@link AnimationTarget} with the specified {@code key}. + */ + public void registerTarget(ResourceLocation key, AnimationTarget target) { + checkDuplicate("target", key, registeredTargets, target); + targets.put(key, target); + } + + /** + * Register a custom {@link AnimationChannel.Interpolation interpolation function} with the specified {@code key}. + */ + public void registerInterpolation(ResourceLocation key, AnimationChannel.Interpolation interpolation) { + checkDuplicate("interpolation", key, registeredInterpolations, interpolation); + interpolations.put(key, interpolation); + } + + private static void checkDuplicate(String what, ResourceLocation key, Map by, T obj) { + final var prevObj = by.putIfAbsent(key, obj); + if (prevObj != null) { + throw new IllegalStateException( + "Duplicate " + what + " registration for " + key + ". " + + obj + " tried to overwrite " + prevObj + "."); + } + } +} diff --git a/src/main/java/net/neoforged/neoforge/client/event/RegisterSpriteSourceTypesEvent.java b/src/main/java/net/neoforged/neoforge/client/event/RegisterSpriteSourceTypesEvent.java index dbcfbd9fc3..96c0bddf41 100644 --- a/src/main/java/net/neoforged/neoforge/client/event/RegisterSpriteSourceTypesEvent.java +++ b/src/main/java/net/neoforged/neoforge/client/event/RegisterSpriteSourceTypesEvent.java @@ -22,7 +22,7 @@ * This event is fired once during the construction of the {@link Minecraft} instance or * before datagen when client datagen is enabled. * - *

This event is not {@linkplain ICancellableEvent cancellable}, and does not {@linkplain HasResult have a result}.

+ *

This event is not {@linkplain ICancellableEvent cancellable}.

* *

This event is fired on the mod-specific event bus, only on the {@linkplain LogicalSide#CLIENT logical client}.

*/ @@ -39,13 +39,29 @@ public RegisterSpriteSourceTypesEvent(BiMap * * @param id The id to register the {@link SpriteSourceType} under * @param codec The codec for the {@link SpriteSourceType} to register + * + * @deprecated Use {@link #register(ResourceLocation, SpriteSourceType)} instead */ + @Deprecated(forRemoval = true, since = "1.21.1") public SpriteSourceType register(ResourceLocation id, MapCodec codec) { if (this.types.containsKey(id)) { throw new IllegalStateException("Duplicate sprite source type registration " + id); } SpriteSourceType sourceType = new SpriteSourceType(codec); - this.types.put(id, sourceType); + register(id, sourceType); return sourceType; } + + /** + * Registers the given {@link SpriteSourceType} under the given id. + * + * @param id The id to register the {@link SpriteSourceType} under + * @param sourceType The {@link SpriteSourceType} to register + */ + public void register(ResourceLocation id, SpriteSourceType sourceType) { + if (this.types.containsKey(id)) { + throw new IllegalStateException("Duplicate sprite source type registration " + id); + } + this.types.put(id, sourceType); + } } diff --git a/src/main/java/net/neoforged/neoforge/client/extensions/common/IClientItemExtensions.java b/src/main/java/net/neoforged/neoforge/client/extensions/common/IClientItemExtensions.java index 385d45a6c7..16ac6d3853 100644 --- a/src/main/java/net/neoforged/neoforge/client/extensions/common/IClientItemExtensions.java +++ b/src/main/java/net/neoforged/neoforge/client/extensions/common/IClientItemExtensions.java @@ -127,6 +127,22 @@ default Model getGenericArmorModel(LivingEntity livingEntity, ItemStack itemStac return original; } + /** + * Called when an armor piece is about to be rendered, allowing parts of the model to be animated or changed. + * + * @param itemStack The item stack being worn + * @param livingEntity The entity wearing the armor + * @param equipmentSlot The slot the armor stack is being worn in + * @param model The armor model being rendered + * @param limbSwing The swing position of the entity's walk animation + * @param limbSwingAmount The swing speed of the entity's walk animation + * @param partialTick The partial tick time + * @param ageInTicks The total age of the entity, with partialTick already applied + * @param netHeadYaw The yaw (Y rotation) of the entity's head + * @param headPitch The pitch (X rotation) of the entity's head + */ + default void setupModelAnimations(LivingEntity livingEntity, ItemStack itemStack, EquipmentSlot equipmentSlot, Model model, float limbSwing, float limbSwingAmount, float partialTick, float ageInTicks, float netHeadYaw, float headPitch) {} + /** * Called when the client starts rendering the HUD, and is wearing this item in the helmet slot. *

diff --git a/src/main/java/net/neoforged/neoforge/client/gui/ConfigurationScreen.java b/src/main/java/net/neoforged/neoforge/client/gui/ConfigurationScreen.java index ccc2f0b64f..becd2d4ca8 100644 --- a/src/main/java/net/neoforged/neoforge/client/gui/ConfigurationScreen.java +++ b/src/main/java/net/neoforged/neoforge/client/gui/ConfigurationScreen.java @@ -160,6 +160,17 @@ public boolean existsWithFallback(final String translationKey) { return true; } + /** + * If the given translation key exists, returns it formatted with the given style(s) and as prefixed with the given component. + * Otherwise returns an empty Component. + */ + public Component optional(final Component prefix, final String translationKey, final ChatFormatting... style) { + if (I18n.exists(translationKey)) { + return Component.empty().append(prefix).append(Component.translatable(translationKey).withStyle(style)); + } + return Component.empty(); + } + public void finish() { if (CLIENT.logUntranslatedConfigurationWarnings.get() && !FMLLoader.isProduction() && (!untranslatables.isEmpty() || !untranslatablesWithFallback.isEmpty())) { StringBuilder stringBuilder = new StringBuilder(); @@ -200,7 +211,8 @@ public void finish() { /** * The breadcrumb separator. Default: "%s > %s" */ - private static final String CRUMB = LANG_PREFIX + "breadcrumb"; + public static final Component CRUMB_SEPARATOR = Component.translatable(LANG_PREFIX + "breadcrumb.separator").withStyle(ChatFormatting.GOLD, ChatFormatting.BOLD); + private static final String CRUMB = LANG_PREFIX + "breadcrumb.order"; /** * The label of list elements. Will be supplied the index into the list. Default: "%s:" */ @@ -209,20 +221,26 @@ public void finish() { * How the range will be added to the tooltip when using translated tooltips. Mimics what the comment does in ModConfigSpec. */ private static final String RANGE_TOOLTIP = LANG_PREFIX + "rangetooltip"; + private static final ChatFormatting RANGE_TOOLTIP_STYLE = ChatFormatting.GRAY; /** * How the filename will be added to the tooltip. */ private static final String FILENAME_TOOLTIP = LANG_PREFIX + "filenametooltip"; + private static final ChatFormatting FILENAME_TOOLTIP_STYLE = ChatFormatting.GRAY; + /** + * A literal to create an empty line in a tooltip. + */ + private static final MutableComponent EMPTY_LINE = Component.literal("\n\n"); - public static final Component TOOLTIP_CANNOT_EDIT_THIS_WHILE_ONLINE = Component.translatable(LANG_PREFIX + "notonline"); - public static final Component TOOLTIP_CANNOT_EDIT_THIS_WHILE_OPEN_TO_LAN = Component.translatable(LANG_PREFIX + "notlan"); - public static final Component TOOLTIP_CANNOT_EDIT_NOT_LOADED = Component.translatable(LANG_PREFIX + "notloaded"); + public static final Component TOOLTIP_CANNOT_EDIT_THIS_WHILE_ONLINE = Component.translatable(LANG_PREFIX + "notonline").withStyle(ChatFormatting.RED); + public static final Component TOOLTIP_CANNOT_EDIT_THIS_WHILE_OPEN_TO_LAN = Component.translatable(LANG_PREFIX + "notlan").withStyle(ChatFormatting.RED); + public static final Component TOOLTIP_CANNOT_EDIT_NOT_LOADED = Component.translatable(LANG_PREFIX + "notloaded").withStyle(ChatFormatting.RED); public static final Component NEW_LIST_ELEMENT = Component.translatable(LANG_PREFIX + "newlistelement"); public static final Component MOVE_LIST_ELEMENT_UP = Component.translatable(LANG_PREFIX + "listelementup"); public static final Component MOVE_LIST_ELEMENT_DOWN = Component.translatable(LANG_PREFIX + "listelementdown"); public static final Component REMOVE_LIST_ELEMENT = Component.translatable(LANG_PREFIX + "listelementremove"); - public static final Component UNSUPPORTED_ELEMENT = Component.translatable(LANG_PREFIX + "unsupportedelement"); - public static final Component LONG_STRING = Component.translatable(LANG_PREFIX + "longstring"); + public static final Component UNSUPPORTED_ELEMENT = Component.translatable(LANG_PREFIX + "unsupportedelement").withStyle(ChatFormatting.RED); + public static final Component LONG_STRING = Component.translatable(LANG_PREFIX + "longstring").withStyle(ChatFormatting.RED); public static final Component GAME_RESTART_TITLE = Component.translatable(LANG_PREFIX + "restart.game.title"); public static final Component GAME_RESTART_MESSAGE = Component.translatable(LANG_PREFIX + "restart.game.text"); public static final Component GAME_RESTART_YES = Component.translatable("menu.quit"); // TitleScreen.init() et.al. @@ -231,7 +249,7 @@ public void finish() { public static final Component RETURN_TO_MENU = Component.translatable("menu.returnToMenu"); // PauseScreen.RETURN_TO_MENU public static final Component SAVING_LEVEL = Component.translatable("menu.savingLevel"); // PauseScreen.SAVING_LEVEL public static final Component RESTART_NO = Component.translatable(LANG_PREFIX + "restart.return"); - public static final Component RESTART_NO_TOOLTIP = Component.translatable(LANG_PREFIX + "restart.return.tooltip"); + public static final Component RESTART_NO_TOOLTIP = Component.translatable(LANG_PREFIX + "restart.return.tooltip").withStyle(ChatFormatting.RED, ChatFormatting.BOLD); public static final Component UNDO = Component.translatable(LANG_PREFIX + "undo"); public static final Component UNDO_TOOLTIP = Component.translatable(LANG_PREFIX + "undo.tooltip"); public static final Component RESET = Component.translatable(LANG_PREFIX + "reset"); @@ -281,19 +299,19 @@ protected void addOptions() { button -> minecraft.setScreen(sectionScreen.apply(this, type, modConfig, translatableConfig(modConfig, ".title", LANG_PREFIX + "title." + type.name().toLowerCase(Locale.ROOT))))).width(BIG_BUTTON_WIDTH).build(); MutableComponent tooltip = Component.empty(); if (!((ModConfigSpec) modConfig.getSpec()).isLoaded()) { - tooltip.append(TOOLTIP_CANNOT_EDIT_NOT_LOADED).append(Component.literal("\n\n")); + tooltip.append(TOOLTIP_CANNOT_EDIT_NOT_LOADED).append(EMPTY_LINE); btn.active = false; count = 99; // prevent autoClose } else if (type == Type.SERVER && minecraft.getCurrentServer() != null && !minecraft.isSingleplayer()) { - tooltip.append(TOOLTIP_CANNOT_EDIT_THIS_WHILE_ONLINE).append(Component.literal("\n\n")); + tooltip.append(TOOLTIP_CANNOT_EDIT_THIS_WHILE_ONLINE).append(EMPTY_LINE); btn.active = false; count = 99; // prevent autoClose } else if (type == Type.SERVER && minecraft.hasSingleplayerServer() && minecraft.getSingleplayerServer().isPublished()) { - tooltip.append(TOOLTIP_CANNOT_EDIT_THIS_WHILE_OPEN_TO_LAN).append(Component.literal("\n\n")); + tooltip.append(TOOLTIP_CANNOT_EDIT_THIS_WHILE_OPEN_TO_LAN).append(EMPTY_LINE); btn.active = false; count = 99; // prevent autoClose } - tooltip.append(Component.translatable(FILENAME_TOOLTIP, modConfig.getFileName())); + tooltip.append(Component.translatable(FILENAME_TOOLTIP, modConfig.getFileName()).withStyle(FILENAME_TOOLTIP_STYLE)); btn.setTooltip(Tooltip.create(tooltip)); list.addSmall(btn, null); count++; @@ -514,7 +532,7 @@ public ConfigurationSectionScreen(final Screen parent, final ModConfig.Type type */ public ConfigurationSectionScreen(final Context parentContext, final Screen parent, final Map valueSpecs, final String key, final Set entrySet, Component title) { - this(Context.section(parentContext, parent, entrySet, valueSpecs, key), Component.translatable(CRUMB, parent.getTitle(), title)); + this(Context.section(parentContext, parent, entrySet, valueSpecs, key), Component.translatable(CRUMB, parent.getTitle(), CRUMB_SEPARATOR, title)); } @SuppressWarnings("resource") @@ -558,10 +576,13 @@ protected Component getTooltipComponent(final String key, @Nullable Range ran final boolean hasTranslatedTooltip = translationChecker.existsWithFallback(tooltipKey); MutableComponent component = Component.empty().append(getTranslationComponent(key).withStyle(ChatFormatting.BOLD)); if (hasTranslatedTooltip || !Strings.isBlank(comment)) { - component = component.append(Component.literal("\n\n")).append(Component.translatableWithFallback(tooltipKey, comment)); + component = component.append(EMPTY_LINE).append(Component.translatableWithFallback(tooltipKey, comment)); } + // The "tooltip.warning" key is to be considered an internal API. It will be removed once Neo has a + // generic styling mechanism for translation texts. Use at your own risk. + component = component.append(translationChecker.optional(EMPTY_LINE, tooltipKey + ".warning", ChatFormatting.RED, ChatFormatting.BOLD)); if (hasTranslatedTooltip && range != null) { - component = component.append(Component.translatable(RANGE_TOOLTIP, range.toString())); + component = component.append(EMPTY_LINE).append(Component.translatable(RANGE_TOOLTIP, range.toString()).withStyle(RANGE_TOOLTIP_STYLE)); } return component; } @@ -917,7 +938,7 @@ protected Element createList(final String key, final ListValueSpec spec, fin return new Element(Component.translatable(SECTION, getTranslationComponent(key)), getTooltipComponent(key, null), Button.builder(Component.translatable(SECTION, Component.translatable(translationChecker.check(getTranslationKey(key) + ".button", SECTION_TEXT))), button -> minecraft.setScreen(sectionCache.computeIfAbsent(key, - k -> new ConfigurationListScreen<>(Context.list(context, this), key, Component.translatable(CRUMB, this.getTitle(), getTranslationComponent(key)), spec, list)).rebuild())) + k -> new ConfigurationListScreen<>(Context.list(context, this), key, Component.translatable(CRUMB, this.getTitle(), CRUMB_SEPARATOR, getTranslationComponent(key)), spec, list)).rebuild())) .tooltip(Tooltip.create(getTooltipComponent(key, null))).build(), false); } diff --git a/src/main/java/net/neoforged/neoforge/client/gui/ModListScreen.java b/src/main/java/net/neoforged/neoforge/client/gui/ModListScreen.java index e59f8f5ca5..fb67ef7d16 100644 --- a/src/main/java/net/neoforged/neoforge/client/gui/ModListScreen.java +++ b/src/main/java/net/neoforged/neoforge/client/gui/ModListScreen.java @@ -47,7 +47,6 @@ import net.neoforged.fml.i18n.MavenVersionTranslator; import net.neoforged.fml.loading.FMLPaths; import net.neoforged.fml.loading.StringUtils; -import net.neoforged.fml.loading.moddiscovery.ModFileInfo; import net.neoforged.neoforge.client.gui.widget.ModListWidget; import net.neoforged.neoforge.client.gui.widget.ScrollPanel; import net.neoforged.neoforge.common.CommonHooks; @@ -404,17 +403,18 @@ public void upload() { lines.add(FMLTranslations.parseMessage("fml.menu.mods.info.version", MavenVersionTranslator.artifactVersionToString(selectedMod.getVersion()))); lines.add(FMLTranslations.parseMessage("fml.menu.mods.info.idstate", selectedMod.getModId(), "LOADED")); // TODO: remove mod loading stages from here too - selectedMod.getConfig().getConfigElement("credits").ifPresent(credits -> lines.add(FMLTranslations.parseMessage("fml.menu.mods.info.credits", credits))); - selectedMod.getConfig().getConfigElement("authors").ifPresent(authors -> lines.add(FMLTranslations.parseMessage("fml.menu.mods.info.authors", authors))); - selectedMod.getConfig().getConfigElement("displayURL").ifPresent(displayURL -> lines.add(FMLTranslations.parseMessage("fml.menu.mods.info.displayurl", displayURL))); + // Normalizing line endings to LF because it is currently not automatically handled for us. Descriptions are already normalized. + selectedMod.getConfig().getConfigElement("credits").ifPresent(credits -> lines.add(FMLTranslations.parseMessage("fml.menu.mods.info.credits", credits).replace("\r\n", "\n"))); + selectedMod.getConfig().getConfigElement("authors").ifPresent(authors -> lines.add(FMLTranslations.parseMessage("fml.menu.mods.info.authors", authors).replace("\r\n", "\n"))); + selectedMod.getConfig().getConfigElement("displayURL").ifPresent(displayURL -> lines.add(FMLTranslations.parseMessage("fml.menu.mods.info.displayurl", displayURL).replace("\r\n", "\n"))); if (selectedMod.getOwningFile() == null || selectedMod.getOwningFile().getMods().size() == 1) lines.add(FMLTranslations.parseMessage("fml.menu.mods.info.nochildmods")); else lines.add(FMLTranslations.parseMessage("fml.menu.mods.info.childmods", selectedMod.getOwningFile().getMods().stream().map(IModInfo::getDisplayName).collect(Collectors.joining(",")))); if (vercheck.status() == VersionChecker.Status.OUTDATED || vercheck.status() == VersionChecker.Status.BETA_OUTDATED) - lines.add(FMLTranslations.parseMessage("fml.menu.mods.info.updateavailable", vercheck.url() == null ? "" : vercheck.url())); - lines.add(FMLTranslations.parseMessage("fml.menu.mods.info.license", ((ModFileInfo) selectedMod.getOwningFile()).getLicense())); + lines.add(FMLTranslations.parseMessage("fml.menu.mods.info.updateavailable", vercheck.url() == null ? "" : vercheck.url()).replace("\r\n", "\n")); + lines.add(FMLTranslations.parseMessage("fml.menu.mods.info.license", selectedMod.getOwningFile().getLicense()).replace("\r\n", "\n")); lines.add(null); lines.add(FMLTranslations.parseMessageWithFallback("fml.menu.mods.info.description." + selectedMod.getModId(), selectedMod::getDescription)); diff --git a/src/main/java/net/neoforged/neoforge/client/model/data/ModelData.java b/src/main/java/net/neoforged/neoforge/client/model/data/ModelData.java index e980e296f0..ba793cc7ea 100644 --- a/src/main/java/net/neoforged/neoforge/client/model/data/ModelData.java +++ b/src/main/java/net/neoforged/neoforge/client/model/data/ModelData.java @@ -70,6 +70,18 @@ public static Builder builder() { return new Builder(null); } + /** + * Helper to create a {@link ModelData} instance for a single property-value pair, without the verbosity + * and runtime overhead of creating a builder object. + */ + public static ModelData of(ModelProperty property, T value) { + Preconditions.checkState(property.test(value), "The provided value is invalid for this property."); + // Must use one of the two map types from the builder to avoid megamorphic calls to Map.get() later + Reference2ReferenceArrayMap, Object> map = new Reference2ReferenceArrayMap<>(1); + map.put(property, value); + return new ModelData(map); + } + public static final class Builder { /** * Hash maps are slower than array maps for *extremely* small maps (empty maps or singletons are the most diff --git a/src/main/java/net/neoforged/neoforge/client/model/generators/BlockStateProvider.java b/src/main/java/net/neoforged/neoforge/client/model/generators/BlockStateProvider.java index dc0c4782f3..72745b01ba 100644 --- a/src/main/java/net/neoforged/neoforge/client/model/generators/BlockStateProvider.java +++ b/src/main/java/net/neoforged/neoforge/client/model/generators/BlockStateProvider.java @@ -29,6 +29,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.ButtonBlock; +import net.minecraft.world.level.block.CeilingHangingSignBlock; import net.minecraft.world.level.block.CrossCollisionBlock; import net.minecraft.world.level.block.DoorBlock; import net.minecraft.world.level.block.FenceBlock; @@ -42,6 +43,7 @@ import net.minecraft.world.level.block.StandingSignBlock; import net.minecraft.world.level.block.TrapDoorBlock; import net.minecraft.world.level.block.WallBlock; +import net.minecraft.world.level.block.WallHangingSignBlock; import net.minecraft.world.level.block.WallSignBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.AttachFace; @@ -481,6 +483,16 @@ public void signBlock(StandingSignBlock signBlock, WallSignBlock wallSignBlock, simpleBlock(wallSignBlock, sign); } + public void hangingSignBlock(CeilingHangingSignBlock hangingSignBlock, WallHangingSignBlock wallHangingSignBlock, ResourceLocation texture) { + ModelFile hangingSign = models().sign(name(hangingSignBlock), texture); + hangingSignBlock(hangingSignBlock, wallHangingSignBlock, hangingSign); + } + + public void hangingSignBlock(CeilingHangingSignBlock hangingSignBlock, WallHangingSignBlock wallHangingSignBlock, ModelFile hangingSign) { + simpleBlock(hangingSignBlock, hangingSign); + simpleBlock(wallHangingSignBlock, hangingSign); + } + public void fourWayBlock(CrossCollisionBlock block, ModelFile post, ModelFile side) { MultiPartBlockStateBuilder builder = getMultipartBuilder(block) .part().modelFile(post).addModel().end(); diff --git a/src/main/java/net/neoforged/neoforge/client/model/generators/ItemModelProvider.java b/src/main/java/net/neoforged/neoforge/client/model/generators/ItemModelProvider.java index f4af7fdeaf..046ef31566 100644 --- a/src/main/java/net/neoforged/neoforge/client/model/generators/ItemModelProvider.java +++ b/src/main/java/net/neoforged/neoforge/client/model/generators/ItemModelProvider.java @@ -10,6 +10,7 @@ import net.minecraft.data.PackOutput; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; import net.neoforged.neoforge.common.data.ExistingFileHelper; /** @@ -31,6 +32,33 @@ public ItemModelBuilder basicItem(ResourceLocation item) { .texture("layer0", ResourceLocation.fromNamespaceAndPath(item.getNamespace(), "item/" + item.getPath())); } + public ItemModelBuilder handheldItem(Item item) { + return handheldItem(Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(item))); + } + + public ItemModelBuilder handheldItem(ResourceLocation item) { + return getBuilder(item.toString()) + .parent(new ModelFile.UncheckedModelFile("item/handheld")) + .texture("layer0", ResourceLocation.fromNamespaceAndPath(item.getNamespace(), "item/" + item.getPath())); + } + + public ItemModelBuilder spawnEggItem(Item item) { + return spawnEggItem(Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(item))); + } + + public ItemModelBuilder spawnEggItem(ResourceLocation item) { + return getBuilder(item.toString()) + .parent(new ModelFile.UncheckedModelFile("item/template_spawn_egg")); + } + + public ItemModelBuilder simpleBlockItem(Block block) { + return simpleBlockItem(Objects.requireNonNull(BuiltInRegistries.BLOCK.getKey(block))); + } + + public ItemModelBuilder simpleBlockItem(ResourceLocation block) { + return withExistingParent(block.toString(), ResourceLocation.fromNamespaceAndPath(block.getNamespace(), "block/" + block.getPath())); + } + @Override public String getName() { return "Item Models: " + modid; diff --git a/src/main/java/net/neoforged/neoforge/client/textures/NamespacedDirectoryLister.java b/src/main/java/net/neoforged/neoforge/client/textures/NamespacedDirectoryLister.java new file mode 100644 index 0000000000..4e8f334dbc --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/client/textures/NamespacedDirectoryLister.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.client.textures; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.client.renderer.texture.atlas.SpriteSource; +import net.minecraft.client.renderer.texture.atlas.SpriteSourceType; +import net.minecraft.client.renderer.texture.atlas.sources.DirectoryLister; +import net.minecraft.resources.FileToIdConverter; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion; + +/** + * Namespace-aware version of {@link DirectoryLister}. This version should be preferred when several textures from + * high-traffic directories should be stitched to an atlas without adding assets from other mods that should not be + * stitched to this atlas + */ +public record NamespacedDirectoryLister(String namespace, String sourcePath, String idPrefix) implements SpriteSource { + + private static final MapCodec CODEC = RecordCodecBuilder.mapCodec(inst -> inst.group( + Codec.STRING.fieldOf("namespace").forGetter(lister -> lister.namespace), + Codec.STRING.fieldOf("source").forGetter(lister -> lister.sourcePath), + Codec.STRING.fieldOf("prefix").forGetter(lister -> lister.idPrefix)).apply(inst, NamespacedDirectoryLister::new)); + public static final ResourceLocation ID = ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "namespaced_directory"); + public static final SpriteSourceType TYPE = new SpriteSourceType(CODEC); + @Override + public void run(ResourceManager resourceManager, Output output) { + FileToIdConverter converter = new FileToIdConverter("textures/" + this.sourcePath, ".png"); + converter.listMatchingResourcesFromNamespace(resourceManager, this.namespace).forEach((path, resource) -> { + ResourceLocation id = converter.fileToId(path).withPrefix(this.idPrefix); + output.add(id, resource); + }); + } + + @Override + public SpriteSourceType type() { + return TYPE; + } +} diff --git a/src/main/java/net/neoforged/neoforge/common/BooleanAttribute.java b/src/main/java/net/neoforged/neoforge/common/BooleanAttribute.java index 453cb3ba31..faf7277198 100644 --- a/src/main/java/net/neoforged/neoforge/common/BooleanAttribute.java +++ b/src/main/java/net/neoforged/neoforge/common/BooleanAttribute.java @@ -5,8 +5,14 @@ package net.neoforged.neoforge.common; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.AttributeModifier.Operation; +import net.minecraft.world.item.TooltipFlag; +import org.jetbrains.annotations.Nullable; /** * A boolean attribute only has two states, on or off, represented by a value of 0 (false) or 1 (true). @@ -34,4 +40,27 @@ public double sanitizeValue(double value) { } return value > 0 ? 1 : 0; } + + @Override + public MutableComponent toValueComponent(@Nullable Operation op, double value, TooltipFlag flag) { + if (op == null) { + return Component.translatable("neoforge.value.boolean." + (value > 0 ? "enabled" : "disabled")); + } else if (op == Operation.ADD_VALUE && value > 0) { + return Component.translatable("neoforge.value.boolean.enable"); + } else if (op == Operation.ADD_MULTIPLIED_TOTAL && (int) value == -1) { + return Component.translatable("neoforge.value.boolean.disable"); + } else { + return Component.translatable("neoforge.value.boolean.invalid"); + } + } + + @Override + public MutableComponent toComponent(AttributeModifier modif, TooltipFlag flag) { + double value = modif.amount(); + + ChatFormatting color = this.getStyle(value > 0); + MutableComponent comp = Component.translatable("neoforge.modifier.bool", this.toValueComponent(modif.operation(), value, flag), Component.translatable(this.getDescriptionId())).withStyle(color); + + return comp.append(this.getDebugInfo(modif, flag)); + } } diff --git a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java index e434bbb54f..5c7e2f992f 100644 --- a/src/main/java/net/neoforged/neoforge/common/CommonHooks.java +++ b/src/main/java/net/neoforged/neoforge/common/CommonHooks.java @@ -205,6 +205,7 @@ import net.neoforged.neoforge.event.entity.player.PlayerEnchantItemEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; +import net.neoforged.neoforge.event.entity.player.SweepAttackEvent; import net.neoforged.neoforge.event.level.BlockDropsEvent; import net.neoforged.neoforge.event.level.BlockEvent; import net.neoforged.neoforge.event.level.NoteBlockEvent; @@ -923,6 +924,17 @@ public static CriticalHitEvent fireCriticalHit(Player player, Entity target, boo return NeoForge.EVENT_BUS.post(new CriticalHitEvent(player, target, damageModifier, vanillaCritical)); } + /** + * Fires the {@link SweepAttackEvent} and returns the resulting event. + * + * @param player The attacking player. + * @param target The attack target. + * @param isVanillaSweep If the attack would have been a sweep attack by vanilla's rules in {@link Player#attack(Entity)}. + */ + public static SweepAttackEvent fireSweepAttack(Player player, Entity target, boolean isVanillaSweep) { + return NeoForge.EVENT_BUS.post(new SweepAttackEvent(player, target, isVanillaSweep)); + } + /** * Hook to fire {@link ItemAttributeModifierEvent}. Modders should use {@link ItemStack#forEachModifier(EquipmentSlot, BiConsumer)} instead. */ diff --git a/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java b/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java index 3c0ca35bb5..46b0696bf4 100644 --- a/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java +++ b/src/main/java/net/neoforged/neoforge/common/NeoForgeMod.java @@ -47,6 +47,7 @@ import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.MobCategory; import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.Attribute.Sentiment; import net.minecraft.world.entity.ai.attributes.RangedAttribute; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.Items; @@ -194,8 +195,8 @@ public class NeoForgeMod { private static final DeferredHolder, SingletonArgumentInfo> MODID_COMMAND_ARGUMENT_TYPE = COMMAND_ARGUMENT_TYPES.register("modid", () -> ArgumentTypeInfos.registerByClass(ModIdArgument.class, SingletonArgumentInfo.contextFree(ModIdArgument::modIdArgument))); - public static final Holder SWIM_SPEED = ATTRIBUTES.register("swim_speed", () -> new RangedAttribute("neoforge.swim_speed", 1.0D, 0.0D, 1024.0D).setSyncable(true)); - public static final Holder NAMETAG_DISTANCE = ATTRIBUTES.register("nametag_distance", () -> new RangedAttribute("neoforge.name_tag_distance", 64.0D, 0.0D, 64.0).setSyncable(true)); + public static final Holder SWIM_SPEED = ATTRIBUTES.register("swim_speed", () -> new PercentageAttribute("neoforge.swim_speed", 1.0D, 0.0D, 1024.0D).setSyncable(true)); + public static final Holder NAMETAG_DISTANCE = ATTRIBUTES.register("nametag_distance", () -> new RangedAttribute("neoforge.name_tag_distance", 64.0D, 0.0D, 64.0).setSyncable(true).setSentiment(Sentiment.NEUTRAL)); /** * This attribute controls if the player may use creative flight when not in creative mode. @@ -471,6 +472,8 @@ public void setItemMovement(ItemEntity entity) { private static boolean enableProperFilenameValidation = false; private static boolean enableMilkFluid = false; + private static boolean enableMergedAttributeTooltips = false; + public static final DeferredHolder BUCKET_EMPTY_MILK = DeferredHolder.create(Registries.SOUND_EVENT, ResourceLocation.withDefaultNamespace("item.bucket.empty_milk")); public static final DeferredHolder BUCKET_FILL_MILK = DeferredHolder.create(Registries.SOUND_EVENT, ResourceLocation.withDefaultNamespace("item.bucket.fill_milk")); public static final DeferredHolder MILK_TYPE = DeferredHolder.create(NeoForgeRegistries.Keys.FLUID_TYPES, ResourceLocation.withDefaultNamespace("milk")); @@ -493,6 +496,13 @@ public static void enableMilkFluid() { enableMilkFluid = true; } + /** + * Run this during mod construction to enable merged attribute tooltip functionality. + */ + public static void enableMergedAttributeTooltips() { + enableMergedAttributeTooltips = true; + } + /** * Run this method during mod constructor to enable {@link net.minecraft.FileUtil#RESERVED_WINDOWS_FILENAMES_NEOFORGE} regex being used for filepath validation. * Fixes MC-268617 at cost of vanilla incompat edge cases with files generated with this activated and them migrated to vanilla instance - See PR #767 @@ -505,6 +515,10 @@ public static boolean getProperFilenameValidation() { return enableProperFilenameValidation; } + public static boolean shouldMergeAttributeTooltips() { + return enableMergedAttributeTooltips; + } + public NeoForgeMod(IEventBus modEventBus, Dist dist, ModContainer container) { LOGGER.info(NEOFORGEMOD, "NeoForge mod loading, version {}, for MC {}", NeoForgeVersion.getVersion(), DetectedVersion.BUILT_IN.getName()); ForgeSnapshotsMod.logStartupWarning(); diff --git a/src/main/java/net/neoforged/neoforge/common/PercentageAttribute.java b/src/main/java/net/neoforged/neoforge/common/PercentageAttribute.java new file mode 100644 index 0000000000..75a845fea8 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/common/PercentageAttribute.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.common; + +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.entity.ai.attributes.AttributeModifier.Operation; +import net.minecraft.world.entity.ai.attributes.RangedAttribute; +import net.minecraft.world.item.TooltipFlag; + +/** + * A Percentage Attribute is one which always displays modifiers as percentages, including for {@link Operation#ADD_VALUE}. + *

+ * This is used for attributes that would not make sense being displayed as flat additions (ex: +0.05 Swim Speed). + */ +public class PercentageAttribute extends RangedAttribute { + protected final double scaleFactor; + + /** + * Creates a new PercentageAttribute with the given description, value information, and scale factor. + *

+ * If your attribute's "real" value correlates 1 == 100%, you would use a scale factor of 100 to convert to 1 to 100%. + * + * @param pDescriptionId The description id used for generating the attribute's lang key. + * @param pDefaultValue The default value of the attribute + * @param pMin The minimum value + * @param pMax The maximum value + * @param scaleFactor The scale factor, used to convert the literal value to a percentage value. + */ + public PercentageAttribute(String pDescriptionId, double pDefaultValue, double pMin, double pMax, double scaleFactor) { + super(pDescriptionId, pDefaultValue, pMin, pMax); + this.scaleFactor = scaleFactor; + } + + /** + * Creates a new PercentageAttribute with the default scale factor of 100. + * + * @see #PercentageAttribute(String, double, double, double, double) + */ + public PercentageAttribute(String pDescriptionId, double pDefaultValue, double pMin, double pMax) { + this(pDescriptionId, pDefaultValue, pMin, pMax, 100); + } + + @Override + public MutableComponent toValueComponent(Operation op, double value, TooltipFlag flag) { + return Component.translatable("neoforge.value.percent", FORMAT.format(value * this.scaleFactor)); + } +} diff --git a/src/main/java/net/neoforged/neoforge/common/TagConventionLogWarning.java b/src/main/java/net/neoforged/neoforge/common/TagConventionLogWarning.java index f874d45787..854a826426 100644 --- a/src/main/java/net/neoforged/neoforge/common/TagConventionLogWarning.java +++ b/src/main/java/net/neoforged/neoforge/common/TagConventionLogWarning.java @@ -411,12 +411,17 @@ public enum LogWarningMode { createForgeMapEntry(Registries.ITEM, "candy", Tags.Items.FOODS_CANDY), createForgeMapEntry(Registries.ITEM, "candies", Tags.Items.FOODS_CANDY), createMapEntry(Registries.ITEM, "c", "foods/candies", Tags.Items.FOODS_CANDY), + createForgeMapEntry(Registries.ITEM, "pie", Tags.Items.FOODS_PIE), + createForgeMapEntry(Registries.ITEM, "pies", Tags.Items.FOODS_PIE), + createMapEntry(Registries.ITEM, "c", "foods/pies", Tags.Items.FOODS_PIE), createForgeMapEntry(Registries.FLUID, "water", Tags.Fluids.WATER), createForgeMapEntry(Registries.FLUID, "lava", Tags.Fluids.LAVA), createForgeMapEntry(Registries.FLUID, "milk", Tags.Fluids.MILK), createForgeMapEntry(Registries.FLUID, "gaseous", Tags.Fluids.GASEOUS), createForgeMapEntry(Registries.FLUID, "honey", Tags.Fluids.HONEY), + createForgeMapEntry(Registries.FLUID, "xp", Tags.Fluids.EXPERIENCE), + createForgeMapEntry(Registries.FLUID, "experience", Tags.Fluids.EXPERIENCE), createForgeMapEntry(Registries.FLUID, "potion", Tags.Fluids.POTION), createForgeMapEntry(Registries.FLUID, "plantoil", "plant_oil"), diff --git a/src/main/java/net/neoforged/neoforge/common/Tags.java b/src/main/java/net/neoforged/neoforge/common/Tags.java index de73509989..8a57785dc8 100644 --- a/src/main/java/net/neoforged/neoforge/common/Tags.java +++ b/src/main/java/net/neoforged/neoforge/common/Tags.java @@ -115,6 +115,12 @@ public static class Blocks { public static final TagKey HIDDEN_FROM_RECIPE_VIEWERS = tag("hidden_from_recipe_viewers"); public static final TagKey NETHERRACKS = tag("netherracks"); public static final TagKey OBSIDIANS = tag("obsidians"); + /** + * For common obsidian that has no special quirks or behaviors. Ideal for recipe use. + * Crying Obsidian, for example, is a light block and harder to obtain. So it gets its own tag instead of being under normal tag. + */ + public static final TagKey OBSIDIANS_NORMAL = tag("obsidians/normal"); + public static final TagKey OBSIDIANS_CRYING = tag("obsidians/crying"); /** * Blocks which are often replaced by deepslate ores, i.e. the ores in the tag {@link #ORES_IN_GROUND_DEEPSLATE}, during world generation */ @@ -218,6 +224,8 @@ public static class Blocks { public static final TagKey STORAGE_BLOCKS_REDSTONE = tag("storage_blocks/redstone"); public static final TagKey STORAGE_BLOCKS_SLIME = tag("storage_blocks/slime"); public static final TagKey STORAGE_BLOCKS_WHEAT = tag("storage_blocks/wheat"); + public static final TagKey STRIPPED_LOGS = tag("stripped_logs"); + public static final TagKey STRIPPED_WOODS = tag("stripped_woods"); public static final TagKey VILLAGER_JOB_SITES = tag("villager_job_sites"); /** @@ -423,6 +431,10 @@ public static class Items { * Sweets and candies like lollipops or chocolate belong in this tag. */ public static final TagKey FOODS_CANDY = tag("foods/candy"); + /** + * Pies and other pie-like foods belong in this tag. + */ + public static final TagKey FOODS_PIE = tag("foods/pie"); /** * Any gold-based foods would go in this tag. Such as Golden Apples or Glistering Melon Slice. */ @@ -436,6 +448,11 @@ public static class Items { * Examples are Rotten Flesh's Hunger or Pufferfish's Nausea, or Poisonous Potato's Poison. */ public static final TagKey FOODS_FOOD_POISONING = tag("foods/food_poisoning"); + /** + * All foods edible by animals excluding poisonous foods. + * (Does not include {@link ItemTags#PARROT_POISONOUS_FOOD}) + */ + public static final TagKey ANIMAL_FOODS = tag("animal_foods"); public static final TagKey GEMS = tag("gems"); public static final TagKey GEMS_DIAMOND = tag("gems/diamond"); public static final TagKey GEMS_EMERALD = tag("gems/emerald"); @@ -480,6 +497,12 @@ public static class Items { public static final TagKey NUGGETS_GOLD = tag("nuggets/gold"); public static final TagKey NUGGETS_IRON = tag("nuggets/iron"); public static final TagKey OBSIDIANS = tag("obsidians"); + /** + * For common obsidian that has no special quirks or behaviors. Ideal for recipe use. + * Crying Obsidian, for example, is a light block and harder to obtain. So it gets its own tag instead of being under normal tag. + */ + public static final TagKey OBSIDIANS_NORMAL = tag("obsidians/normal"); + public static final TagKey OBSIDIANS_CRYING = tag("obsidians/crying"); /** * Blocks which are often replaced by deepslate ores, i.e. the ores in the tag {@link #ORES_IN_GROUND_DEEPSLATE}, during world generation */ @@ -606,6 +629,8 @@ public static class Items { public static final TagKey STORAGE_BLOCKS_SLIME = tag("storage_blocks/slime"); public static final TagKey STORAGE_BLOCKS_WHEAT = tag("storage_blocks/wheat"); public static final TagKey STRINGS = tag("strings"); + public static final TagKey STRIPPED_LOGS = tag("stripped_logs"); + public static final TagKey STRIPPED_WOODS = tag("stripped_woods"); public static final TagKey VILLAGER_JOB_SITES = tag("villager_job_sites"); // Tools and Armors @@ -747,12 +772,12 @@ private static TagKey neoforgeTag(String name) { */ public static class Fluids { /** - * Holds all fluids related to water. + * Holds all fluids related to water.

* This tag is done to help out multi-loader mods/datapacks where the vanilla water tag has attached behaviors outside Neo. */ public static final TagKey WATER = tag("water"); /** - * Holds all fluids related to lava. + * Holds all fluids related to lava.

* This tag is done to help out multi-loader mods/datapacks where the vanilla lava tag has attached behaviors outside Neo. */ public static final TagKey LAVA = tag("lava"); @@ -765,36 +790,48 @@ public static class Fluids { */ public static final TagKey GASEOUS = tag("gaseous"); /** - * Holds all fluids related to honey.

+ * Holds all fluids related to honey. + *

* (Standard unit for honey bottle is 250mb per bottle) */ public static final TagKey HONEY = tag("honey"); /** - * Holds all fluids related to potions. The effects of the potion fluid should be read from NBT. + * Holds all fluids related to experience. + *

+ * (Standard unit for experience is 20mb per 1 experience. However, extraction from Bottle o' Enchanting should yield 250mb while smashing yields less) + */ + public static final TagKey EXPERIENCE = tag("experience"); + /** + * Holds all fluids related to potions. The effects of the potion fluid should be read from DataComponents. * The effects and color of the potion fluid should be read from {@link net.minecraft.core.component.DataComponents#POTION_CONTENTS} - * component that people should be attaching to the fluidstack of this fluid.

+ * component that people should be attaching to the fluidstack of this fluid. + *

* (Standard unit for potions is 250mb per bottle) */ public static final TagKey POTION = tag("potion"); /** * Holds all fluids related to Suspicious Stew. * The effects of the suspicious stew fluid should be read from {@link net.minecraft.core.component.DataComponents#SUSPICIOUS_STEW_EFFECTS} - * component that people should be attaching to the fluidstack of this fluid.

+ * component that people should be attaching to the fluidstack of this fluid. + *

* (Standard unit for suspicious stew is 250mb per bowl) */ public static final TagKey SUSPICIOUS_STEW = tag("suspicious_stew"); /** - * Holds all fluids related to Mushroom Stew.

+ * Holds all fluids related to Mushroom Stew. + *

* (Standard unit for mushroom stew is 250mb per bowl) */ public static final TagKey MUSHROOM_STEW = tag("mushroom_stew"); /** - * Holds all fluids related to Rabbit Stew.

+ * Holds all fluids related to Rabbit Stew. + *

* (Standard unit for rabbit stew is 250mb per bowl) */ public static final TagKey RABBIT_STEW = tag("rabbit_stew"); /** - * Holds all fluids related to Beetroot Soup.

+ * Holds all fluids related to Beetroot Soup. + *

* (Standard unit for beetroot soup is 250mb per bowl) */ public static final TagKey BEETROOT_SOUP = tag("beetroot_soup"); diff --git a/src/main/java/net/neoforged/neoforge/common/VillagerTradingManager.java b/src/main/java/net/neoforged/neoforge/common/VillagerTradingManager.java index 92a0a16b4e..b36bbdb53b 100644 --- a/src/main/java/net/neoforged/neoforge/common/VillagerTradingManager.java +++ b/src/main/java/net/neoforged/neoforge/common/VillagerTradingManager.java @@ -12,6 +12,7 @@ import java.util.List; import java.util.Map; import net.minecraft.core.NonNullList; +import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.entity.npc.VillagerProfession; import net.minecraft.world.entity.npc.VillagerTrades; @@ -35,20 +36,20 @@ public class VillagerTradingManager { static void loadTrades(TagsUpdatedEvent e) { if (e.getUpdateCause() == TagsUpdatedEvent.UpdateCause.SERVER_DATA_LOAD) { - postWandererEvent(); - postVillagerEvents(); + postWandererEvent(e.getRegistryAccess()); + postVillagerEvents(e.getRegistryAccess()); } } /** * Posts the WandererTradesEvent. */ - private static void postWandererEvent() { + private static void postWandererEvent(RegistryAccess registryAccess) { List generic = NonNullList.create(); List rare = NonNullList.create(); Arrays.stream(WANDERER_TRADES.get(1)).forEach(generic::add); Arrays.stream(WANDERER_TRADES.get(2)).forEach(rare::add); - NeoForge.EVENT_BUS.post(new WandererTradesEvent(generic, rare)); + NeoForge.EVENT_BUS.post(new WandererTradesEvent(generic, rare, registryAccess)); VillagerTrades.WANDERING_TRADER_TRADES.put(1, generic.toArray(new ItemListing[0])); VillagerTrades.WANDERING_TRADER_TRADES.put(2, rare.toArray(new ItemListing[0])); } @@ -56,7 +57,7 @@ private static void postWandererEvent() { /** * Posts a VillagerTradesEvent for each registered profession. */ - private static void postVillagerEvents() { + private static void postVillagerEvents(RegistryAccess registryAccess) { for (VillagerProfession prof : BuiltInRegistries.VILLAGER_PROFESSION) { Int2ObjectMap trades = VANILLA_TRADES.getOrDefault(prof, new Int2ObjectOpenHashMap<>()); Int2ObjectMap> mutableTrades = new Int2ObjectOpenHashMap<>(); @@ -66,7 +67,7 @@ private static void postVillagerEvents() { trades.int2ObjectEntrySet().forEach(e -> { Arrays.stream(e.getValue()).forEach(mutableTrades.get(e.getIntKey())::add); }); - NeoForge.EVENT_BUS.post(new VillagerTradesEvent(mutableTrades, prof)); + NeoForge.EVENT_BUS.post(new VillagerTradesEvent(mutableTrades, prof, registryAccess)); Int2ObjectMap newTrades = new Int2ObjectOpenHashMap<>(); mutableTrades.int2ObjectEntrySet().forEach(e -> newTrades.put(e.getIntKey(), e.getValue().toArray(new ItemListing[0]))); VillagerTrades.TRADES.put(prof, newTrades); diff --git a/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeBlockTagsProvider.java b/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeBlockTagsProvider.java index 71da6a581c..ca4fde00ba 100644 --- a/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeBlockTagsProvider.java +++ b/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeBlockTagsProvider.java @@ -80,7 +80,9 @@ public void addTags(HolderLookup.Provider p_256380_) { tag(Tags.Blocks.SKULLS).add(Blocks.SKELETON_SKULL, Blocks.SKELETON_WALL_SKULL, Blocks.WITHER_SKELETON_SKULL, Blocks.WITHER_SKELETON_WALL_SKULL, Blocks.PLAYER_HEAD, Blocks.PLAYER_WALL_HEAD, Blocks.ZOMBIE_HEAD, Blocks.ZOMBIE_WALL_HEAD, Blocks.CREEPER_HEAD, Blocks.CREEPER_WALL_HEAD, Blocks.PIGLIN_HEAD, Blocks.PIGLIN_WALL_HEAD, Blocks.DRAGON_HEAD, Blocks.DRAGON_WALL_HEAD); tag(Tags.Blocks.HIDDEN_FROM_RECIPE_VIEWERS); tag(Tags.Blocks.NETHERRACKS).add(Blocks.NETHERRACK); - tag(Tags.Blocks.OBSIDIANS).add(Blocks.OBSIDIAN); + tag(Tags.Blocks.OBSIDIANS_NORMAL).add(Blocks.OBSIDIAN); + tag(Tags.Blocks.OBSIDIANS_CRYING).add(Blocks.CRYING_OBSIDIAN); + tag(Tags.Blocks.OBSIDIANS).addTags(Tags.Blocks.OBSIDIANS_NORMAL, Tags.Blocks.OBSIDIANS_CRYING); tag(Tags.Blocks.ORE_BEARING_GROUND_DEEPSLATE).add(Blocks.DEEPSLATE); tag(Tags.Blocks.ORE_BEARING_GROUND_NETHERRACK).add(Blocks.NETHERRACK); tag(Tags.Blocks.ORE_BEARING_GROUND_STONE).add(Blocks.STONE); @@ -142,6 +144,14 @@ public void addTags(HolderLookup.Provider p_256380_) { tag(Tags.Blocks.STORAGE_BLOCKS_REDSTONE).add(Blocks.REDSTONE_BLOCK); tag(Tags.Blocks.STORAGE_BLOCKS_SLIME).add(Blocks.SLIME_BLOCK); tag(Tags.Blocks.STORAGE_BLOCKS_WHEAT).add(Blocks.HAY_BLOCK); + tag(Tags.Blocks.STRIPPED_LOGS).add( + Blocks.STRIPPED_ACACIA_LOG, Blocks.STRIPPED_BAMBOO_BLOCK, Blocks.STRIPPED_BIRCH_LOG, + Blocks.STRIPPED_CHERRY_LOG, Blocks.STRIPPED_DARK_OAK_LOG, Blocks.STRIPPED_JUNGLE_LOG, + Blocks.STRIPPED_MANGROVE_LOG, Blocks.STRIPPED_OAK_LOG, Blocks.STRIPPED_SPRUCE_LOG); + tag(Tags.Blocks.STRIPPED_WOODS).add( + Blocks.STRIPPED_ACACIA_WOOD, Blocks.STRIPPED_BIRCH_WOOD, Blocks.STRIPPED_CHERRY_WOOD, + Blocks.STRIPPED_DARK_OAK_WOOD, Blocks.STRIPPED_JUNGLE_WOOD, Blocks.STRIPPED_MANGROVE_WOOD, + Blocks.STRIPPED_OAK_WOOD, Blocks.STRIPPED_SPRUCE_WOOD); tag(Tags.Blocks.VILLAGER_JOB_SITES).add( Blocks.BARREL, Blocks.BLAST_FURNACE, Blocks.BREWING_STAND, Blocks.CARTOGRAPHY_TABLE, Blocks.CAULDRON, Blocks.WATER_CAULDRON, Blocks.LAVA_CAULDRON, Blocks.POWDER_SNOW_CAULDRON, diff --git a/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeFluidTagsProvider.java b/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeFluidTagsProvider.java index 880ebada1d..5d96ec98ba 100644 --- a/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeFluidTagsProvider.java +++ b/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeFluidTagsProvider.java @@ -29,6 +29,7 @@ public void addTags(HolderLookup.Provider lookupProvider) { tag(Fluids.MILK).addOptional(NeoForgeMod.MILK.getId()).addOptional(NeoForgeMod.FLOWING_MILK.getId()); tag(Fluids.GASEOUS); tag(Fluids.HONEY); + tag(Fluids.EXPERIENCE); tag(Fluids.POTION); tag(Fluids.SUSPICIOUS_STEW); tag(Fluids.MUSHROOM_STEW); diff --git a/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeItemTagsProvider.java b/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeItemTagsProvider.java index 786b481659..20e88b6501 100644 --- a/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeItemTagsProvider.java +++ b/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeItemTagsProvider.java @@ -121,6 +121,7 @@ public void addTags(HolderLookup.Provider lookupProvider) { tag(Tags.Items.FOODS_COOKED_FISH).add(Items.COOKED_COD, Items.COOKED_SALMON); tag(Tags.Items.FOODS_SOUP).add(Items.BEETROOT_SOUP, Items.MUSHROOM_STEW, Items.RABBIT_STEW, Items.SUSPICIOUS_STEW); tag(Tags.Items.FOODS_CANDY); + tag(Tags.Items.FOODS_PIE).add(Items.PUMPKIN_PIE); tag(Tags.Items.FOODS_GOLDEN).add(Items.GOLDEN_APPLE).add(Items.ENCHANTED_GOLDEN_APPLE).add(Items.GOLDEN_CARROT); tag(Tags.Items.FOODS_EDIBLE_WHEN_PLACED).add(Items.CAKE); tag(Tags.Items.FOODS_FOOD_POISONING).add(Items.POISONOUS_POTATO, Items.PUFFERFISH, Items.SPIDER_EYE, Items.CHICKEN, Items.ROTTEN_FLESH); @@ -128,8 +129,14 @@ public void addTags(HolderLookup.Provider lookupProvider) { .add(Items.BAKED_POTATO, Items.PUMPKIN_PIE, Items.HONEY_BOTTLE, Items.OMINOUS_BOTTLE, Items.DRIED_KELP) .addTags(Tags.Items.FOODS_FRUIT, Tags.Items.FOODS_VEGETABLE, Tags.Items.FOODS_BERRY, Tags.Items.FOODS_BREAD, Tags.Items.FOODS_COOKIE, Tags.Items.FOODS_RAW_MEAT, Tags.Items.FOODS_RAW_FISH, Tags.Items.FOODS_COOKED_MEAT, Tags.Items.FOODS_COOKED_FISH, - Tags.Items.FOODS_SOUP, Tags.Items.FOODS_CANDY, Tags.Items.FOODS_GOLDEN, + Tags.Items.FOODS_SOUP, Tags.Items.FOODS_CANDY, Tags.Items.FOODS_PIE, Tags.Items.FOODS_GOLDEN, Tags.Items.FOODS_EDIBLE_WHEN_PLACED, Tags.Items.FOODS_FOOD_POISONING); + tag(Tags.Items.ANIMAL_FOODS) + .addTags(ItemTags.ARMADILLO_FOOD, ItemTags.AXOLOTL_FOOD, ItemTags.BEE_FOOD, ItemTags.CAMEL_FOOD, + ItemTags.CAT_FOOD, ItemTags.CHICKEN_FOOD, ItemTags.COW_FOOD, ItemTags.FOX_FOOD, ItemTags.FROG_FOOD, + ItemTags.GOAT_FOOD, ItemTags.HOGLIN_FOOD, ItemTags.HORSE_FOOD, ItemTags.LLAMA_FOOD, ItemTags.OCELOT_FOOD, + ItemTags.PANDA_FOOD, ItemTags.PARROT_FOOD, ItemTags.PIG_FOOD, ItemTags.PIGLIN_FOOD, ItemTags.RABBIT_FOOD, + ItemTags.SHEEP_FOOD, ItemTags.SNIFFER_FOOD, ItemTags.STRIDER_FOOD, ItemTags.TURTLE_FOOD, ItemTags.WOLF_FOOD); tag(Tags.Items.GEMS).addTags(Tags.Items.GEMS_AMETHYST, Tags.Items.GEMS_DIAMOND, Tags.Items.GEMS_EMERALD, Tags.Items.GEMS_LAPIS, Tags.Items.GEMS_PRISMARINE, Tags.Items.GEMS_QUARTZ); tag(Tags.Items.GEMS_AMETHYST).add(Items.AMETHYST_SHARD); tag(Tags.Items.GEMS_DIAMOND).add(Items.DIAMOND); @@ -165,6 +172,8 @@ public void addTags(HolderLookup.Provider lookupProvider) { tag(Tags.Items.NUGGETS_IRON).add(Items.IRON_NUGGET); tag(Tags.Items.NUGGETS_GOLD).add(Items.GOLD_NUGGET); copy(Tags.Blocks.OBSIDIANS, Tags.Items.OBSIDIANS); + copy(Tags.Blocks.OBSIDIANS_NORMAL, Tags.Items.OBSIDIANS_NORMAL); + copy(Tags.Blocks.OBSIDIANS_CRYING, Tags.Items.OBSIDIANS_CRYING); copy(Tags.Blocks.ORE_BEARING_GROUND_DEEPSLATE, Tags.Items.ORE_BEARING_GROUND_DEEPSLATE); copy(Tags.Blocks.ORE_BEARING_GROUND_NETHERRACK, Tags.Items.ORE_BEARING_GROUND_NETHERRACK); copy(Tags.Blocks.ORE_BEARING_GROUND_STONE, Tags.Items.ORE_BEARING_GROUND_STONE); @@ -241,6 +250,8 @@ public void addTags(HolderLookup.Provider lookupProvider) { copy(Tags.Blocks.STORAGE_BLOCKS_SLIME, Tags.Items.STORAGE_BLOCKS_SLIME); copy(Tags.Blocks.STORAGE_BLOCKS_WHEAT, Tags.Items.STORAGE_BLOCKS_WHEAT); tag(Tags.Items.STRINGS).add(Items.STRING); + copy(Tags.Blocks.STRIPPED_LOGS, Tags.Items.STRIPPED_LOGS); + copy(Tags.Blocks.STRIPPED_WOODS, Tags.Items.STRIPPED_WOODS); tag(Tags.Items.VILLAGER_JOB_SITES).add( Items.BARREL, Items.BLAST_FURNACE, Items.BREWING_STAND, Items.CARTOGRAPHY_TABLE, Items.CAULDRON, Items.COMPOSTER, Items.FLETCHING_TABLE, Items.GRINDSTONE, @@ -267,7 +278,7 @@ public void addTags(HolderLookup.Provider lookupProvider) { .addTags(Tags.Items.TOOLS_BOW, Tags.Items.TOOLS_BRUSH, Tags.Items.TOOLS_CROSSBOW, Tags.Items.TOOLS_FISHING_ROD, Tags.Items.TOOLS_IGNITER, Tags.Items.TOOLS_SHEAR, Tags.Items.TOOLS_SHIELD, Tags.Items.TOOLS_SPEAR, Tags.Items.TOOLS_MACE, Tags.Items.MINING_TOOL_TOOLS, Tags.Items.MELEE_WEAPON_TOOLS, Tags.Items.RANGED_WEAPON_TOOLS); tag(Tags.Items.ARMORS).addTags(ItemTags.HEAD_ARMOR, ItemTags.CHEST_ARMOR, ItemTags.LEG_ARMOR, ItemTags.FOOT_ARMOR); - tag(Tags.Items.ENCHANTABLES).addTags(ItemTags.ARMOR_ENCHANTABLE, ItemTags.EQUIPPABLE_ENCHANTABLE, ItemTags.WEAPON_ENCHANTABLE, ItemTags.SWORD_ENCHANTABLE, ItemTags.MINING_ENCHANTABLE, ItemTags.MINING_LOOT_ENCHANTABLE, ItemTags.FISHING_ENCHANTABLE, ItemTags.TRIDENT_ENCHANTABLE, ItemTags.BOW_ENCHANTABLE, ItemTags.CROSSBOW_ENCHANTABLE, ItemTags.FIRE_ASPECT_ENCHANTABLE, ItemTags.DURABILITY_ENCHANTABLE).addOptionalTag(ItemTags.MACE_ENCHANTABLE); + tag(Tags.Items.ENCHANTABLES).addTags(ItemTags.ARMOR_ENCHANTABLE, ItemTags.EQUIPPABLE_ENCHANTABLE, ItemTags.WEAPON_ENCHANTABLE, ItemTags.SWORD_ENCHANTABLE, ItemTags.MINING_ENCHANTABLE, ItemTags.MINING_LOOT_ENCHANTABLE, ItemTags.FISHING_ENCHANTABLE, ItemTags.TRIDENT_ENCHANTABLE, ItemTags.BOW_ENCHANTABLE, ItemTags.CROSSBOW_ENCHANTABLE, ItemTags.MACE_ENCHANTABLE, ItemTags.FIRE_ASPECT_ENCHANTABLE, ItemTags.DURABILITY_ENCHANTABLE, ItemTags.VANISHING_ENCHANTABLE); // Backwards compat with pre-1.21 tags. Done after so optional tag is last for better readability. // TODO: Remove backwards compat tag entries in 1.22 diff --git a/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeLanguageProvider.java b/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeLanguageProvider.java index 75d947020c..f764016f5c 100644 --- a/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeLanguageProvider.java +++ b/src/main/java/net/neoforged/neoforge/common/data/internal/NeoForgeLanguageProvider.java @@ -69,6 +69,8 @@ protected void addTranslations() { add(Tags.Blocks.NEEDS_GOLD_TOOL, "Needs Gold Tools"); add(Tags.Blocks.NEEDS_NETHERITE_TOOL, "Needs Netherite Tools"); add(Tags.Blocks.OBSIDIANS, "Obsidians"); + add(Tags.Blocks.OBSIDIANS_NORMAL, "Normal Obsidians"); + add(Tags.Blocks.OBSIDIANS_CRYING, "Crying Obsidians"); add(Tags.Blocks.ORE_BEARING_GROUND_DEEPSLATE, "Deepslate Ore Bearing Ground"); add(Tags.Blocks.ORE_BEARING_GROUND_NETHERRACK, "Netherrack Ore Bearing Ground"); add(Tags.Blocks.ORE_BEARING_GROUND_STONE, "Stone Ore Bearing Ground"); @@ -123,6 +125,8 @@ protected void addTranslations() { add(Tags.Blocks.STORAGE_BLOCKS_REDSTONE, "Redstone Storage Blocks"); add(Tags.Blocks.STORAGE_BLOCKS_SLIME, "Slime Storage Blocks"); add(Tags.Blocks.STORAGE_BLOCKS_WHEAT, "Wheat Storage Blocks"); + add(Tags.Blocks.STRIPPED_LOGS, "Stripped Logs"); + add(Tags.Blocks.STRIPPED_WOODS, "Stripped Woods"); add(Tags.Blocks.VILLAGER_JOB_SITES, "Villager Job Sites"); add(Tags.Blocks.VILLAGER_FARMLANDS, "Villager Farmlands"); @@ -204,6 +208,7 @@ protected void addTranslations() { add(Tags.Items.FOODS_BERRY, "Berries"); add(Tags.Items.FOODS_BREAD, "Breads"); add(Tags.Items.FOODS_CANDY, "Candies"); + add(Tags.Items.FOODS_PIE, "Pies"); add(Tags.Items.FOODS_COOKED_FISH, "Cooked Fishes"); add(Tags.Items.FOODS_COOKED_MEAT, "Cooked Meats"); add(Tags.Items.FOODS_COOKIE, "Cookies"); @@ -215,6 +220,7 @@ protected void addTranslations() { add(Tags.Items.FOODS_RAW_MEAT, "Raw Meats"); add(Tags.Items.FOODS_SOUP, "Soups"); add(Tags.Items.FOODS_VEGETABLE, "Vegetables"); + add(Tags.Items.ANIMAL_FOODS, "Animal Foods"); add(Tags.Items.GEMS, "Gems"); add(Tags.Items.GEMS_AMETHYST, "Amethyst Gems"); add(Tags.Items.GEMS_DIAMOND, "Diamond Gems"); @@ -246,6 +252,8 @@ protected void addTranslations() { add(Tags.Items.NUGGETS_IRON, "Iron Nuggets"); add(Tags.Items.NUGGETS_GOLD, "Gold Nuggets"); add(Tags.Items.OBSIDIANS, "Obsidians"); + add(Tags.Items.OBSIDIANS_NORMAL, "Normal Obsidians"); + add(Tags.Items.OBSIDIANS_CRYING, "Crying Obsidians"); add(Tags.Items.ORE_BEARING_GROUND_DEEPSLATE, "Deepslate Ore Bearing Ground"); add(Tags.Items.ORE_BEARING_GROUND_NETHERRACK, "Netherrack Ore Bearing Ground"); add(Tags.Items.ORE_BEARING_GROUND_STONE, "Stone Ore Bearing Ground"); @@ -316,6 +324,8 @@ protected void addTranslations() { add(Tags.Items.STORAGE_BLOCKS_SLIME, "Slime Storage Blocks"); add(Tags.Items.STORAGE_BLOCKS_WHEAT, "Wheat Storage Blocks"); add(Tags.Items.STRINGS, "Strings"); + add(Tags.Items.STRIPPED_LOGS, "Stripped Log Blocks"); + add(Tags.Items.STRIPPED_WOODS, "Stripped Wood Blocks"); add(Tags.Items.VILLAGER_JOB_SITES, "Villager Job Sites"); add(Tags.Items.TOOLS_SHEAR, "Shears"); add(Tags.Items.TOOLS_SHIELD, "Shields"); @@ -339,6 +349,7 @@ protected void addTranslations() { add(Tags.Fluids.MILK, "Milk"); add(Tags.Fluids.GASEOUS, "Gaseous"); add(Tags.Fluids.HONEY, "Honey"); + add(Tags.Fluids.EXPERIENCE, "Experience"); add(Tags.Fluids.POTION, "Potion"); add(Tags.Fluids.SUSPICIOUS_STEW, "Suspicious Stew"); add(Tags.Fluids.MUSHROOM_STEW, "Mushroom Stew"); diff --git a/src/main/java/net/neoforged/neoforge/common/extensions/IAttributeExtension.java b/src/main/java/net/neoforged/neoforge/common/extensions/IAttributeExtension.java new file mode 100644 index 0000000000..6a5c51564d --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/common/extensions/IAttributeExtension.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.common.extensions; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; +import net.minecraft.ChatFormatting; +import net.minecraft.Util; +import net.minecraft.core.Holder; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.TextColor; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.Attribute.Sentiment; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.AttributeModifier.Operation; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.item.TooltipFlag; +import net.neoforged.neoforge.common.NeoForgeMod; +import net.neoforged.neoforge.common.util.AttributeUtil; +import org.jetbrains.annotations.Nullable; + +public interface IAttributeExtension { + public static final DecimalFormat FORMAT = Util.make(new DecimalFormat("#.##"), fmt -> fmt.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT)));; + + /** + * Converts the value of an attribute modifier to the value that will be displayed. + *

+ * For multiplicative modifiers, this method is responsible for converting the value to percentage form. + * + * @param op The operation of the modifier. Null if we are just displaying the raw value and not a modifier. + * @param value The value to convert. Either the current attribute value (if null operation) or the attribute modifier's amount. + * @param flag The tooltip flag. + * @return The component form of the formatted value. + */ + default MutableComponent toValueComponent(@Nullable Operation op, double value, TooltipFlag flag) { + if (isNullOrAddition(op)) { + return Component.translatable("neoforge.value.flat", FORMAT.format(value)); + } + + return Component.translatable("neoforge.value.percent", FORMAT.format(value * 100)); + } + + /** + * Converts an attribute modifier into its tooltip representation. + *

+ * This method does not handle formatting of "base" modifiers, such as Attack Damage or Attack Speed. + *

+ * The returned component may append additional debug information based on the tooltip flag. + * + * @param modif The attribute modifier being converted to a component. + * @param flag The tooltip flag. + * @return The component representation of the passed attribute modifier, with debug info appended if enabled. + */ + default MutableComponent toComponent(AttributeModifier modif, TooltipFlag flag) { + Attribute attr = self(); + double value = modif.amount(); + String key = value > 0 ? "neoforge.modifier.plus" : "neoforge.modifier.take"; + ChatFormatting color = attr.getStyle(value > 0); + + Component attrDesc = Component.translatable(attr.getDescriptionId()); + Component valueComp = this.toValueComponent(modif.operation(), value, flag); + MutableComponent comp = Component.translatable(key, valueComp, attrDesc).withStyle(color); + + return comp.append(this.getDebugInfo(modif, flag)); + } + + /** + * Computes the additional debug information for a given attribute modifier, if the flag {@linkplain TooltipFlag#isAdvanced() is advanced}. + * + * @param modif The attribute modifier being converted to a component. + * @param flag The tooltip flag. + * @return The debug component, or {@link CommonComponents#EMPTY} if disabled. + * @apiNote This information is automatically appended to {@link #toComponent(AttributeModifier, TooltipFlag)}. + */ + default Component getDebugInfo(AttributeModifier modif, TooltipFlag flag) { + Component debugInfo = CommonComponents.EMPTY; + + if (flag.isAdvanced()) { + // Advanced Tooltips show the underlying operation and the "true" value. We offset MULTIPLY_TOTAL by 1 due to how the operation is calculated. + double advValue = (modif.operation() == Operation.ADD_MULTIPLIED_TOTAL ? 1 : 0) + modif.amount(); + String valueStr = FORMAT.format(advValue); + String txt = switch (modif.operation()) { + case ADD_VALUE -> String.format(Locale.ROOT, advValue > 0 ? "[+%s]" : "[%s]", valueStr); + case ADD_MULTIPLIED_BASE -> String.format(Locale.ROOT, advValue > 0 ? "[+%sx]" : "[%sx]", valueStr); + case ADD_MULTIPLIED_TOTAL -> String.format(Locale.ROOT, "[x%s]", valueStr); + }; + debugInfo = Component.literal(" ").append(Component.literal(txt).withStyle(ChatFormatting.GRAY)); + } + return debugInfo; + } + + /** + * Gets the specific ID that represents a "base" (green) modifier for this attribute. + * + * @return The ID of the "base" modifier, or null, if no such modifier may exist. + */ + @Nullable + default ResourceLocation getBaseId() { + if (this == Attributes.ATTACK_DAMAGE.value()) return AttributeUtil.BASE_ATTACK_DAMAGE_ID; + else if (this == Attributes.ATTACK_SPEED.value()) return AttributeUtil.BASE_ATTACK_SPEED_ID; + else if (this == Attributes.ENTITY_INTERACTION_RANGE.value()) return AttributeUtil.BASE_ENTITY_REACH_ID; + return null; + } + + /** + * Converts a "base" attribute modifier (as dictated by {@link #getBaseId()}) into a text component. + *

+ * Similar to {@link #toComponent}, this method is responsible for adding debug information when the tooltip flag {@linkplain TooltipFlag#isAdvanced() is advanced}. + * + * @param value The value to be shown (after having been added to the entity's base value) + * @param entityBase The entity's base value for this attribute from {@link LivingEntity#getAttributeBaseValue(Holder)}. + * @param merged If we are displaying a merged base component (which will have a non-merged base component as a child). + * @param flag The tooltip flag. + * @return The component representation of the passed attribute modifier. + */ + default MutableComponent toBaseComponent(double value, double entityBase, boolean merged, TooltipFlag flag) { + Attribute attr = self(); + MutableComponent comp = Component.translatable("attribute.modifier.equals.0", FORMAT.format(value), Component.translatable(attr.getDescriptionId())); + + // Emit both the value of the modifier, and the entity's base value as debug information, since both are flattened into the modifier. + // Skip showing debug information here when displaying a merged modifier, since it will be shown if the user holds shift to display the un-merged modifier. + if (flag.isAdvanced() && !merged) { + Component debugInfo = Component.literal(" ").append(Component.translatable("neoforge.attribute.debug.base", FORMAT.format(entityBase), FORMAT.format(value - entityBase)).withStyle(ChatFormatting.GRAY)); + comp.append(debugInfo); + } + + return comp; + } + + /** + * Returns the color used by merged attribute modifiers. Only used when {@link NeoForgeMod#enableMergedAttributeTooltips()} is active. + *

+ * Similarly to {@link Attribute#getStyle(boolean)}, this method should return a color based on the attribute's {@link Sentiment}. + * The returned color should be distinguishable from the color used by {@link Attribute#getStyle(boolean)}. + * + * @param positive If the attribute modifier value is positive or not. + */ + TextColor getMergedStyle(boolean isPositive); + + public static boolean isNullOrAddition(@Nullable Operation op) { + return op == null || op == Operation.ADD_VALUE; + } + + private Attribute self() { + return (Attribute) this; + } +} diff --git a/src/main/java/net/neoforged/neoforge/common/extensions/IItemExtension.java b/src/main/java/net/neoforged/neoforge/common/extensions/IItemExtension.java index 1de3e6358d..0ae0cb4bc3 100644 --- a/src/main/java/net/neoforged/neoforge/common/extensions/IItemExtension.java +++ b/src/main/java/net/neoforged/neoforge/common/extensions/IItemExtension.java @@ -21,6 +21,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; @@ -336,12 +337,25 @@ default ResourceLocation getArmorTexture(ItemStack stack, Entity entity, Equipme * Called when a entity tries to play the 'swing' animation. * * @param entity The entity swinging the item. - * @return True to cancel any further processing by EntityLiving + * @return True to cancel any further processing by {@link LivingEntity} + * @deprecated To be replaced with hand sensitive version in 21.2 + * @see #onEntitySwing(ItemStack, LivingEntity, InteractionHand) */ + @Deprecated(forRemoval = true, since = "21.1") default boolean onEntitySwing(ItemStack stack, LivingEntity entity) { return false; } + /** + * Called when a entity tries to play the 'swing' animation. + * + * @param entity The entity swinging the item. + * @return True to cancel any further processing by {@link LivingEntity} + */ + default boolean onEntitySwing(ItemStack stack, LivingEntity entity, InteractionHand hand) { + return onEntitySwing(stack, entity); + } + /** * Return the itemDamage represented by this ItemStack. Defaults to the Damage * entry in the stack NBT, but can be overridden here for other sources. diff --git a/src/main/java/net/neoforged/neoforge/common/extensions/IItemStackExtension.java b/src/main/java/net/neoforged/neoforge/common/extensions/IItemStackExtension.java index 8c9d46d8e8..f8c61d0bc9 100644 --- a/src/main/java/net/neoforged/neoforge/common/extensions/IItemStackExtension.java +++ b/src/main/java/net/neoforged/neoforge/common/extensions/IItemStackExtension.java @@ -12,6 +12,7 @@ import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.stats.Stats; +import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; @@ -217,12 +218,26 @@ default boolean canDisableShield(ItemStack shield, LivingEntity entity, LivingEn * Called when a entity tries to play the 'swing' animation. * * @param entity The entity swinging the item. - * @return True to cancel any further processing by EntityLiving + * @return True to cancel any further processing by {@link LivingEntity} + * @deprecated To be replaced with hand sensitive version in 21.2 + * @see #onEntitySwing(LivingEntity, InteractionHand) */ + @Deprecated(forRemoval = true, since = "21.1") default boolean onEntitySwing(LivingEntity entity) { return self().getItem().onEntitySwing(self(), entity); } + /** + * Called when a entity tries to play the 'swing' animation. + * + * @param entity The entity swinging the item. + * @param hand The hand the item is held in. + * @return True to cancel any further processing by {@link LivingEntity} + */ + default boolean onEntitySwing(LivingEntity entity, InteractionHand hand) { + return self().getItem().onEntitySwing(self(), entity, hand); + } + /** * Called when an entity stops using an item item for any reason. * diff --git a/src/main/java/net/neoforged/neoforge/common/extensions/ITagAppenderExtension.java b/src/main/java/net/neoforged/neoforge/common/extensions/ITagAppenderExtension.java index fdd4a00438..57d19aaa04 100644 --- a/src/main/java/net/neoforged/neoforge/common/extensions/ITagAppenderExtension.java +++ b/src/main/java/net/neoforged/neoforge/common/extensions/ITagAppenderExtension.java @@ -54,7 +54,7 @@ default TagsProvider.TagAppender replace(boolean value) { */ default TagsProvider.TagAppender remove(final ResourceLocation location) { TagsProvider.TagAppender builder = self(); - builder.getInternalBuilder().removeElement(location, builder.getModID()); + builder.getInternalBuilder().removeElement(location); return builder; } @@ -106,7 +106,7 @@ default TagsProvider.TagAppender remove(final ResourceKey firstResourceKey */ default TagsProvider.TagAppender remove(TagKey tag) { TagsProvider.TagAppender builder = self(); - builder.getInternalBuilder().removeTag(tag.location(), builder.getModID()); + builder.getInternalBuilder().removeTag(tag.location()); return builder; } diff --git a/src/main/java/net/neoforged/neoforge/common/extensions/ITagBuilderExtension.java b/src/main/java/net/neoforged/neoforge/common/extensions/ITagBuilderExtension.java index 18d488597e..c63342f984 100644 --- a/src/main/java/net/neoforged/neoforge/common/extensions/ITagBuilderExtension.java +++ b/src/main/java/net/neoforged/neoforge/common/extensions/ITagBuilderExtension.java @@ -10,6 +10,7 @@ import net.minecraft.tags.TagEntry; public interface ITagBuilderExtension { + // TODO: In 1.21.2, rename this to self() and mark as private default TagBuilder getRawBuilder() { return (TagBuilder) this; } @@ -20,7 +21,9 @@ default TagBuilder getRawBuilder() { * @param tagEntry The tag entry to add to the remove list * @param source The source of the caller for logging purposes (generally a modid) * @return The builder for chaining purposes + * @deprecated Use {@link TagBuilder#remove(TagEntry)} instead. */ + @Deprecated(forRemoval = true, since = "1.21.1") default TagBuilder remove(final TagEntry tagEntry, final String source) { return this.getRawBuilder().remove(tagEntry); } @@ -31,19 +34,43 @@ default TagBuilder remove(final TagEntry tagEntry, final String source) { * @param elementID The ID of the element to add to the remove list * @param source The source of the caller for logging purposes (generally a modid) * @return The builder for chaining purposes + * @deprecated Use {@link #removeElement(ResourceLocation)} instead. */ + @Deprecated(forRemoval = true, since = "1.21.1") default TagBuilder removeElement(final ResourceLocation elementID, final String source) { return this.remove(TagEntry.element(elementID), source); } + /** + * Adds a single-element entry to the remove list. + * + * @param elementID The ID of the element to add to the remove list + * @return The builder for chaining purposes + */ + default TagBuilder removeElement(final ResourceLocation elementID) { + return this.getRawBuilder().remove(TagEntry.element(elementID)); + } + /** * Adds a tag to the remove list. * * @param tagID The ID of the tag to add to the remove list * @param source The source of the caller for logging purposes (generally a modid) * @return The builder for chaining purposes + * @deprecated Use {@link #removeElement(ResourceLocation)} instead. */ + @Deprecated(forRemoval = true, since = "1.21.1") default TagBuilder removeTag(final ResourceLocation tagID, final String source) { return this.remove(TagEntry.tag(tagID), source); } + + /** + * Adds a tag to the remove list. + * + * @param tagID The ID of the tag to add to the remove list + * @return The builder for chaining purposes + */ + default TagBuilder removeTag(final ResourceLocation tagID) { + return this.getRawBuilder().remove(TagEntry.tag(tagID)); + } } diff --git a/src/main/java/net/neoforged/neoforge/common/util/AttributeTooltipContext.java b/src/main/java/net/neoforged/neoforge/common/util/AttributeTooltipContext.java new file mode 100644 index 0000000000..e21ee1ff52 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/common/util/AttributeTooltipContext.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.common.util; + +import net.minecraft.core.HolderLookup.Provider; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.Item.TooltipContext; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.saveddata.maps.MapId; +import net.minecraft.world.level.saveddata.maps.MapItemSavedData; +import org.jetbrains.annotations.Nullable; + +/** + * Extended {@link TooltipContext} used when generating attribute tooltips. + */ +public interface AttributeTooltipContext extends Item.TooltipContext { + /** + * {@return the player for whom tooltips are being generated for, if known} + */ + @Nullable + Player player(); + + /** + * {@return the current tooltip flag} + */ + TooltipFlag flag(); + + public static AttributeTooltipContext of(@Nullable Player player, Item.TooltipContext itemCtx, TooltipFlag flag) { + return new AttributeTooltipContext() { + @Override + public Provider registries() { + return itemCtx.registries(); + } + + @Override + public float tickRate() { + return itemCtx.tickRate(); + } + + @Override + public MapItemSavedData mapData(MapId id) { + return itemCtx.mapData(id); + } + + @Override + public Level level() { + return itemCtx.level(); + } + + @Nullable + @Override + public Player player() { + return player; + } + + @Override + public TooltipFlag flag() { + return flag; + } + }; + } +} diff --git a/src/main/java/net/neoforged/neoforge/common/util/AttributeUtil.java b/src/main/java/net/neoforged/neoforge/common/util/AttributeUtil.java new file mode 100644 index 0000000000..160626a669 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/common/util/AttributeUtil.java @@ -0,0 +1,356 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.common.util; + +import com.google.common.collect.Multimap; +import com.google.common.collect.TreeMultimap; +import com.mojang.datafixers.util.Pair; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.EnumMap; +import java.util.IdentityHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Consumer; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.core.Holder; +import net.minecraft.core.component.DataComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.TextColor; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.entity.EquipmentSlotGroup; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.AttributeModifier.Operation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.alchemy.PotionContents; +import net.minecraft.world.item.component.ItemAttributeModifiers; +import net.neoforged.fml.loading.FMLEnvironment; +import net.neoforged.neoforge.client.event.AddAttributeTooltipsEvent; +import net.neoforged.neoforge.client.event.GatherSkippedAttributeTooltipsEvent; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.common.NeoForgeMod; +import net.neoforged.neoforge.common.extensions.IAttributeExtension; +import net.neoforged.neoforge.event.ItemAttributeModifierEvent; +import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * Utility code to support {@link IAttributeExtension}. + */ +public class AttributeUtil { + /** + * ID of the base modifier for Attack Damage + */ + public static final ResourceLocation BASE_ATTACK_DAMAGE_ID = Item.BASE_ATTACK_DAMAGE_ID; + + /** + * ID of the base modifier for Attack Speed + */ + public static final ResourceLocation BASE_ATTACK_SPEED_ID = Item.BASE_ATTACK_SPEED_ID; + + /** + * ID of the base modifier for Attack Range + */ + public static final ResourceLocation BASE_ENTITY_REACH_ID = ResourceLocation.withDefaultNamespace("base_entity_reach"); + + /** + * ID used for attribute modifiers used to hold merged values when {@link NeoForgeMod#enableMergedAttributeTooltips()} is active. + *

+ * Should not be used by any real attribute modifiers for gameplay purposes. + */ + public static final ResourceLocation FAKE_MERGED_ID = ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "fake_merged_modifier"); + + /** + * Comparator for {@link AttributeModifier}. First compares by operation, then amount, then the ID. + */ + public static final Comparator ATTRIBUTE_MODIFIER_COMPARATOR = Comparator.comparing(AttributeModifier::operation) + .thenComparingDouble(a -> -Math.abs(a.amount())) // Sort most impactful modifiers first + .thenComparing(AttributeModifier::id); + + private static final Logger LOGGER = LogManager.getLogger(); + + /** + * Checks if attribute modifier tooltips should show, and if they should, adds tooltips for all attribute modifiers present on an item stack to the stack's tooltip lines. + *

+ * After the tooltip lines have been added, fires the {@link AddAttributeTooltipsEvent} to allow mods to add additional attribute-related lines. + * + * @param tooltip A consumer to add the tooltip lines to. + * @param ctx The tooltip context. + */ + public static void addAttributeTooltips(ItemStack stack, Consumer tooltip, AttributeTooltipContext ctx) { + ItemAttributeModifiers modifiers = stack.getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.EMPTY); + if (modifiers.showInTooltip()) { + applyModifierTooltips(stack, tooltip, ctx); + } + NeoForge.EVENT_BUS.post(new AddAttributeTooltipsEvent(stack, tooltip, ctx)); + } + + /** + * Applies the attribute modifier tooltips for all attribute modifiers present on the item stack. + *

+ * Before application, this method posts the {@link GatherSkippedAttributeTooltipsEvent} to determine which tooltips should be skipped. + *

+ * This method is also responsible for adding the modifier group category labels. + * + * @param tooltip A consumer to add the tooltip lines to. + * @param ctx The tooltip context. + */ + public static void applyModifierTooltips(ItemStack stack, Consumer tooltip, AttributeTooltipContext ctx) { + var event = NeoForge.EVENT_BUS.post(new GatherSkippedAttributeTooltipsEvent(stack, ctx)); + if (event.isSkippingAll()) { + return; + } + + for (EquipmentSlotGroup group : EquipmentSlotGroup.values()) { + if (event.isSkipped(group)) { + continue; + } + + Multimap, AttributeModifier> modifiers = getSortedModifiers(stack, group); + + // Remove any skipped modifiers before doing any logic + modifiers.values().removeIf(m -> event.isSkipped(m.id())); + + if (modifiers.isEmpty()) { + continue; + } + + // Add an empty line, then the name of the group, then the modifiers. + tooltip.accept(Component.empty()); + tooltip.accept(Component.translatable("item.modifiers." + group.getSerializedName()).withStyle(ChatFormatting.GRAY)); + + applyTextFor(stack, tooltip, modifiers, ctx); + } + } + + /** + * Applies the text for the provided attribute modifiers to the tooltip for a given item stack. + *

+ * This method will attempt to merge multiple modifiers for a single attribute into a single modifier if {@linkplain NeoForgeMod#enableMergedAttributeTooltips()} was called. + * + * @param stack The item stack that owns the modifiers. + * @param tooltip The consumer to append tooltip components to. + * @param modifierMap A mutable map of modifiers to convert into tooltip lines. + * @param ctx The tooltip context. + */ + public static void applyTextFor(ItemStack stack, Consumer tooltip, Multimap, AttributeModifier> modifierMap, AttributeTooltipContext ctx) { + // Don't add anything if there is nothing in the group + if (modifierMap.isEmpty()) { + return; + } + + // Collect all the base modifiers + Map, BaseModifier> baseModifs = new IdentityHashMap<>(); + + var it = modifierMap.entries().iterator(); + while (it.hasNext()) { + Entry, AttributeModifier> entry = it.next(); + Holder attr = entry.getKey(); + AttributeModifier modif = entry.getValue(); + if (modif.id().equals(attr.value().getBaseId())) { + baseModifs.put(attr, new BaseModifier(modif, new ArrayList<>())); + // Remove base modifiers from the main map after collection so we don't need to check for them later. + it.remove(); + } + } + + // Collect children of all base modifiers for merging logic + for (Map.Entry, AttributeModifier> entry : modifierMap.entries()) { + BaseModifier base = baseModifs.get(entry.getKey()); + if (base != null) { + base.children.add(entry.getValue()); + } + } + + // Add tooltip lines for base modifiers + for (Map.Entry, BaseModifier> entry : baseModifs.entrySet()) { + Holder attr = entry.getKey(); + BaseModifier baseModif = entry.getValue(); + double entityBase = ctx.player() == null ? 0 : ctx.player().getAttributeBaseValue(attr); + double base = baseModif.base.amount() + entityBase; + final double rawBase = base; + double amt = base; + + // Compute the base value including merged modifiers if merging is enabled + if (NeoForgeMod.shouldMergeAttributeTooltips()) { + for (AttributeModifier modif : baseModif.children) { + switch (modif.operation()) { + case ADD_VALUE: + base = amt = amt + modif.amount(); + break; + case ADD_MULTIPLIED_BASE: + amt += modif.amount() * base; + break; + case ADD_MULTIPLIED_TOTAL: + amt *= 1 + modif.amount(); + break; + } + } + } + + boolean isMerged = NeoForgeMod.shouldMergeAttributeTooltips() && !baseModif.children.isEmpty(); + MutableComponent text = attr.value().toBaseComponent(amt, entityBase, isMerged, ctx.flag()); + tooltip.accept(Component.literal(" ").append(text).withStyle(isMerged ? ChatFormatting.GOLD : ChatFormatting.DARK_GREEN)); + if (ctx.flag().hasShiftDown() && isMerged) { + // Display the raw base value, and then all children modifiers. + text = attr.value().toBaseComponent(rawBase, entityBase, false, ctx.flag()); + tooltip.accept(listHeader().append(text.withStyle(ChatFormatting.DARK_GREEN))); + for (AttributeModifier modifier : baseModif.children) { + tooltip.accept(listHeader().append(attr.value().toComponent(modifier, ctx.flag()))); + } + } + } + + for (Holder attr : modifierMap.keySet()) { + // Skip attributes who have already been processed during the base modifier stage + if (NeoForgeMod.shouldMergeAttributeTooltips() && baseModifs.containsKey(attr)) { + continue; + } + + Collection modifs = modifierMap.get(attr); + // Initiate merged-tooltip logic if we have more than one modifier for a given attribute. + if (NeoForgeMod.shouldMergeAttributeTooltips() && modifs.size() > 1) { + Map mergeData = new EnumMap<>(Operation.class); + + for (AttributeModifier modifier : modifs) { + if (modifier.amount() == 0) { + continue; + } + + MergedModifierData data = mergeData.computeIfAbsent(modifier.operation(), op -> new MergedModifierData()); + if (data.sum != 0) { + // If the sum for this operation is non-zero, we've already consumed one modifier. Consuming a second means we've merged. + data.isMerged = true; + } + data.sum += modifier.amount(); + data.children.add(modifier); + } + + for (Operation op : Operation.values()) { + MergedModifierData data = mergeData.get(op); + + // If the merged value comes out to 0, just ignore the whole stack + if (data == null || data.sum == 0) { + continue; + } + + // Handle merged modifier stacks by creating a "fake" merged modifier with the underlying value. + if (data.isMerged) { + TextColor color = attr.value().getMergedStyle(data.sum > 0); + var fakeModif = new AttributeModifier(FAKE_MERGED_ID, data.sum, op); + MutableComponent comp = attr.value().toComponent(fakeModif, ctx.flag()); + tooltip.accept(comp.withStyle(comp.getStyle().withColor(color))); + if (ctx.flag().hasShiftDown()) { + data.children.forEach(modif -> tooltip.accept(listHeader().append(attr.value().toComponent(modif, ctx.flag())))); + } + } else { + var fakeModif = new AttributeModifier(FAKE_MERGED_ID, data.sum, op); + tooltip.accept(attr.value().toComponent(fakeModif, ctx.flag())); + } + } + } else { + for (AttributeModifier m : modifs) { + if (m.amount() != 0) { + tooltip.accept(attr.value().toComponent(m, ctx.flag())); + } + } + } + } + } + + /** + * Adds tooltip lines for the attribute modifiers contained in a {@link PotionContents}. + * + * @param list The list of attribute modifiers generated by calling {@link MobEffect#createModifiers} for each mob effect instance on the potion. + * @param tooltips The tooltip consumer to add lines to. + */ + public static void addPotionTooltip(List, AttributeModifier>> list, Consumer tooltips) { + for (Pair, AttributeModifier> pair : list) { + tooltips.accept(pair.getFirst().value().toComponent(pair.getSecond(), getTooltipFlag())); + } + } + + /** + * Creates a sorted {@link TreeMultimap} used to ensure a stable iteration order of item attribute modifiers. + */ + public static Multimap, AttributeModifier> sortedMap() { + return TreeMultimap.create(Comparator.comparing(Holder::getKey), ATTRIBUTE_MODIFIER_COMPARATOR); + } + + /** + * Returns a sorted, mutable {@link Multimap} containing all the attribute modifiers on an item stack for the given group. + *

+ * This includes attribute modifiers from components (or default modifiers, if not present), enchantments, and the {@link ItemAttributeModifierEvent}. + * + * @param stack The stack to query modifiers for. + * @param slot The slot group to query modifiers for. + */ + public static Multimap, AttributeModifier> getSortedModifiers(ItemStack stack, EquipmentSlotGroup slot) { + Multimap, AttributeModifier> map = sortedMap(); + stack.forEachModifier(slot, (attr, modif) -> { + if (attr != null && modif != null) { + map.put(attr, modif); + } else { + LOGGER.debug("Detected broken attribute modifier entry on item {}. Attr={}, Modif={}", stack, attr, modif); + } + }); + return map; + } + + /** + * Creates a mutable component starting with the char used to represent a drop-down list. + */ + private static MutableComponent listHeader() { + return Component.literal(" \u2507 ").withStyle(ChatFormatting.GRAY); + } + + /** + * Gets the current global tooltip flag. Used by {@link AttributeUtil#addPotionTooltip} since one isn't available locally. + * + * @return If called on the client, the current tooltip flag, otherwise {@link TooltipFlag#NORMAL} + */ + private static TooltipFlag getTooltipFlag() { + if (FMLEnvironment.dist.isClient()) { + return ClientAccess.getTooltipFlag(); + } + return TooltipFlag.NORMAL; + } + + /** + * Stores a single base modifier (determined by {@link IAttributeExtension#getBaseId()}) and any other children non-base modifiers for the same attribute. + *

+ * Used during attribute merging logic within {@link AttributeUtil#applyTextFor}. + */ + private static record BaseModifier(AttributeModifier base, List children) {} + + /** + * State-tracking object used to merge attribute modifier tooltips in {@link AttributeUtil#applyTextFor}. + */ + private static class MergedModifierData { + double sum = 0; + boolean isMerged = false; + private List children = new LinkedList<>(); + } + + /** + * Client bouncer class to avoid class loading issues. Access to this class still needs a dist check. + */ + private static class ClientAccess { + static TooltipFlag getTooltipFlag() { + return Minecraft.getInstance().options.advancedItemTooltips ? TooltipFlag.ADVANCED : TooltipFlag.NORMAL; + } + } +} diff --git a/src/main/java/net/neoforged/neoforge/common/world/ModifiableBiomeInfo.java b/src/main/java/net/neoforged/neoforge/common/world/ModifiableBiomeInfo.java index 8099df85c6..74d844fdbf 100644 --- a/src/main/java/net/neoforged/neoforge/common/world/ModifiableBiomeInfo.java +++ b/src/main/java/net/neoforged/neoforge/common/world/ModifiableBiomeInfo.java @@ -10,7 +10,6 @@ import com.mojang.serialization.DynamicOps; import com.mojang.serialization.JsonOps; import java.util.List; -import java.util.Locale; import net.minecraft.core.Holder; import net.minecraft.core.RegistryAccess; import net.minecraft.resources.RegistryOps; @@ -67,20 +66,18 @@ public BiomeInfo getModifiedBiomeInfo() { } /** - * Internal forge method; the game will crash if mods invoke this. + * Internal NeoForge method. Will do nothing if this modifier had already been applied. * Creates and caches the modified biome info. * * @param biome named biome with original data. * @param biomeModifiers biome modifiers to apply. * * @return whether the biome's network-synced data was modified - * - * @throws IllegalStateException if invoked more than once. */ @ApiStatus.Internal public boolean applyBiomeModifiers(final Holder biome, final List biomeModifiers, RegistryAccess registryAccess) { if (this.modifiedBiomeInfo != null) - throw new IllegalStateException(String.format(Locale.ENGLISH, "Biome %s already modified", biome)); + return true; BiomeInfo original = this.getOriginalBiomeInfo(); final BiomeInfo.Builder builder = BiomeInfo.Builder.copyOf(original); diff --git a/src/main/java/net/neoforged/neoforge/common/world/ModifiableStructureInfo.java b/src/main/java/net/neoforged/neoforge/common/world/ModifiableStructureInfo.java index 3247d5f903..55371a81f9 100644 --- a/src/main/java/net/neoforged/neoforge/common/world/ModifiableStructureInfo.java +++ b/src/main/java/net/neoforged/neoforge/common/world/ModifiableStructureInfo.java @@ -6,7 +6,6 @@ package net.neoforged.neoforge.common.world; import java.util.List; -import java.util.Locale; import net.minecraft.core.Holder; import net.minecraft.world.level.levelgen.structure.Structure; import net.minecraft.world.level.levelgen.structure.Structure.StructureSettings; @@ -55,18 +54,16 @@ public StructureInfo getModifiedStructureInfo() { } /** - * Internal neoforge method; the game will crash if mods invoke this. + * Internal NeoForge method. Will do nothing if this modifier had already been applied. * Creates and caches the modified structure info. * * @param structure named structure with original data. * @param structureModifiers structure modifiers to apply. - * - * @throws IllegalStateException if invoked more than once. */ @ApiStatus.Internal public void applyStructureModifiers(final Holder structure, final List structureModifiers) { if (this.modifiedStructureInfo != null) - throw new IllegalStateException(String.format(Locale.ENGLISH, "Structure %s already modified", structure)); + return; StructureInfo original = this.getOriginalStructureInfo(); final StructureInfo.Builder builder = StructureInfo.Builder.copyOf(original); diff --git a/src/main/java/net/neoforged/neoforge/data/loading/DatagenModLoader.java b/src/main/java/net/neoforged/neoforge/data/loading/DatagenModLoader.java index 583269b9cf..687dc8dd71 100644 --- a/src/main/java/net/neoforged/neoforge/data/loading/DatagenModLoader.java +++ b/src/main/java/net/neoforged/neoforge/data/loading/DatagenModLoader.java @@ -16,6 +16,7 @@ import net.minecraft.server.Bootstrap; import net.neoforged.fml.ModLoader; import net.neoforged.neoforge.client.ClientHooks; +import net.neoforged.neoforge.client.entity.animation.json.AnimationTypeManager; import net.neoforged.neoforge.common.data.ExistingFileHelper; import net.neoforged.neoforge.data.event.GatherDataEvent; import net.neoforged.neoforge.internal.CommonModLoader; @@ -55,6 +56,7 @@ public static void begin(final Set mods, final Path path, final Collecti } if (clientGenerators) { ClientHooks.registerSpriteSourceTypes(); + AnimationTypeManager.init(); } existingFileHelper = new ExistingFileHelper(existingPacks, existingMods, structureValidator, assetIndex, assetsDir); ModLoader.runEventGenerator(mc -> new GatherDataEvent(mc, dataGeneratorConfig.makeGenerator(p -> dataGeneratorConfig.isFlat() ? p : p.resolve(mc.getModId()), diff --git a/src/main/java/net/neoforged/neoforge/event/brewing/RegisterBrewingRecipesEvent.java b/src/main/java/net/neoforged/neoforge/event/brewing/RegisterBrewingRecipesEvent.java index 53ff0f6af2..669e61cedd 100644 --- a/src/main/java/net/neoforged/neoforge/event/brewing/RegisterBrewingRecipesEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/brewing/RegisterBrewingRecipesEvent.java @@ -5,6 +5,7 @@ package net.neoforged.neoforge.event.brewing; +import net.minecraft.core.RegistryAccess; import net.minecraft.world.item.alchemy.PotionBrewing; import net.neoforged.bus.api.Event; import org.jetbrains.annotations.ApiStatus; @@ -16,13 +17,19 @@ */ public class RegisterBrewingRecipesEvent extends Event { private final PotionBrewing.Builder builder; + private final RegistryAccess registryAccess; @ApiStatus.Internal - public RegisterBrewingRecipesEvent(PotionBrewing.Builder builder) { + public RegisterBrewingRecipesEvent(PotionBrewing.Builder builder, RegistryAccess registryAccess) { this.builder = builder; + this.registryAccess = registryAccess; } public PotionBrewing.Builder getBuilder() { return builder; } + + public RegistryAccess getRegistryAccess() { + return registryAccess; + } } diff --git a/src/main/java/net/neoforged/neoforge/event/entity/player/CriticalHitEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/player/CriticalHitEvent.java index 03b4c3e32b..53c6d5ba52 100644 --- a/src/main/java/net/neoforged/neoforge/event/entity/player/CriticalHitEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/entity/player/CriticalHitEvent.java @@ -11,10 +11,12 @@ /** * This event is fired when a player attacks an entity in {@link Player#attack(Entity)}. - * It can be used to change the critical hit status and damage modifier *

- * In the event the attack was not a critical hit, the event will still be fired, but it will be preemptively cancelled. - **/ + * It can be used to change the critical hit status and the critical damage multiplier. + * Additionally, this event allows controlling if the critical hit will impact sweep conditions. + *

+ * This event is fired on both the logical client and logical server. + */ public class CriticalHitEvent extends PlayerEvent { private final Entity target; private final float vanillaDmgMultiplier; @@ -22,6 +24,7 @@ public class CriticalHitEvent extends PlayerEvent { private float dmgMultiplier; private boolean isCriticalHit; + private boolean disableSweep = true; /** * Fire via {@link CommonHooks#fireCriticalHit(Player, Entity, boolean, float)} @@ -44,8 +47,6 @@ public Entity getTarget() { * The damage multiplier is applied to the base attack's damage if the attack {@linkplain #isCriticalHit() critically hits}. *

* A damage multiplier of 1.0 will not change the damage, a value of 1.5 will increase the damage by 50%, and so on. - * - * @param modifier The new damage modifier. */ public float getDamageMultiplier() { return this.dmgMultiplier; @@ -55,8 +56,8 @@ public float getDamageMultiplier() { * Sets the damage multiplier for the critical hit. Not used if {@link #isCriticalHit()} is false. *

* Changing the damage modifier to zero does not guarantee that the attack does zero damage. - * - * @param modifier The new damage modifier. Must not be negative. + * + * @param dmgMultiplier The new damage modifier. Must not be negative. * @see #getDamageMultiplier() */ public void setDamageMultiplier(float dmgMultiplier) { @@ -75,7 +76,7 @@ public boolean isCriticalHit() { /** * Changes the critical hit state. - * + * * @param isCriticalHit true if the attack should critically hit */ public void setCriticalHit(boolean isCriticalHit) { @@ -86,7 +87,7 @@ public void setCriticalHit(boolean isCriticalHit) { * Gets the original damage multiplier set by vanilla. *

* If the event {@link #isVanillaCritical()}, the damage multiplier will be 1.5, otherwise it will be 1.0 - * + * * @see #getDamageMultiplier() */ public float getVanillaMultiplier() { @@ -99,4 +100,27 @@ public float getVanillaMultiplier() { public boolean isVanillaCritical() { return this.isVanillaCritical; } + + /** + * Sets if this attack should prevent a sweep from occurring. + *

+ * In vanilla, a critical hit always prevents a sweep from occurring. + * This method can allow an attack to both critically hit and sweep without having to validate the other sweep conditions. + * + * @see {@link SweepAttackEvent} for more advanced sweep attack handling. + */ + public void setDisableSweep(boolean disableSweep) { + this.disableSweep = disableSweep; + } + + /** + * If this attack is a {@linkplain #isCriticalHit() critical hit}, returns if a sweep should be prevented. + *

+ * If this attack is not a critical hit, the return value of this method is meaningless. + * + * @see {@link SweepAttackEvent} for more advanced sweep attack handling. + */ + public boolean disableSweep() { + return disableSweep; + } } diff --git a/src/main/java/net/neoforged/neoforge/event/entity/player/SweepAttackEvent.java b/src/main/java/net/neoforged/neoforge/event/entity/player/SweepAttackEvent.java new file mode 100644 index 0000000000..eb07599ef1 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/event/entity/player/SweepAttackEvent.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.event.entity.player; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.neoforged.bus.api.ICancellableEvent; +import net.neoforged.neoforge.common.ItemAbilities; + +/** + * The SweepAttackEvent is fired when a {@link Player} attacks a target, after the {@link CriticalHitEvent} has been fired. + *

+ * This event can be used to force an attack to trigger a sweep, or to prevent a sweep from occurring. + *

+ * This event is fired on both the logical client and logical server. + */ +public class SweepAttackEvent extends PlayerEvent implements ICancellableEvent { + private final Entity target; + private final boolean isVanillaSweep; + + private boolean isSweeping; + + public SweepAttackEvent(Player player, Entity target, boolean isVanillaSweep) { + super(player); + this.target = target; + this.isSweeping = this.isVanillaSweep = isVanillaSweep; + } + + /** + * Returns the target of the attack, which is guaranteed to be a valid attack target. + */ + public Entity getTarget() { + return this.target; + } + + /** + * Returns true if the attack would cause a sweep by utilizing the vanilla rules. + *

+ * The vanilla rules are as follows. All of them must be true for a vanilla sweep to occur: + *

    + *
  1. The player's attack strength is greater than 90%.
  2. + *
  3. The attack is not a critical hit, or is a critical hit which does not {@linkplain CriticalHitEvent#disableSweep() disable the sweep attack}.
  4. + *
  5. The player is on the ground.
  6. + *
  7. The distance the player has traveled this tick is less than their speed.
  8. + *
  9. The player's weapon supports sweep attacks via {@link ItemAbilities#SWORD_SWEEP}.
  10. + *
+ */ + public boolean isVanillaSweep() { + return this.isVanillaSweep; + } + + /** + * Returns true if the attack will be trigger a sweep. + */ + public boolean isSweeping() { + return this.isSweeping; + } + + /** + * @param sweep Whether to enable a sweep for this attack. + */ + public void setSweeping(boolean sweep) { + this.isSweeping = sweep; + } + + /** + * Cancels the event, preventing further event handlers from acting. Canceling the event will use the current value of {@link #isSweeping()}. + *

+ * If you intend to perform a custom sweep attack, you should cancel the event and {@link #setSweeping} to false before performing your handling. + */ + @Override + public void setCanceled(boolean canceled) { + ICancellableEvent.super.setCanceled(canceled); + } +} diff --git a/src/main/java/net/neoforged/neoforge/event/village/VillagerTradesEvent.java b/src/main/java/net/neoforged/neoforge/event/village/VillagerTradesEvent.java index 58adf8c425..4fb6c4c2fb 100644 --- a/src/main/java/net/neoforged/neoforge/event/village/VillagerTradesEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/village/VillagerTradesEvent.java @@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import java.util.List; +import net.minecraft.core.RegistryAccess; import net.minecraft.world.entity.npc.VillagerData; import net.minecraft.world.entity.npc.VillagerProfession; import net.minecraft.world.entity.npc.VillagerTrades.ItemListing; @@ -14,6 +15,7 @@ import net.neoforged.neoforge.common.BasicItemListing; import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.event.TagsUpdatedEvent; +import org.jetbrains.annotations.ApiStatus; /** * VillagerTradesEvent is fired during reload by {@link TagsUpdatedEvent}. It is used to gather the trade lists for each profession. @@ -28,10 +30,21 @@ public class VillagerTradesEvent extends Event { protected Int2ObjectMap> trades; protected VillagerProfession type; + private final RegistryAccess registryAccess; + /** + * @deprecated Use {@link #VillagerTradesEvent(Int2ObjectMap, VillagerProfession, RegistryAccess)} instead + */ + @Deprecated(forRemoval = true, since = "1.21.1") public VillagerTradesEvent(Int2ObjectMap> trades, VillagerProfession type) { + this(trades, type, RegistryAccess.EMPTY); + } + + @ApiStatus.Internal + public VillagerTradesEvent(Int2ObjectMap> trades, VillagerProfession type, RegistryAccess registryAccess) { this.trades = trades; this.type = type; + this.registryAccess = registryAccess; } public Int2ObjectMap> getTrades() { @@ -41,4 +54,8 @@ public Int2ObjectMap> getTrades() { public VillagerProfession getType() { return type; } + + public RegistryAccess getRegistryAccess() { + return registryAccess; + } } diff --git a/src/main/java/net/neoforged/neoforge/event/village/WandererTradesEvent.java b/src/main/java/net/neoforged/neoforge/event/village/WandererTradesEvent.java index 4c9880952c..ba3766f6d9 100644 --- a/src/main/java/net/neoforged/neoforge/event/village/WandererTradesEvent.java +++ b/src/main/java/net/neoforged/neoforge/event/village/WandererTradesEvent.java @@ -6,11 +6,13 @@ package net.neoforged.neoforge.event.village; import java.util.List; +import net.minecraft.core.RegistryAccess; import net.minecraft.world.entity.npc.VillagerTrades.ItemListing; import net.neoforged.bus.api.Event; import net.neoforged.neoforge.common.BasicItemListing; import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.event.TagsUpdatedEvent; +import org.jetbrains.annotations.ApiStatus; /** * WandererTradesEvent is fired during reload by {@link TagsUpdatedEvent}. It is used to gather the trade lists for the wandering merchant. @@ -21,10 +23,21 @@ public class WandererTradesEvent extends Event { protected List generic; protected List rare; + private final RegistryAccess registryAccess; + /** + * @deprecated Use {@link #WandererTradesEvent(List, List, RegistryAccess)} instead + */ + @Deprecated(forRemoval = true, since = "1.21.1") public WandererTradesEvent(List generic, List rare) { + this(generic, rare, RegistryAccess.EMPTY); + } + + @ApiStatus.Internal + public WandererTradesEvent(List generic, List rare, RegistryAccess registryAccess) { this.generic = generic; this.rare = rare; + this.registryAccess = registryAccess; } public List getGenericTrades() { @@ -34,4 +47,8 @@ public List getGenericTrades() { public List getRareTrades() { return rare; } + + public RegistryAccess getRegistryAccess() { + return registryAccess; + } } diff --git a/src/main/java/net/neoforged/neoforge/items/VanillaInventoryCodeHooks.java b/src/main/java/net/neoforged/neoforge/items/VanillaInventoryCodeHooks.java index e1765da397..6085397554 100644 --- a/src/main/java/net/neoforged/neoforge/items/VanillaInventoryCodeHooks.java +++ b/src/main/java/net/neoforged/neoforge/items/VanillaInventoryCodeHooks.java @@ -10,6 +10,7 @@ import java.util.Optional; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.FrontAndTop; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySelector; import net.minecraft.world.item.ItemStack; @@ -17,10 +18,12 @@ import net.minecraft.world.level.block.DropperBlock; import net.minecraft.world.level.block.HopperBlock; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.CrafterBlockEntity; import net.minecraft.world.level.block.entity.DispenserBlockEntity; import net.minecraft.world.level.block.entity.Hopper; import net.minecraft.world.level.block.entity.HopperBlockEntity; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.phys.AABB; import net.neoforged.neoforge.capabilities.Capabilities; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -121,6 +124,21 @@ public static boolean insertHook(HopperBlockEntity hopper) { .orElse(false); } + /** + * Added capability support for the Crafter dispensing the result + */ + public static ItemStack insertCrafterOutput(Level level, BlockPos pos, CrafterBlockEntity crafterBlockEntity, ItemStack stack) { + FrontAndTop frontAndTop = level.getBlockState(pos).getValue(BlockStateProperties.ORIENTATION); + return getAttachedItemHandler(level, pos, frontAndTop.front()) + .map(destinationResult -> { + IItemHandler itemHandler = destinationResult.getKey(); + Object destination = destinationResult.getValue(); + ItemStack remainder = putStackInInventoryAllSlots(crafterBlockEntity, destination, itemHandler, stack); + return remainder; + }) + .orElse(stack); + } + private static ItemStack putStackInInventoryAllSlots(BlockEntity source, Object destination, IItemHandler destInventory, ItemStack stack) { for (int slot = 0; slot < destInventory.getSlots() && !stack.isEmpty(); slot++) { stack = insertStack(source, destination, destInventory, stack, slot); diff --git a/src/main/java/net/neoforged/neoforge/logging/CrashReportExtender.java b/src/main/java/net/neoforged/neoforge/logging/CrashReportExtender.java index 21d2ae09fb..3fddbac195 100644 --- a/src/main/java/net/neoforged/neoforge/logging/CrashReportExtender.java +++ b/src/main/java/net/neoforged/neoforge/logging/CrashReportExtender.java @@ -21,6 +21,7 @@ import net.neoforged.fml.CrashReportCallables; import net.neoforged.fml.ISystemReportExtender; import net.neoforged.fml.ModLoadingIssue; +import net.neoforged.fml.i18n.FMLTranslations; import net.neoforged.neoforge.forge.snapshots.ForgeSnapshotsMod; import net.neoforged.neoforgespi.language.IModFileInfo; import net.neoforged.neoforgespi.language.IModInfo; @@ -54,28 +55,42 @@ public static String generateEnhancedStackTrace(final Throwable throwable, boole return header ? s : s.substring(s.indexOf(Strings.LINE_SEPARATOR)); } + private static final StackTraceElement[] BLANK_STACK_TRACE = new StackTraceElement[0]; + public static File dumpModLoadingCrashReport(final Logger logger, final List issues, final File topLevelDir) { - final CrashReport crashReport = CrashReport.forThrowable(new Exception("Mod Loading has failed"), "Mod loading error has occurred"); + final CrashReport crashReport = CrashReport.forThrowable(new ModLoadingCrashException("Mod loading has failed"), "Mod loading failures have occurred; consult the issue messages for more details"); for (var issue : issues) { final Optional modInfo = Optional.ofNullable(issue.affectedMod()); - final CrashReportCategory category = crashReport.addCategory(modInfo.map(iModInfo -> "MOD " + iModInfo.getModId()).orElse("NO MOD INFO AVAILABLE")); + final CrashReportCategory category = crashReport.addCategory(modInfo.map(iModInfo -> "Mod loading issue for: " + iModInfo.getModId()).orElse("Mod loading issue")); Throwable cause = issue.cause(); int depth = 0; while (cause != null && cause.getCause() != null && cause.getCause() != cause) { category.setDetail("Caused by " + (depth++), cause + generateEnhancedStackTrace(cause.getStackTrace()).replaceAll(Strings.LINE_SEPARATOR + "\t", "\n\t\t")); cause = cause.getCause(); } + // Set the stack trace to the issue cause if possible; if there is no issue cause, then remove the + // stacktrace (since otherwise it is set to the report's 'root' exception, which is a dummy exception) if (cause != null) - category.applyStackTrace(cause); - category.setDetail("Mod File", () -> modInfo.map(IModInfo::getOwningFile).map(t -> t.getFile().getFilePath().toUri().getPath()).orElse("NO FILE INFO")); - category.setDetail("Failure message", () -> issue.translationKey().replace("\n", "\n\t\t")); - for (int i = 0; i < issue.translationArgs().size(); i++) { - var arg = issue.translationArgs().get(i); - category.setDetail("Failure message arg " + (i + 1), () -> arg.toString().replace("\n", "\n\t\t")); + category.setStackTrace(cause.getStackTrace()); + else + category.setStackTrace(BLANK_STACK_TRACE); + category.setDetail("Mod file", () -> modInfo.map(IModInfo::getOwningFile).map(t -> t.getFile().getFilePath().toUri().getPath()).orElse("")); + + try { + //noinspection UnstableApiUsage + category.setDetail("Failure message", () -> FMLTranslations.stripControlCodes(FMLTranslations.translateIssueEnglish(issue)).replace("\n", "\n\t\t")); + } catch (Exception e) { + // If translating the issue failed, fallback to just adding the raw translation key and arguments + category.setDetail("Failure message", () -> issue.translationKey().replace("\n", "\n\t\t")); + for (int i = 0; i < issue.translationArgs().size(); i++) { + var arg = issue.translationArgs().get(i); + category.setDetail("Failure message arg " + (i + 1), () -> arg.toString().replace("\n", "\n\t\t")); + } } - category.setDetail("Mod Version", () -> modInfo.map(IModInfo::getVersion).map(Object::toString).orElse("NO MOD INFO AVAILABLE")); - category.setDetail("Mod Issue URL", () -> modInfo.map(IModInfo::getOwningFile).map(IModFileInfo.class::cast).flatMap(mfi -> mfi.getConfig().getConfigElement("issueTrackerURL")).orElse("NOT PROVIDED")); - category.setDetail("Exception message", Objects.toString(cause, "MISSING EXCEPTION MESSAGE")); + + category.setDetail("Mod version", () -> modInfo.map(IModInfo::getVersion).map(Object::toString).orElse("")); + category.setDetail("Mod issues URL", () -> modInfo.map(IModInfo::getOwningFile).map(IModFileInfo.class::cast).flatMap(mfi -> mfi.getConfig().getConfigElement("issueTrackerURL")).orElse("")); + category.setDetail("Exception message", Objects.toString(cause, "")); } final File file1 = new File(topLevelDir, "crash-reports"); final File file2 = new File(file1, "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-fml.txt"); @@ -87,4 +102,24 @@ public static File dumpModLoadingCrashReport(final Logger logger, final ListThe stacktrace is very likely to be constant (since its only invoked by the sided mod loader classes), so their + * stacktrace is irrelevant for debugging and only serve to distract the reader from the actual exceptions further + * down in the crash report.

+ */ + private static class ModLoadingCrashException extends Exception { + public ModLoadingCrashException(String message) { + super(message); + } + + @Override + public synchronized Throwable fillInStackTrace() { + // Do not fill in the stack trace + return this; + } + } } diff --git a/src/main/java/net/neoforged/neoforge/network/ConfigurationInitialization.java b/src/main/java/net/neoforged/neoforge/network/ConfigurationInitialization.java index c9713d4ed1..2c64664388 100644 --- a/src/main/java/net/neoforged/neoforge/network/ConfigurationInitialization.java +++ b/src/main/java/net/neoforged/neoforge/network/ConfigurationInitialization.java @@ -12,10 +12,14 @@ import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.neoforge.network.configuration.CheckExtensibleEnums; +import net.neoforged.neoforge.network.configuration.CommonRegisterTask; +import net.neoforged.neoforge.network.configuration.CommonVersionTask; import net.neoforged.neoforge.network.configuration.RegistryDataMapNegotiation; import net.neoforged.neoforge.network.configuration.SyncConfig; import net.neoforged.neoforge.network.configuration.SyncRegistries; import net.neoforged.neoforge.network.event.RegisterConfigurationTasksEvent; +import net.neoforged.neoforge.network.payload.CommonRegisterPayload; +import net.neoforged.neoforge.network.payload.CommonVersionPayload; import net.neoforged.neoforge.network.payload.ConfigFilePayload; import net.neoforged.neoforge.network.payload.FrozenRegistryPayload; import net.neoforged.neoforge.network.payload.FrozenRegistrySyncCompletedPayload; @@ -39,12 +43,18 @@ public static void configureEarlyTasks(ServerConfigurationPacketListener listene @SubscribeEvent private static void configureModdedClient(RegisterConfigurationTasksEvent event) { - if (event.getListener().hasChannel(ConfigFilePayload.TYPE)) { - event.register(new SyncConfig(event.getListener())); + ServerConfigurationPacketListener listener = event.getListener(); + if (listener.hasChannel(CommonVersionPayload.TYPE) && listener.hasChannel(CommonRegisterPayload.TYPE)) { + event.register(new CommonVersionTask()); + event.register(new CommonRegisterTask()); + } + + if (listener.hasChannel(ConfigFilePayload.TYPE)) { + event.register(new SyncConfig(listener)); } //These two can always be registered they detect the listener connection type internally and will skip themselves. - event.register(new RegistryDataMapNegotiation(event.getListener())); - event.register(new CheckExtensibleEnums(event.getListener())); + event.register(new RegistryDataMapNegotiation(listener)); + event.register(new CheckExtensibleEnums(listener)); } } diff --git a/src/main/java/net/neoforged/neoforge/network/configuration/CommonRegisterTask.java b/src/main/java/net/neoforged/neoforge/network/configuration/CommonRegisterTask.java new file mode 100644 index 0000000000..de0b843bee --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/network/configuration/CommonRegisterTask.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.network.configuration; + +import java.util.function.Consumer; +import net.minecraft.network.ConnectionProtocol; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion; +import net.neoforged.neoforge.network.payload.CommonRegisterPayload; +import net.neoforged.neoforge.network.registration.NetworkRegistry; +import org.jetbrains.annotations.ApiStatus; + +/** + * Common Register configuration task. After completion of {@link CommonVersionTask}, sends a {@link CommonRegisterPayload} to the client + * containing all known serverbound channels, and awaits a response containing the client's known clientbound channels. + */ +@ApiStatus.Internal +public record CommonRegisterTask() implements ICustomConfigurationTask { + public static final Type TYPE = new Type(ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "common_register")); + + @Override + public Type type() { + return TYPE; + } + + @Override + public void run(Consumer sender) { + // There is currently no implementation for a version handshake, and the only existing version is 1, so we only send 1. + // Version negotiation will have to be implemented properly if a version 2 is ever added. + sender.accept(new CommonRegisterPayload(1, ConnectionProtocol.PLAY, NetworkRegistry.getCommonPlayChannels(PacketFlow.SERVERBOUND))); + } +} diff --git a/src/main/java/net/neoforged/neoforge/network/configuration/CommonVersionTask.java b/src/main/java/net/neoforged/neoforge/network/configuration/CommonVersionTask.java new file mode 100644 index 0000000000..a8f018a1d3 --- /dev/null +++ b/src/main/java/net/neoforged/neoforge/network/configuration/CommonVersionTask.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.network.configuration; + +import java.util.function.Consumer; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion; +import net.neoforged.neoforge.network.payload.CommonVersionPayload; +import org.jetbrains.annotations.ApiStatus; + +/** + * Common Version configuration task. Initiated after registry sync to begin the c:register handshake. + * The server will start the task, send c:version to the client, and await a reply. Upon reply, we transition to {@link CommonRegisterTask}. + */ +@ApiStatus.Internal +public record CommonVersionTask() implements ICustomConfigurationTask { + public static final Type TYPE = new Type(ResourceLocation.fromNamespaceAndPath(NeoForgeVersion.MOD_ID, "common_version")); + + @Override + public Type type() { + return TYPE; + } + + @Override + public void run(Consumer sender) { + sender.accept(new CommonVersionPayload()); + } +} diff --git a/src/main/java/net/neoforged/neoforge/network/registration/NetworkRegistry.java b/src/main/java/net/neoforged/neoforge/network/registration/NetworkRegistry.java index da26d5bb94..899598ef6d 100644 --- a/src/main/java/net/neoforged/neoforge/network/registration/NetworkRegistry.java +++ b/src/main/java/net/neoforged/neoforge/network/registration/NetworkRegistry.java @@ -48,6 +48,8 @@ import net.neoforged.neoforge.common.extensions.ICommonPacketListener; import net.neoforged.neoforge.internal.versions.neoforge.NeoForgeVersion; import net.neoforged.neoforge.network.configuration.CheckExtensibleEnums; +import net.neoforged.neoforge.network.configuration.CommonRegisterTask; +import net.neoforged.neoforge.network.configuration.CommonVersionTask; import net.neoforged.neoforge.network.connection.ConnectionType; import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; import net.neoforged.neoforge.network.filters.NetworkFilters; @@ -379,7 +381,6 @@ public static void initializeNeoForgeConnection(ServerConfigurationPacketListene nowListeningOn.addAll(getInitialListeningChannels(listener.flow())); nowListeningOn.addAll(setup.getChannels(ConnectionProtocol.CONFIGURATION).keySet()); listener.send(new MinecraftRegisterPayload(nowListeningOn.build())); - sendCommonPayloads(listener); } /** @@ -419,7 +420,6 @@ public static boolean initializeOtherConnection(ServerConfigurationPacketListene .filter(registration -> registration.getValue().optional()) .forEach(registration -> nowListeningOn.add(registration.getKey())); listener.send(new MinecraftRegisterPayload(nowListeningOn.build())); - sendCommonPayloads(listener); return true; } @@ -516,7 +516,6 @@ public static void initializeNeoForgeConnection(ClientConfigurationPacketListene nowListeningOn.addAll(getInitialListeningChannels(listener.flow())); nowListeningOn.addAll(setup.getChannels(ConnectionProtocol.CONFIGURATION).keySet()); listener.send(new MinecraftRegisterPayload(nowListeningOn.build())); - sendCommonPayloads(listener); } /** @@ -569,7 +568,6 @@ public static void initializeOtherConnection(ClientConfigurationPacketListener l .filter(registration -> registration.getValue().optional()) .forEach(registration -> nowListeningOn.add(registration.getKey())); listener.send(new MinecraftRegisterPayload(nowListeningOn.build())); - sendCommonPayloads(listener); } /** @@ -724,14 +722,22 @@ public static Set getInitialServerUnregisterChannels() { *

* Invoked on the network thread. * - * @param connection The current connection. - * @param payload The incoming version payload. + * @param listener The receiving listener. + * @param payload The incoming version payload. */ - public static void checkCommonVersion(Connection connection, CommonVersionPayload payload) { + public static void checkCommonVersion(ICommonPacketListener listener, CommonVersionPayload payload) { List otherVersions = payload.versions(); if (otherVersions.stream().noneMatch(SUPPORTED_COMMON_NETWORKING_VERSIONS::contains)) { String versions = String.join(", ", SUPPORTED_COMMON_NETWORKING_VERSIONS.stream().map(i -> i.toString()).toList()); - connection.disconnect(Component.literal("Unsupported common network version. This installation of NeoForge only supports: " + versions)); + listener.disconnect(Component.literal("Unsupported common network version. This installation of NeoForge only supports: " + versions)); + } + + if (listener.protocol() == ConnectionProtocol.CONFIGURATION) { + if (listener.flow() == PacketFlow.SERVERBOUND) { + ((ServerConfigurationPacketListener) listener).finishCurrentTask(CommonVersionTask.TYPE); + } else { + listener.send(new CommonVersionPayload()); + } } } @@ -740,13 +746,21 @@ public static void checkCommonVersion(Connection connection, CommonVersionPayloa *

* Invoked on the network thread. * - * @param connection The connection to add the channels to. - * @param payload The incoming register payload. + * @param listener The receiving listener. + * @param payload The incoming register payload. */ - public static void onCommonRegister(Connection connection, CommonRegisterPayload payload) { - Set channels = ChannelAttributes.getOrCreateCommonChannels(connection, payload.protocol()); + public static void onCommonRegister(ICommonPacketListener listener, CommonRegisterPayload payload) { + Set channels = ChannelAttributes.getOrCreateCommonChannels(listener.getConnection(), payload.protocol()); channels.clear(); channels.addAll(payload.channels()); + + if (listener.protocol() == ConnectionProtocol.CONFIGURATION) { + if (listener.flow() == PacketFlow.SERVERBOUND) { + ((ServerConfigurationPacketListener) listener).finishCurrentTask(CommonRegisterTask.TYPE); + } else { + listener.send(new CommonRegisterPayload(1, ConnectionProtocol.PLAY, getCommonPlayChannels(PacketFlow.CLIENTBOUND))); + } + } } public static Set getCommonPlayChannels(PacketFlow flow) { @@ -758,16 +772,6 @@ public static Set getCommonPlayChannels(PacketFlow flow) { .collect(Collectors.toSet()); } - public static void sendCommonPayloads(ICommonPacketListener listener) { - if (listener.hasChannel(CommonVersionPayload.ID)) { - listener.send(new CommonVersionPayload()); - } - - if (listener.hasChannel(CommonRegisterPayload.ID)) { - listener.send(new CommonRegisterPayload(1, ConnectionProtocol.PLAY, getCommonPlayChannels(listener.flow()))); - } - } - /** * Invoked when the configuration phase of a connection is completed. *

diff --git a/src/main/java/net/neoforged/neoforge/network/registration/PayloadRegistrar.java b/src/main/java/net/neoforged/neoforge/network/registration/PayloadRegistrar.java index 2e1dee20b0..366e9c8b50 100644 --- a/src/main/java/net/neoforged/neoforge/network/registration/PayloadRegistrar.java +++ b/src/main/java/net/neoforged/neoforge/network/registration/PayloadRegistrar.java @@ -35,6 +35,7 @@ public PayloadRegistrar(String version) { private PayloadRegistrar(PayloadRegistrar source) { this.version = source.version; this.optional = source.optional; + this.thread = source.thread; } /** diff --git a/src/main/java/net/neoforged/neoforge/registries/DataPackRegistryEvent.java b/src/main/java/net/neoforged/neoforge/registries/DataPackRegistryEvent.java index b316e643a2..8fee27ff8e 100644 --- a/src/main/java/net/neoforged/neoforge/registries/DataPackRegistryEvent.java +++ b/src/main/java/net/neoforged/neoforge/registries/DataPackRegistryEvent.java @@ -8,6 +8,7 @@ import com.mojang.serialization.Codec; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.core.Registry; import net.minecraft.resources.RegistryDataLoader; @@ -74,6 +75,29 @@ public void dataPackRegistry(ResourceKey> registryKey, Codec this.registryDataList.add(new DataPackRegistryData<>(new RegistryDataLoader.RegistryData<>(registryKey, codec, false), networkCodec)); } + /** + * Registers the registry key as a datapack registry with a {@link RegistryBuilder} configurator, which will cause data to be loaded from + * a datapack folder based on the registry's name. + *

+ * Data JSONs will be loaded from {@code data//modid/registryname/}, where {@code modid} is the namespace of the registry key. + * + * @param registryKey the root registry key of the new datapack registry + * @param codec the codec to be used for loading data from datapacks on servers + * @param networkCodec the codec to be used for syncing loaded data to clients. + * If {@code networkCodec} is null, data will not be synced, and clients are not required to have this + * datapack registry to join a server. + *

+ * If {@code networkCodec} is not null, clients must have this datapack registry/mod + * when joining a server that has this datapack registry/mod. + * The data will be synced using the network codec and accessible via {@link ClientPacketListener#registryAccess()}. + * @param consumer A consumer that configures the provided RegistryBuilder + * @see #dataPackRegistry(ResourceKey, Codec) + * @see #dataPackRegistry(ResourceKey, Codec, Codec) + */ + public void dataPackRegistry(ResourceKey> registryKey, Codec codec, @Nullable Codec networkCodec, Consumer> consumer) { + this.registryDataList.add(new DataPackRegistryData<>(new RegistryDataLoader.RegistryData<>(registryKey, codec, false, consumer), networkCodec)); + } + void process() { for (DataPackRegistryData registryData : this.registryDataList) { DataPackRegistriesHooks.addRegistryCodec(registryData); diff --git a/src/main/java/net/neoforged/neoforge/registries/DeferredRegister.java b/src/main/java/net/neoforged/neoforge/registries/DeferredRegister.java index 8222fffabe..f404f8f8e4 100644 --- a/src/main/java/net/neoforged/neoforge/registries/DeferredRegister.java +++ b/src/main/java/net/neoforged/neoforge/registries/DeferredRegister.java @@ -156,6 +156,20 @@ public static DeferredRegister.Blocks createBlocks(String modid) { return new Blocks(modid); } + /** + * Factory for a specialized DeferredRegister for {@link DataComponentType DataComponentTypes}. + * + * @param registryKey The key for the data component type registry, like {@link Registries#DATA_COMPONENT_TYPE} for item data components + * @param modid The namespace for all objects registered to this DeferredRegister + * @see #create(Registry, String) + * @see #create(ResourceKey, String) + * @see #create(ResourceLocation, String) + * @see #createItems(String) + */ + public static DataComponents createDataComponents(ResourceKey>> registryKey, String modid) { + return new DataComponents(registryKey, modid); + } + /** * Factory for a specialized DeferredRegister for {@link DataComponentType DataComponentTypes}. * @@ -164,7 +178,9 @@ public static DeferredRegister.Blocks createBlocks(String modid) { * @see #create(ResourceKey, String) * @see #create(ResourceLocation, String) * @see #createItems(String) + * @deprecated Scheduled for removal in 1.21.2; use {@link DeferredRegister#createDataComponents(ResourceKey, String)} with {@link Registries#DATA_COMPONENT_TYPE} instead */ + @Deprecated(since = "1.21.1", forRemoval = true) public static DataComponents createDataComponents(String modid) { return new DataComponents(modid); } @@ -599,6 +615,12 @@ protected DeferredItem createHolder(ResourceKey> { + protected DataComponents(ResourceKey>> registryKey, String namespace) { + super(registryKey, namespace); + } + + /** @deprecated Scheduled for removal in 1.21.2; use {@link DataComponents#DataComponents(ResourceKey, String)} */ + @Deprecated(since = "1.21.1", forRemoval = true) protected DataComponents(String namespace) { super(Registries.DATA_COMPONENT_TYPE, namespace); } diff --git a/src/main/java/net/neoforged/neoforge/server/command/GenerateCommand.java b/src/main/java/net/neoforged/neoforge/server/command/GenerateCommand.java index a37a5732b1..d3ef9c3f80 100644 --- a/src/main/java/net/neoforged/neoforge/server/command/GenerateCommand.java +++ b/src/main/java/net/neoforged/neoforge/server/command/GenerateCommand.java @@ -96,8 +96,10 @@ private static int stopGeneration(CommandSourceStack source) { double percent = (double) count / total * 100.0; source.sendSuccess(() -> Component.translatable("commands.neoforge.chunkgen.stopped", count, total, percent), true); - generationBar.close(); - generationBar = null; + if (generationBar != null) { + generationBar.close(); + generationBar = null; + } activeTask = null; } else { source.sendSuccess(() -> Component.translatable("commands.neoforge.chunkgen.not_running"), false); diff --git a/src/main/java/net/neoforged/neoforge/server/command/TPSCommand.java b/src/main/java/net/neoforged/neoforge/server/command/TPSCommand.java index eb50fd2963..4703bda119 100644 --- a/src/main/java/net/neoforged/neoforge/server/command/TPSCommand.java +++ b/src/main/java/net/neoforged/neoforge/server/command/TPSCommand.java @@ -5,18 +5,27 @@ package net.neoforged.neoforge.server.command; +import com.google.common.math.Stats; +import com.mojang.brigadier.Command; import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import java.text.DecimalFormat; +import net.minecraft.ChatFormatting; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.commands.arguments.DimensionArgument; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.CommonColors; +import net.minecraft.util.Mth; import net.minecraft.util.TimeUtil; -import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.TickRateManager; +import org.jetbrains.annotations.Nullable; +import org.joml.Math; class TPSCommand { private static final DecimalFormat TIME_FORMATTER = new DecimalFormat("########0.000"); @@ -24,40 +33,66 @@ class TPSCommand { static ArgumentBuilder register() { return Commands.literal("tps") - .requires(cs -> cs.hasPermission(0)) //permission - .then(Commands.argument("dim", DimensionArgument.dimension()) - .executes(ctx -> sendTime(ctx.getSource(), DimensionArgument.getDimension(ctx, "dim")))) + .then(Commands.argument("dimension", DimensionArgument.dimension()) + .executes(ctx -> sendTime(ctx, DimensionArgument.getDimension(ctx, "dimension")))) .executes(ctx -> { - for (ServerLevel dim : ctx.getSource().getServer().getAllLevels()) - sendTime(ctx.getSource(), dim); + for (ServerLevel dimension : ctx.getSource().getServer().getAllLevels()) { + sendTime(ctx, dimension); + } - long[] times = ctx.getSource().getServer().getTickTimesNanos(); - double meanTickTime = mean(times) * 1.0E-6D; - double meanTPS = TimeUtil.MILLISECONDS_PER_SECOND / Math.max(meanTickTime, ctx.getSource().getServer().tickRateManager().millisecondsPerTick()); - ctx.getSource().sendSuccess(() -> Component.translatable("commands.neoforge.tps.summary.all", TIME_FORMATTER.format(meanTickTime), TIME_FORMATTER.format(meanTPS)), false); - - return 0; + sendTime(ctx, null); + return Command.SINGLE_SUCCESS; }); } - private static int sendTime(CommandSourceStack cs, ServerLevel dim) throws CommandSyntaxException { - long[] times = cs.getServer().getTickTime(dim.dimension()); + private static int sendTime(CommandContext context, @Nullable ServerLevel dimension) throws CommandSyntaxException { + var src = context.getSource(); + src.sendSuccess(() -> createComponent(src.getServer(), dimension), false); + return Command.SINGLE_SUCCESS; + } + + private static Component createComponent(MinecraftServer server, @Nullable ServerLevel dimension) { + long[] times; + TickRateManager tickRateManager; + + if (dimension == null) { + times = server.getTickTimesNanos(); + tickRateManager = server.tickRateManager(); + } else { + var dimensionTimes = server.getTickTime(dimension.dimension()); + times = dimensionTimes == null ? UNLOADED : dimensionTimes; + tickRateManager = dimension.tickRateManager(); + } + + var tickTime = Stats.meanOf(times) / TimeUtil.NANOSECONDS_PER_MILLISECOND; + var tps = TimeUtil.MILLISECONDS_PER_SECOND / Math.max(tickTime, tickRateManager.millisecondsPerTick()); + var tickTimeComponent = Component.literal(TIME_FORMATTER.format(tickTime)).withColor(CommonColors.LIGHT_GRAY); + var tpsComponent = Component.literal(TIME_FORMATTER.format(tps)).withColor(calculateTPSColor(tickRateManager, tps)); + + MutableComponent component; + + if (dimension == null) { + component = Component.translatable("commands.neoforge.tps.overall", tpsComponent, tickTimeComponent); + } else { + var dimensionType = dimension.dimensionTypeRegistration(); - if (times == null) // Null means the world is unloaded. Not invalid. That's taken care of by DimensionArgument itself. - times = UNLOADED; + var dimensionName = Component.empty().append(dimension.getDescription()).withStyle(style -> style + .withColor(ChatFormatting.GREEN) + .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.translatable( + "commands.neoforge.tps.dimension.tooltip", + dimension.dimension().location().toString(), + dimensionType.getRegisteredName())))); - final Registry reg = cs.registryAccess().registryOrThrow(Registries.DIMENSION_TYPE); - double worldTickTime = mean(times) * 1.0E-6D; - double worldTPS = TimeUtil.MILLISECONDS_PER_SECOND / Math.max(worldTickTime, dim.tickRateManager().millisecondsPerTick()); - cs.sendSuccess(() -> Component.translatable("commands.neoforge.tps.summary.named", dim.getDescription(), reg.getKey(dim.dimensionType()).toString(), TIME_FORMATTER.format(worldTickTime), TIME_FORMATTER.format(worldTPS)), false); + component = Component.translatable("commands.neoforge.tps.dimension", dimensionName, tpsComponent, tickTimeComponent); + } - return 1; + return component.withStyle(style -> style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.translatable("commands.neoforge.tps.tooltip", tickRateManager.tickrate())))); } - private static long mean(long[] values) { - long sum = 0L; - for (long v : values) - sum += v; - return sum / values.length; + private static int calculateTPSColor(TickRateManager tickRateManager, double tps) { + // Improved color blending code thanks to sciwhiz12 + float maxTPS = TimeUtil.MILLISECONDS_PER_SECOND / tickRateManager.millisecondsPerTick(); + // 0 degrees (0F) is red, 120 degrees (0.33F) is green + return Mth.hsvToRgb((float) (Mth.inverseLerp(tps, 0, maxTPS) * 0.33F), 1F, 1F); } } diff --git a/src/main/resources/META-INF/coremods.json b/src/main/resources/META-INF/coremods.json deleted file mode 100644 index 98eab2a142..0000000000 --- a/src/main/resources/META-INF/coremods.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "field_to_method": "coremods/field_to_method.js", - "field_to_instanceof": "coremods/field_to_instanceof.js", - "add_bouncer_method": "coremods/add_bouncer_method.js", - "method_redirector": "coremods/method_redirector.js" -} diff --git a/src/main/resources/assets/neoforge/lang/cs_cz.json b/src/main/resources/assets/neoforge/lang/cs_cz.json index 75160c4ebe..2c95bf1deb 100644 --- a/src/main/resources/assets/neoforge/lang/cs_cz.json +++ b/src/main/resources/assets/neoforge/lang/cs_cz.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "Vybrané ID dimenze (%1$s) je neplatné.", "commands.neoforge.setdim.invalid.nochange": "Vybraná entita (%1$s) již existuje v specifické dimenzi (%2$s).", "commands.neoforge.setdim.deprecated": "Tento příkaz je zastaralý kvůli smazání ve verzi 1.17, použijte místo něj %s.", - "commands.neoforge.tps.invalid": "Neplatná dimenze %1$s Možné hodnoty: %2$s", - "commands.neoforge.tps.summary.all": "Celkem: Průměrná doba ticku: %1$s ms. Průměrný TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Módový seznam: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Průměrná doba ticku: %2$s ms. Průměrný TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Průměrná doba ticku: %3$s ms. Průměrný TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Sledování entity povoleno na %d sekund.", "commands.neoforge.tracking.entity.reset": "Data časování entity byla vymazána!", "commands.neoforge.tracking.invalid": "Neplatná sledovací data.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Čas v %s běží normální rychlostí (20 minut za den).", "commands.neoforge.timespeed.set": "Nastaven běh času v %s na %sx (%s minut za den).", "commands.neoforge.timespeed.set.default": "Nastaven běh času v %s na základní nastavení (20 minut za den).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Konfigurace pro %s typu %s nalezena na %s", "commands.config.noconfig": "Konfigurace pro %s typu %s nenalezena", "neoforge.update.beta.1": "%sPOZOR: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "Konfigurace Serveru %s", "neoforge.configuration.uitext.title.common": "Běžná konfigurace %s", "neoforge.configuration.uitext.title.startup": "Konfigurace při spuštění %s", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Nastavení jsou zde rozhodnuté serverem a nemohou být změněny když jste online.", - "color": "červený" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Nastavení zde nemohou být změněny, když je Vaše hra otevřená k LAN. Prosím, vraťte se do hlavního menu a načtěte svět znovu.", - "color": "červený" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Nastavení zde jsou dostupné pouze až po načtení světa.", - "color": "červený" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "Tato hodnota nemůže být změněna v UI. Prosím, kontaktujte autora módu, aby pro něj poskytl UI.", - "color": "červený" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "Tato hodnota je moc veliká pro změnu v UI. Prosím, změňte ji v konfiguračním souboru.", - "color": "červený" - } - ], + "neoforge.configuration.uitext.notonline": "Nastavení jsou zde rozhodnuté serverem a nemohou být změněny když jste online.", + "neoforge.configuration.uitext.notlan": "Nastavení zde nemohou být změněny, když je Vaše hra otevřená k LAN. Prosím, vraťte se do hlavního menu a načtěte svět znovu.", + "neoforge.configuration.uitext.notloaded": "Nastavení zde jsou dostupné pouze až po načtení světa.", + "neoforge.configuration.uitext.unsupportedelement": "Tato hodnota nemůže být změněna v UI. Prosím, kontaktujte autora módu, aby pro něj poskytl UI.", + "neoforge.configuration.uitext.longstring": "Tato hodnota je moc veliká pro změnu v UI. Prosím, změňte ji v konfiguračním souboru.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Změnit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "zlato", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Vrátit zpět", "neoforge.configuration.uitext.undo.tooltip": "Vrátí zpět změny pouze na této obrazovce.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRozmezí: ", - "color": "šedivá" - }, - { - "index": 0, - "color": "šedivá" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "Soubor: \"", - "color": "šedivá" - }, - { - "index": 0, - "color": "šedivá" - }, - { - "text": "\"", - "color": "šedivá" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Obecné volby", "neoforge.configuration.uitext.client": "Volby klienta", "neoforge.configuration.uitext.server": "Volby serveru", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "Svět se musí znovu načíst", "neoforge.configuration.uitext.restart.server.text": "Jeden či více konfiguračních možností, které byly změněny, se projeví až se znovu načte svět.", "neoforge.configuration.uitext.restart.return": "Ignorovat", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Vaše změny nebudou mít žádný účinek do restartu!", - "color": "červená", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Vaše změny nebudou mít žádný účinek do restartu!", "neoforge.configuration.title": "NeoForge konfigurace", "neoforge.configuration.section.neoforge.client.toml": "Nastavení Klienta", "neoforge.configuration.section.neoforge.client.toml.title": "Nastavení Klienta", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Manažer oprávnění", "neoforge.configgui.permissionHandler.tooltip": "Manažer oprávnění použitý na serveru. Výchozí je neoforge:default_handler pokud žádný handler s tímto názvem není registrován.", "neoforge.configgui.removeErroringBlockEntities": "Odstranit Block Entity volající chyby", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Zapněte toto nastavení pro smazání všech entit které vyhazují error ve své \"update\" metodě, místo vypnutí serveru a vytvoření crash logu.\n\n", - { - "text": "POZOR, TOTO MŮŽE VŠECHNO POKAZIT.\nBUĎTE OPATRNÍ.\nNEJSME ZODPOVĚDNI ZA JAKÉKOLIV NAPÁCHANÉ ŠKODY.", - "color": "červená", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "POZOR, TOTO MŮŽE VŠECHNO POKAZIT.\nBUĎTE OPATRNÍ.\nNEJSME ZODPOVĚDNI ZA JAKÉKOLIV NAPÁCHANÉ ŠKODY.", "neoforge.configgui.removeErroringEntities": "Odstranit Entity volající chyby", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Zapněte toto nastavení pro smazání všech block entit které vyhazují error ve své \"update\" metodě, místo vypnutí serveru a vytvoření crash logu.\n\n", - { - "text": "POZOR, TOTO MŮŽE VŠECHNO POKAZIT.\nBUĎTE OPATRNÍ.\nNEJSME ZODPOVĚDNI ZA JAKÉKOLIV NAPÁCHANÉ ŠKODY.", - "color": "červená", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "POZOR, TOTO MŮŽE VŠECHNO POKAZIT.\nBUĎTE OPATRNÍ.\nNEJSME ZODPOVĚDNI ZA JAKÉKOLIV NAPÁCHANÉ ŠKODY.", "neoforge.configgui.showLoadWarnings": "Zobrazit Upozornění při Načítání", "neoforge.configgui.showLoadWarnings.tooltip": "Pokud je zapnuto, NeoForge zobrazí jakákoliv upozornění, která se vyskytla při načítání.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Používejte kombinovaný doplňek DEPTH_STENCIL", diff --git a/src/main/resources/assets/neoforge/lang/da_dk.json b/src/main/resources/assets/neoforge/lang/da_dk.json index cb6bec74a1..667edefa31 100644 --- a/src/main/resources/assets/neoforge/lang/da_dk.json +++ b/src/main/resources/assets/neoforge/lang/da_dk.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "This command is deprecated for removal in 1.17, use %s instead.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Entity tracking enabled for %d seconds.", "commands.neoforge.tracking.entity.reset": "Entity timings data has been cleared!", "commands.neoforge.tracking.invalid": "Invalid tracking data.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Config for %s of type %s found at %s", "commands.config.noconfig": "Config for %s of type %s not found", "neoforge.update.beta.1": "%sADVARSEL: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Remove Erroring Block Entities", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Remove Erroring Entities", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Show Load Warnings", "neoforge.configgui.showLoadWarnings.tooltip": "When enabled, NeoForge will show any warnings that occurred during loading.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/de_de.json b/src/main/resources/assets/neoforge/lang/de_de.json index 4e005889f3..7792a3f15c 100644 --- a/src/main/resources/assets/neoforge/lang/de_de.json +++ b/src/main/resources/assets/neoforge/lang/de_de.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "Die angegebene Dimension-ID (%1$s) ist ungültig.", "commands.neoforge.setdim.invalid.nochange": "Die ausgewählte Entität (%1$s) ist bereits in der angegebenen Dimension (%2$s).", "commands.neoforge.setdim.deprecated": "Dieser Befehl ist veraltet und wird in 1.17 entfernt, verwende stattdessen %s.", - "commands.neoforge.tps.invalid": "Ungültige Dimension %1$s Mögliche Werte: %2$s", - "commands.neoforge.tps.summary.all": "Insgesamt: Mittlere Tickdauer: %1$s ms. Mittlere TPS: %2$s", + "commands.neoforge.tps.overall": "Insgesamt: %s TPS (%s ms/Tick)", + "commands.neoforge.tps.tooltip": "Mittlere TPS; höher ist besser. Ziel-TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/Tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimensionstyp: %s)", "commands.neoforge.mods.list": "Modliste: %1$s", - "commands.neoforge.tps.summary.basic": "Dimension %1$s: Mittlere Tickdauer: %2$s ms. Mittlere TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dimension %1$s (%2$s): Mittlere Tickdauer: %3$s ms. Mittlere TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Entitäts-Tracking für %d Sekunden aktiviert.", "commands.neoforge.tracking.entity.reset": "Entitäts-Timing-Daten wurden gelöscht!", "commands.neoforge.tracking.invalid": "Ungültige Tracking-Daten.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Die Zeit in %s vergeht normal (20 Minuten pro Tag).", "commands.neoforge.timespeed.set": "Die Zeit in %s vergeht jetzt %sx so schnell wie üblich (%s Minuten pro Tag).", "commands.neoforge.timespeed.set.default": "Die Zeit in %s vergeht jetzt normal (20 Minuten pro Tag).", + "commands.neoforge.data_components.list.error.held_stack_empty": "Du hältst kein Item", + "commands.neoforge.data_components.list.title": "Datenkomponenten auf %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Komponente %s enthält den Standardwert", + "commands.neoforge.data_components.list.tooltip.deleted": "Komponente %s mit Wert %s wurde gelöscht", + "commands.neoforge.data_components.list.tooltip.modified": "Komponente %s wurde von %s auf %s geändert", + "commands.neoforge.data_components.list.tooltip.added": "Komponente %s wurde mit dem Wert %s hinzugefügt", "commands.config.getwithtype": "Konfiguration für %s vom Typ %s gefunden bei %s", "commands.config.noconfig": "Konfiguration für %s vom Typ %s nicht gefunden", "neoforge.update.beta.1": "%sWARNUNG: %sNeoForge Beta", @@ -122,59 +130,23 @@ "neoforge.update.newversion": "Neue NeoForge-Version verfügbar: %s", "neoforge.menu.updatescreen.title": "Mod Update", "neoforge.configuration.uitext.title": "%s Einstellungen", - "neoforge.configuration.uitext.type.client": "Clienteinstellungen", - "neoforge.configuration.uitext.type.server": "Servereinstellungen", + "neoforge.configuration.uitext.type.client": "Client Einstellungen", + "neoforge.configuration.uitext.type.server": "Server Einstellungen", "neoforge.configuration.uitext.type.common": "Gemeinsame Einstellungen", - "neoforge.configuration.uitext.type.startup": "Starteinstellungen", - "neoforge.configuration.uitext.title.client": "%s Clienteinstellungen", - "neoforge.configuration.uitext.title.server": "%s Servereinstellungen", - "neoforge.configuration.uitext.title.common": "%s Gemeinsame Einstellungen", + "neoforge.configuration.uitext.type.startup": "Start Einstellungen", + "neoforge.configuration.uitext.title.client": "%s Client Konfiguration", + "neoforge.configuration.uitext.title.server": "%s Server Konfiguration", + "neoforge.configuration.uitext.title.common": "%s allgemeine Konfiguration", "neoforge.configuration.uitext.title.startup": "%s Starteinstellungen", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Diese Einstellungen werden vom Server übernommen und können nicht geändert werden während Du online bist.", - "color": "rot" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Diese Einstellungen können nicht geändert werden, während du dein Spiel für andere im LAN geöffnet hast. Bitte kehre ins Hauptmenü zurück und lade den Spielstand erneut.", - "color": "rot" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Diese Einstellungen sind nur verfügbar, wenn du dich in einer Welt befindest.", - "color": "rot" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "Diese Einstellungen können nicht in der Benutzeroberfläche bearbeitet werden. Kontaktiere die/den Autor:Innen des/der Mod(s) und bitte ihn/sie ein angepasstes Bedienelement zu implementieren.", - "color": "rot" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "Dieser Wert ist zu lang, um hier bearbeitet werden zu können. Bitte bearbeite ihn in der Konfigurationsdatei.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Diese Einstellungen werden vom Server übernommen und können nicht geändert werden während Du online bist.", + "neoforge.configuration.uitext.notlan": "Diese Einstellungen können nicht geändert werden während Du Dein Spiel für andere geöffnet hast. Bitte kehre ins Hauptmenü zurück und lade den Spielstand erneut.", + "neoforge.configuration.uitext.notloaded": "Diese Einstellungen sind nur verfügbar, wenn du dich in einer Welt befindest.", + "neoforge.configuration.uitext.unsupportedelement": "Diese Einstellungen können nicht in der Benutzeroberfläche bearbeitet werden. Kontaktiere die/den Autor:Innen des/der Mod(s) und bitte ihn/sie ein angepasstes Bedienelement zu implementieren.", + "neoforge.configuration.uitext.longstring": "Dieser Wert ist zu lang, um hier bearbeitet werden zu können. Bitte bearbeite ihn in der Konfigurationsdatei.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Bearbeiten", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "Gold", - "bold": true - }, - { - "index": 0 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Rückgängig", "neoforge.configuration.uitext.undo.tooltip": "Änderungen werden nur auf diesem Bildschirm rückgängig gemacht.", @@ -184,47 +156,19 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nWertebereich: ", - "color": "grau" - }, - { - "index": 0, - "color": "grau" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "Datei: \"", - "color": "grau" - }, - { - "index": 0, - "color": "grau" - }, - { - "text": "\"", - "color": "grau" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Wertebereich: %s", + "neoforge.configuration.uitext.filenametooltip": "Datei: \"%s\"", "neoforge.configuration.uitext.common": "Gemeinsame Einstellungen", "neoforge.configuration.uitext.client": "Clienteinstellungen", "neoforge.configuration.uitext.server": "Servereinstellungen", "neoforge.configuration.uitext.startup": "Starteinstellungen", "neoforge.configuration.uitext.restart.game.title": "Minecraft muss neu gestartet werden", - "neoforge.configuration.uitext.restart.game.text": "Eine oder mehrere der geänderten Einstellungen sind nur wirksam, wenn das Spiel gestartet wird.", - "neoforge.configuration.uitext.restart.server.title": "Spielstand muss neu geladen werden", + "neoforge.configuration.uitext.restart.game.text": "Eine oder mehrere der geänderten Einstellungen sind nur wirksam, wenn das Spiel neu-gestartet wird.", + "neoforge.configuration.uitext.restart.server.title": "Welt muss neu geladen werden", "neoforge.configuration.uitext.restart.server.text": "Eine oder mehrere der geänderten Einstellungen sind nur wirksam, wenn die Welt neu geladen wird.", "neoforge.configuration.uitext.restart.return": "Ignorieren", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Deine Änderungen haben keine Wirkung, bis das Spiel neu gestartet wird!", - "color": "red", - "bold": true - } - ], - "neoforge.configuration.title": "NeoForge-Konfiguration", + "neoforge.configuration.uitext.restart.return.tooltip": "Deine Änderungen haben keine Wirkung, bis das Spiel neu gestartet wird!", + "neoforge.configuration.title": "NeoForge Konfiguration", "neoforge.configuration.section.neoforge.client.toml": "Client-Einstellungen", "neoforge.configuration.section.neoforge.client.toml.title": "Client-Einstellungen", "neoforge.configuration.section.neoforge.common.toml": "Gemeinsame Einstellungen", @@ -237,32 +181,20 @@ "neoforge.configgui.forgeLightPipelineEnabled.tooltip": "Aktiviert die NeoForge Block-Darstellungs-Pipeline - korrigiert die Beleuchtung von benutzerdefinierten Modellen.", "neoforge.configgui.fullBoundingBoxLadders": "Leitern im gesamten Kollisionsbereich", "neoforge.configgui.fullBoundingBoxLadders.tooltip": "Ändere dies zu 'true', um den gesamten Kollisionsbereich einer Entität, anstatt nur den Block, in dem sie sich befindet, auf Leitern zu überprüfen. Verursacht merkliche Unterschiede in der Spielmechanik, daher ist die Standardeinstellung die Vanilla-Funktionsweise. Standardwert: 'false'.", - "neoforge.configgui.logLegacyTagWarnings": "Veraltete Tags melden", - "neoforge.configgui.logLegacyTagWarnings.tooltip": "Eine Konfiguration, die hauptsächlich für Entwickler gedacht ist. Meldet Tags von Mods im Log, die den 'forge'-Namensraum verwenden, wenn man der integrierte Server verwendet. Standard ist DEV_SHORT.", - "neoforge.configgui.logUntranslatedConfigurationWarnings": "Unübersetzte Konfigurationstexte melden", + "neoforge.configgui.logLegacyTagWarnings": "Veraltete Tags protokollieren", + "neoforge.configgui.logLegacyTagWarnings.tooltip": "Eine Konfigurationsoption hauptsächlich für Entwickler. Protokolliert Tags von Modifikationen, die den 'forge'-Namensraum verwenden, wenn sie auf einem integrierten Server ausgeführt werden. Standard ist DEV_SHORT.", + "neoforge.configgui.logUntranslatedConfigurationWarnings": "Nicht übersetzte Konfigurationsschlüssel protokollieren", "neoforge.configgui.logUntranslatedConfigurationWarnings.tooltip": "Eine Konfiguration, die hauptsächlich für Entwickler gedacht ist. Meldet Konfigurationswerte im Log, die keine Übersetzung haben, wenn man den Client in einer Entwicklungsumgebung verwendet.", - "neoforge.configgui.logUntranslatedItemTagWarnings": "Unübersetzte Item-Tags melden", + "neoforge.configgui.logUntranslatedItemTagWarnings": "Nicht übersetzte Item-Tags protokollieren", "neoforge.configgui.logUntranslatedItemTagWarnings.tooltip": "Eine Konfiguration, die hauptsächlich für Entwickler gedacht ist. Meldet Item-Tags von Mods im Log, die keine Übersetzungen haben, wenn man den integrierten Server verwendet. Das gewünschte Format ist tag.item.. für den Übersetzungsschlüssel. Standard ist SILENCED.", "neoforge.configgui.permissionHandler": "Berechtigungsverwalter", "neoforge.configgui.permissionHandler.tooltip": "Der vom Server verwendete Berechtigungsverwalter. Standard ist neoforge:default_handler, wenn kein Handler mit diesem Namen registriert wurde.", "neoforge.configgui.removeErroringBlockEntities": "Fehlerhafte Block-Entitäten entfernen", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Aktiviere diese Option, um alle Entitäten mit Fehlern in ihrer Update-Methode zu entfernen, anstatt den Server zu schließen und einen Absturzbericht zu erstellen.\n\n", - { - "text": "SEI GEWARNT: DIES KANN ALLES BESCHÄDIGEN. SPARSAM VERWENDEN. WIR SIND NICHT FÜR SCHÄDEN VERANTWORTLICH.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Aktiviere diese Option, um alle Block-Entitäten mit Fehlern in ihrer Update-Methode zu entfernen, anstatt den Server zu schließen und einen Absturzbericht zu erstellen.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "SEI GEWARNT: DIES KANN ALLES BESCHÄDIGEN. SPARSAM VERWENDEN. WIR SIND NICHT FÜR SCHÄDEN VERANTWORTLICH.", "neoforge.configgui.removeErroringEntities": "Fehlerhafte Entitäten entfernen", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Aktiviere diese Option, um alle Block-Entitäten mit Fehlern in ihrer Update-Methode zu entfernen, anstatt den Server zu schließen und einen Absturzbericht zu erstellen.\n\n", - { - "text": "SEI GEWARNT: DIES KANN ALLES BESCHÄDIGEN. SPARSAM VERWENDEN. WIR SIND NICHT FÜR SCHÄDEN VERANTWORTLICH.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Aktiviere diese Option, um alle Entitäten mit Fehlern in ihrer Update-Methode zu entfernen, anstatt den Server zu schließen und einen Absturzbericht zu erstellen.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "SEI GEWARNT: DIES KANN ALLES BESCHÄDIGEN. SPARSAM VERWENDEN. WIR SIND NICHT FÜR SCHÄDEN VERANTWORTLICH.", "neoforge.configgui.showLoadWarnings": "Ladewarnungen anzeigen", "neoforge.configgui.showLoadWarnings.tooltip": "Wenn aktiviert, zeigt NeoForge alle Warnungen an, die beim Laden aufgetreten sind.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Kombinierten DEPTH_STENCIL-Aufsatz verwenden", diff --git a/src/main/resources/assets/neoforge/lang/en_gb.json b/src/main/resources/assets/neoforge/lang/en_gb.json index fef46ba376..7797dbc97d 100644 --- a/src/main/resources/assets/neoforge/lang/en_gb.json +++ b/src/main/resources/assets/neoforge/lang/en_gb.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "This command is deprecated for removal in 1.17, use %s instead.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Entity tracking enabled for %d seconds.", "commands.neoforge.tracking.entity.reset": "Entity timings data has been cleared!", "commands.neoforge.tracking.invalid": "Invalid tracking data.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Config for %s of type %s found at %s", "commands.config.noconfig": "Config for %s of type %s not found", "neoforge.update.beta.1": "%sWARNING: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Remove Erroring Block Entities", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Remove Erroring Entities", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Show Load Warnings", "neoforge.configgui.showLoadWarnings.tooltip": "When enabled, NeoForge will show any warnings that occurred during loading.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/en_us.json b/src/main/resources/assets/neoforge/lang/en_us.json index 46e4288763..484a2b29f3 100644 --- a/src/main/resources/assets/neoforge/lang/en_us.json +++ b/src/main/resources/assets/neoforge/lang/en_us.json @@ -80,11 +80,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "This command is deprecated for removal in 1.17, use %s instead.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Entity tracking enabled for %d seconds.", "commands.neoforge.tracking.entity.reset": "Entity timings data has been cleared!", "commands.neoforge.tracking.invalid": "Invalid tracking data.", @@ -147,51 +147,15 @@ "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -201,30 +165,8 @@ "neoforge.configuration.uitext.listelementup": "\u23f6", "neoforge.configuration.uitext.listelementdown": "\u23f7", "neoforge.configuration.uitext.listelementremove": "\u274c", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -234,13 +176,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", @@ -264,23 +200,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Remove Erroring Block Entities", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Remove Erroring Entities", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Show Load Warnings", "neoforge.configgui.showLoadWarnings.tooltip": "When enabled, NeoForge will show any warnings that occurred during loading.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", @@ -339,5 +263,20 @@ "neoforge.network.extensible_enums.no_vanilla_server": "This client does not support vanilla servers as it has extended enums used in serverbound networking", "neoforge.network.extensible_enums.enum_set_mismatch": "The set of extensible enums on the client and server do not match. Make sure you are using the same NeoForge version as the server", - "neoforge.network.extensible_enums.enum_entry_mismatch": "The set of values added to extensible enums on the client and server do not match. Make sure you are using the same mod and NeoForge versions as the server. See the log for more details" + "neoforge.network.extensible_enums.enum_entry_mismatch": "The set of values added to extensible enums on the client and server do not match. Make sure you are using the same mod and NeoForge versions as the server. See the log for more details", + + "neoforge.attribute.debug.base": "[Entity: %s | Item: %s]", + + "neoforge.value.flat": "%s", + "neoforge.value.percent": "%s%%", + + "neoforge.value.boolean.enabled": "Enabled", + "neoforge.value.boolean.disabled": "Disabled", + "neoforge.value.boolean.enable": "Enables", + "neoforge.value.boolean.disable": "Disables", + "neoforge.value.boolean.invalid": "Invalid", + + "neoforge.modifier.plus": "+%s %s", + "neoforge.modifier.take": "%s %s", + "neoforge.modifier.bool": "%s %s" } diff --git a/src/main/resources/assets/neoforge/lang/eo_uy.json b/src/main/resources/assets/neoforge/lang/eo_uy.json index 63165fcb18..cb1667bac3 100644 --- a/src/main/resources/assets/neoforge/lang/eo_uy.json +++ b/src/main/resources/assets/neoforge/lang/eo_uy.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "This command is deprecated for removal in 1.17, use %s instead.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Entity tracking enabled for %d seconds.", "commands.neoforge.tracking.entity.reset": "Entity timings data has been cleared!", "commands.neoforge.tracking.invalid": "Invalid tracking data.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Config for %s of type %s found at %s", "commands.config.noconfig": "Config for %s of type %s not found", "neoforge.update.beta.1": "%sWARNING: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Remove Erroring Block Entities", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Remove Erroring Entities", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Show Load Warnings", "neoforge.configgui.showLoadWarnings.tooltip": "When enabled, NeoForge will show any warnings that occurred during loading.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/es_es.json b/src/main/resources/assets/neoforge/lang/es_es.json index d23a28c119..93be1b1bcc 100644 --- a/src/main/resources/assets/neoforge/lang/es_es.json +++ b/src/main/resources/assets/neoforge/lang/es_es.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "Este comando está obsoleto para su eliminación en 1.17, utilice %s en su lugar", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Seguimiento de entidad habilitado durante %d segundos.", "commands.neoforge.tracking.entity.reset": "Se ha borrado la información de tiempos de entidad.", "commands.neoforge.tracking.invalid": "Datos de seguimiento no válidos.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Configuración para %s de tipo %s encontrada en %s", "commands.config.noconfig": "Configuración para %s de tipo %s no encontrada", "neoforge.update.beta.1": "%sADVERTENCIA: %sVersión Beta de NeoForge", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Eliminar entidades de bloque con errores", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Eliminar entidades con errores", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Mostrar advertencias de carga", "neoforge.configgui.showLoadWarnings.tooltip": "Cuando está habilitado, NeoForge mostrará cualquier advertencia que haya ocurrido durante la carga.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/et_ee.json b/src/main/resources/assets/neoforge/lang/et_ee.json index ad9498f46c..22c875870e 100644 --- a/src/main/resources/assets/neoforge/lang/et_ee.json +++ b/src/main/resources/assets/neoforge/lang/et_ee.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "See käsklus on iganenud ning eemaldatakse 1.17-s, kasuta selle asemel %s.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Olemi jälitamine %d sekundiks lubatud.", "commands.neoforge.tracking.entity.reset": "Olemite aegade andmed on tühjendatud!", "commands.neoforge.tracking.invalid": "Sobimatud jälgimisandmed.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Seadistus %s jaoks tüübiga %s leiti asukohast %s", "commands.config.noconfig": "Seadistust %s jaoks tüübiga %s ei leitud", "neoforge.update.beta.1": "%sHOIATUS: %sNeoForge beeta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Eemalda vigu põhjustavad plokiolemid", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Eemalda vigu põhjustavad olemid", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Kuva laadimishoiatused", "neoforge.configgui.showLoadWarnings.tooltip": "Lubamisel kuvab NeoForge mistahes hoiatusi, mis esinesid laadimise käigus.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/fr_fr.json b/src/main/resources/assets/neoforge/lang/fr_fr.json index c6feef0557..984e6149b2 100644 --- a/src/main/resources/assets/neoforge/lang/fr_fr.json +++ b/src/main/resources/assets/neoforge/lang/fr_fr.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "Cette commande est obsolète pour la suppression en 1.17, veuillez utiliser %s à la place.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Suivi des entités activé pour %d secondes.", "commands.neoforge.tracking.entity.reset": "Les données de timings de l'entité ont été effacées !", "commands.neoforge.tracking.invalid": "Données de suivi invalides.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Configuration pour %s de type %s trouvée dans %s", "commands.config.noconfig": "La configuration pour %s du type %s est introuvable", "neoforge.update.beta.1": "%sATTENTION: %sNeoForge Bêta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Supprimer les Block Entities en erreur", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Supprimer les entités erronées", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Afficher les avertissements lors du chargement", "neoforge.configgui.showLoadWarnings.tooltip": "Lorsque cette option est activée, NeoForge affichera tous les avertissements qui se sont produits pendant le chargement.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/hu_hu.json b/src/main/resources/assets/neoforge/lang/hu_hu.json index c9195292a6..ec7866274c 100644 --- a/src/main/resources/assets/neoforge/lang/hu_hu.json +++ b/src/main/resources/assets/neoforge/lang/hu_hu.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "This command is deprecated for removal in 1.17, use %s instead.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Entity tracking enabled for %d seconds.", "commands.neoforge.tracking.entity.reset": "Entity timings data has been cleared!", "commands.neoforge.tracking.invalid": "Invalid tracking data.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Config for %s of type %s found at %s", "commands.config.noconfig": "Config for %s of type %s not found", "neoforge.update.beta.1": "%sWARNING: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Remove Erroring Block Entities", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Remove Erroring Entities", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Show Load Warnings", "neoforge.configgui.showLoadWarnings.tooltip": "When enabled, NeoForge will show any warnings that occurred during loading.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/it_it.json b/src/main/resources/assets/neoforge/lang/it_it.json index db7ebdd5da..1747ce6a2c 100644 --- a/src/main/resources/assets/neoforge/lang/it_it.json +++ b/src/main/resources/assets/neoforge/lang/it_it.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "Questo comando sarà rimosso in 1.17, utilizzare invece %s.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Monitoraggio entità abilitato per %d secondi.", "commands.neoforge.tracking.entity.reset": "I dati dei tempi delle entità sono stati cancellati!", "commands.neoforge.tracking.invalid": "Dati di tracciamento non validi.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Configurazione per %s di tipo %s trovata in %s", "commands.config.noconfig": "Configurazione per %s di tipo %s non trovata", "neoforge.update.beta.1": "%sATTENZIONE: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Rimuovi Entità Blocco in Errore", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Rimuovi Entità in Errore", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Mostra Avvisi del Caricamento", "neoforge.configgui.showLoadWarnings.tooltip": "Se abilitata, NeoForge mostrerà tutti gli avvisi che si sono verificati durante il caricamento.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/ja_jp.json b/src/main/resources/assets/neoforge/lang/ja_jp.json index 6c9928ce1c..73ad50928d 100644 --- a/src/main/resources/assets/neoforge/lang/ja_jp.json +++ b/src/main/resources/assets/neoforge/lang/ja_jp.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "指定したディメンションID(%1$s)は有効ではありません", "commands.neoforge.setdim.invalid.nochange": "選択したエンティティ(%1$s)は、指定したディメンション(%2$s)内に既に存在します", "commands.neoforge.setdim.deprecated": "このコマンドは非推奨であり、1.17で削除されます。代わりに%sを使用してください", - "commands.neoforge.tps.invalid": "ディメンション%1$sは有効ではありません。次の値が使用できます:%2$s", - "commands.neoforge.tps.summary.all": "全体:1ティックあたりの時間:%1$s ms、1秒あたりのティック数(TPS):%2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod一覧:%1$s", - "commands.neoforge.tps.summary.basic": "ディメンション%1$s:1ティックあたりの時間:%2$s ms、1秒あたりのティック数(TPS):%3$s", - "commands.neoforge.tps.summary.named": "ディメンション%1$s(%2$s):1ティックあたりの時間:%3$s ms、1秒あたりのティック数(TPS):%4$s", "commands.neoforge.tracking.entity.enabled": "エンティティのトラッキングを%d秒間有効にしました", "commands.neoforge.tracking.entity.reset": "エンティティのタイミングデータを消去しました", "commands.neoforge.tracking.invalid": "トラッキングデータが有効ではありません", @@ -108,13 +108,21 @@ "commands.neoforge.chunkgen.success": "生成が完了しました", "commands.neoforge.chunkgen.error": "%1$s個のエラーが発生しました。詳細な情報はログを確認してください", "commands.neoforge.chunkgen.stopped": "Generation stopped! %1$s out of %2$s chunks generated. (%3$s%%)", - "commands.neoforge.chunkgen.status": "Generation status! %1$s out of %2$s chunks generated. (%3$s%%)", + "commands.neoforge.chunkgen.status": "生成ステータス! %1$s / %2$s チャンクが生成されました。 (%3$s%%)", "commands.neoforge.chunkgen.not_running": "事前生成は実行されていません。生成を開始するためのコマンドを確認するには「/neoforge generate help」を実行してください", "commands.neoforge.chunkgen.help_line": "§2/neoforge generate start [progressBar] §r§f- 指定の位置を中心として、各辺がchunkRadius * 2の正方形で生成します。\n§2/neoforge generate stop §r§f- 現在の生成を停止し、完了した進行状況を表示します。\n§2/neoforge generate status §r- 現在実行中の生成に対する完了した進行状況を表示します。\n§2/neoforge generate help §r- このメッセージを表示します。\nヒント:サーバーコンソールから実行する場合は、/execute in neoforge generate...を使用することで、異なるディメンションで生成を実行できます。", "commands.neoforge.timespeed.query": "Time in %s flows at a rate of %sx (%s minutes per day).", "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "%s(種類:%s)の設定が%sで見つかりました", "commands.config.noconfig": "%s(種類:%s)の設定が見つかりません", "neoforge.update.beta.1": "%s警告:%sNeoForge ベータ版", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "エラーを発するブロックエンティティの除去", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "エラーを発するエンティティの除去", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "読み込み時の警告の表示", "neoforge.configgui.showLoadWarnings.tooltip": "有効にすると、読み込み中に発生した警告が表示されるようになります。", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/ko_kr.json b/src/main/resources/assets/neoforge/lang/ko_kr.json index e3492e0eab..c04de76122 100644 --- a/src/main/resources/assets/neoforge/lang/ko_kr.json +++ b/src/main/resources/assets/neoforge/lang/ko_kr.json @@ -36,7 +36,7 @@ "fml.menu.multiplayer.modsincompatible": "호환되지 않는 서버 모드 목록", "fml.menu.multiplayer.networkincompatible": "서버의 네트워크 메시지들이 호환되지 않음", "fml.menu.multiplayer.missingdatapackregistries": "필요한 데이터팩 레지스트리가 누락됨: %1$s", - "fml.menu.branding": "%s (%s mods)", + "fml.menu.branding": "%s (%s 모드)", "fml.menu.notification.title": "시작 알림", "fml.menu.accessdenied.title": "서버 접속이 거부되었습니다", "fml.menu.accessdenied.message": "Fancy Mod Loader가 서버에 접속할 수 없습니다.\n이 서버(%1$s)는 모드가 설치된 클라이언트의 접속을 거부합니다.", @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "'%1$s'은(는) 잘못된 차원입니다.", "commands.neoforge.setdim.invalid.nochange": "해당 엔티티('%1$s')은(는) 이미 지정된 차원('%2$s')에 있습니다.", "commands.neoforge.setdim.deprecated": "이 명령어는 1.17에서 제거될 예정입니다. %s을(를) 대신 사용하세요.", - "commands.neoforge.tps.invalid": "'%1$s'은(는) 잘못된 차원입니다. 올바른 차원들: %2$s", - "commands.neoforge.tps.summary.all": "총합: 평균 틱 처리 시간: %1$s ms. 평균 TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "모드 목록: %1$s", - "commands.neoforge.tps.summary.basic": "차원 %1$s: 평균 틱 처리 시간: %2$s ms. 평균 TPS: %3$s", - "commands.neoforge.tps.summary.named": "차원 %1$s (%2$s): 평균 틱 처리 시간: %3$s ms. 평균 TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "엔티티 처리 시간을 %d초간 수집합니다...", "commands.neoforge.tracking.entity.reset": "엔티티 처리 시간 정보를 삭제합니다!", "commands.neoforge.tracking.invalid": "처리 시간 정보가 손상되었습니다.", @@ -107,14 +107,22 @@ "commands.neoforge.chunkgen.started": "%2$s×%3$s 청크 (%4$s×%5$s 블록) 범위 안에 청크 %1$s개 생성 중.", "commands.neoforge.chunkgen.success": "생성 완료!", "commands.neoforge.chunkgen.error": "청크 생성 중 %1$s개의 오류가 발생했습니다! 출력 로그에서 자세한 내용을 확인하세요.", - "commands.neoforge.chunkgen.stopped": "Generation stopped! %1$s out of %2$s chunks generated. (%3$s%%)", - "commands.neoforge.chunkgen.status": "Generation status! %1$s out of %2$s chunks generated. (%3$s%%)", + "commands.neoforge.chunkgen.stopped": "청크 생성 중단됨! %1$s/%2$s개의 청크를 생성했습니다. (%3$s%%)", + "commands.neoforge.chunkgen.status": "청크 생성 진행률! %1$s/%2$s개의 청크를 생성했습니다. (%3$s%%)", "commands.neoforge.chunkgen.not_running": "현재 청크를 생성하고 있지 않습니다. `/neoforge generate help`를 참고하여 청크 사전 생성 명령어 사용 방법을 확인하세요.", "commands.neoforge.chunkgen.help_line": "§2/neoforge generate start <범위> [진행률 표시] §r§f- 주어진 위치를 중심으로 범위 * 2 길이의 정사각형 구역 내 청크를 생성합니다.\n§2/neoforge generate stop §r§f- 진행 중인 청크 사전 생성을 중단하고 진행률을 표시합니다.\n§2/neoforge generate status §r- 이미 진행 중인 청크 생성 작업의 진행률을 표시합니다.\n§2/neoforge generate help §r- 이 도움말을 표시합니다.\n팁: 다른 차원의 청크를 사전 생성할 땐 '/execute in <차원> neoforge generate...' 식으로 다른 차원에서 명령을 실행하세요.", "commands.neoforge.timespeed.query": "Time in %s flows at a rate of %sx (%s minutes per day).", "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "모드 %s의 설정 %s이(가) %s에서 발견됨", "commands.config.noconfig": "모드 %s의 설정 %s을(를) 찾을 수 없음", "neoforge.update.beta.1": "%s경고: %s 네오 포지 베타 버전입니다", @@ -122,108 +130,44 @@ "neoforge.update.newversion": "새로운 네오 포지 버전으로 업데이트할 수 있습니다: %s", "neoforge.menu.updatescreen.title": "모드 업데이트", "neoforge.configuration.uitext.title": "%s Configuration", - "neoforge.configuration.uitext.type.client": "Client Settings", - "neoforge.configuration.uitext.type.server": "Server Settings", - "neoforge.configuration.uitext.type.common": "Common settings", - "neoforge.configuration.uitext.type.startup": "Startup settings", + "neoforge.configuration.uitext.type.client": "클라이언트 설정", + "neoforge.configuration.uitext.type.server": "서버 설정", + "neoforge.configuration.uitext.type.common": "공통 설정", + "neoforge.configuration.uitext.type.startup": "시작 설정", "neoforge.configuration.uitext.title.client": "%s Client Configuration", "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", - "neoforge.configuration.uitext.undo": "Undo", - "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", - "neoforge.configuration.uitext.reset": "Reset", - "neoforge.configuration.uitext.reset.tooltip": "Reverts everything on this screen to its default value.", + "neoforge.configuration.uitext.undo": "되돌리기", + "neoforge.configuration.uitext.undo.tooltip": "이 화면에서만 변경사항을 되돌립니다.", + "neoforge.configuration.uitext.reset": "초기화", + "neoforge.configuration.uitext.reset.tooltip": "이 화면에 있는 모든 것을 기본 값으로 되돌립니다.", "neoforge.configuration.uitext.newlistelement": "+", "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], - "neoforge.configuration.uitext.common": "Common Options", - "neoforge.configuration.uitext.client": "Client Options", - "neoforge.configuration.uitext.server": "Server Options", - "neoforge.configuration.uitext.startup": "Startup Options", - "neoforge.configuration.uitext.restart.game.title": "Minecraft needs to be restarted", + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", + "neoforge.configuration.uitext.common": "공통 옵션", + "neoforge.configuration.uitext.client": "클라이언트 옵션", + "neoforge.configuration.uitext.server": "서버 옵션", + "neoforge.configuration.uitext.startup": "시작 옵션", + "neoforge.configuration.uitext.restart.game.title": "마인크래프트를 다시 시작해야 합니다", "neoforge.configuration.uitext.restart.game.text": "One or more of the configuration option that were changed will only take effect when the game is started.", "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "오류가 발생한 블록 엔티티 제거", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "오류가 나는 엔티티 제거", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "게임을 불러오는 중 발생한 경고 표시", "neoforge.configgui.showLoadWarnings.tooltip": "네오 포지가 게임을 불러오며 발생한 모든 경고 메세지들을 표시합니다.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/ms_my.json b/src/main/resources/assets/neoforge/lang/ms_my.json new file mode 100644 index 0000000000..3f44f98fd2 --- /dev/null +++ b/src/main/resources/assets/neoforge/lang/ms_my.json @@ -0,0 +1,247 @@ +{ + "fml.menu.mods": "Mod", + "fml.menu.mods.title": "Mod", + "fml.menu.mods.normal": "Tutup", + "fml.menu.mods.search": "Cari", + "fml.menu.mods.a_to_z": "A-Z", + "fml.menu.mods.z_to_a": "Z-A", + "fml.menu.mods.config": "Konfigurasi", + "fml.menu.mods.openmodsfolder": "Open mods folder", + "fml.menu.modoptions": "Mod Options...", + "fml.menu.mods.info.version": "Version: %1$s", + "fml.menu.mods.info.idstate": "ModID: %1$s State: {1,lower}", + "fml.menu.mods.info.credits": "Credits: %1$s", + "fml.menu.mods.info.authors": "Authors: %1$s", + "fml.menu.mods.info.displayurl": "Homepage: %1$s", + "fml.menu.mods.info.license": "License: %1$s", + "fml.menu.mods.info.securejardisabled": "Secure mod features disabled, update JDK", + "fml.menu.mods.info.signature": "Signature: %1$s", + "fml.menu.mods.info.signature.unsigned": "TIDAK DITANDA", + "fml.menu.mods.info.trust": "Trust: %1$s", + "fml.menu.mods.info.trust.noauthority": "Tiada", + "fml.menu.mods.info.nochildmods": "No child mods found", + "fml.menu.mods.info.childmods": "Child mods: %1$s", + "fml.menu.mods.info.updateavailable": "Update available: %1$s", + "fml.menu.mods.info.changelogheader": "Log perubahan:", + "fml.menu.multiplayer.compatible": "Compatible FML modded server\n{0,choice,1#1 mod|1<%1$s mods} present", + "fml.menu.multiplayer.incompatible": "Incompatible FML modded server", + "fml.menu.multiplayer.incompatible.extra": "Incompatible FML modded server\n%1$s", + "fml.menu.multiplayer.truncated": "Data may be inaccurate due to protocol size limits.", + "fml.menu.multiplayer.vanilla": "Vanilla server", + "fml.menu.multiplayer.vanilla.incompatible": "Incompatible Vanilla server", + "fml.menu.multiplayer.unknown": "Unknown server %1$s", + "fml.menu.multiplayer.serveroutdated": "NeoForge server network version is outdated", + "fml.menu.multiplayer.clientoutdated": "NeoForge client network version is outdated", + "fml.menu.multiplayer.extraservermods": "Server has additional mods that may be needed on the client", + "fml.menu.multiplayer.modsincompatible": "Server mod list is not compatible", + "fml.menu.multiplayer.networkincompatible": "Server network message list is not compatible", + "fml.menu.multiplayer.missingdatapackregistries": "Missing required datapack registries: %1$s", + "fml.menu.branding": "%s (%s mod)", + "fml.menu.notification.title": "Startup Notification", + "fml.menu.accessdenied.title": "Server Access Denied", + "fml.menu.accessdenied.message": "Fancy Mod Loader could not connect to this server\nThe server %1$s has forbidden modded access", + "fml.menu.backupfailed.title": "Backup Failed", + "fml.menu.backupfailed.message": "There was an error saving the archive %1$s\nPlease fix the problem and try again", + "fml.button.open.file": "Buka %1$s", + "fml.button.open.log": "Open log file", + "fml.button.open.crashreport": "Open crash report", + "fml.button.open.mods.folder": "Open Mods Folder", + "fml.button.continue.launch": "Proceed to main menu", + "fml.modmismatchscreen.missingmods.client": "Your client is missing the following mods, install these mods to join this server:", + "fml.modmismatchscreen.missingmods.server": "The server is missing the following mods, remove these mods from your client to join this server:", + "fml.modmismatchscreen.mismatchedmods": "The following mod versions do not match, install the same version of these mods that the server has to join this server:", + "fml.modmismatchscreen.table.channelname": "Nama saluran", + "fml.modmismatchscreen.table.youneed": "Anda memerlukan", + "fml.modmismatchscreen.table.youhave": "Anda mempunyai", + "fml.modmismatchscreen.table.serverhas": "Pelayan mempunyai", + "fml.modmismatchscreen.additional": "[%1$s additional, see latest.log for the full list]", + "fml.modmismatchscreen.homepage": "Click to get to the homepage of this mod", + "fml.modmismatchscreen.table.reason": "Sebab", + "fml.modmismatchscreen.table.visit.mod_page": "Open the mod page of the mod that registers the channel: %s", + "fml.modmismatchscreen.simplifiedview": "Simplified view", + "fml.resources.modresources": "Resources for %1$s mod files", + "fml.resources.moddata": "Data for %1$s mod files", + "loadwarning.neoforge.prbuild": "This build of NeoForge was created by a community member and is thus §c§lUNSUPPORTED§r", + "commands.neoforge.arguments.enum.invalid": "Enum constant must be one of %1$s, found %2$s", + "commands.neoforge.dimensions.list": "Currently registered dimensions by type:", + "commands.neoforge.dump.success": "New file created with %s registry's contents is at %s", + "commands.neoforge.dump.failure": "Failed to create new file with %s registry's contents at %s", + "commands.neoforge.dump.error.unknown_registry": "Unknown registry '%s'", + "commands.neoforge.entity.list.invalid": "Invalid filter, does not match any entities. Use /neoforge entity list for a proper list", + "commands.neoforge.entity.list.invalidworld": "Could not load world for dimension %1$s. Please select a valid dimension.", + "commands.neoforge.entity.list.none": "No entities found.", + "commands.neoforge.entity.list.single.header": "Entity: %1$s Total: %2$s", + "commands.neoforge.entity.list.multiple.header": "Total: %1$s", + "commands.neoforge.setdim.invalid.entity": "The entity selected (%1$s) is not valid.", + "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", + "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", + "commands.neoforge.setdim.deprecated": "This command is deprecated for removal in 1.17, use %s instead.", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", + "commands.neoforge.mods.list": "Mod List: %1$s", + "commands.neoforge.tracking.entity.enabled": "Entity tracking enabled for %d seconds.", + "commands.neoforge.tracking.entity.reset": "Entity timings data has been cleared!", + "commands.neoforge.tracking.invalid": "Invalid tracking data.", + "commands.neoforge.tracking.be.enabled": "Block Entity tracking enabled for %d seconds.", + "commands.neoforge.tracking.be.reset": "Block entity timings data has been cleared!", + "commands.neoforge.tracking.timing_entry": "%1$s - %2$s [%3$s, %4$s, %5$s]: %6$s", + "commands.neoforge.tracking.no_data": "No data has been recorded yet.", + "commands.neoforge.tags.error.unknown_registry": "Unknown registry '%s'", + "commands.neoforge.tags.error.unknown_tag": "Unknown tag '%s' in registry '%s'", + "commands.neoforge.tags.error.unknown_element": "Unknown element '%s' in registry '%s'", + "commands.neoforge.tags.registry_key": "%s", + "commands.neoforge.tags.tag_count": "Tag: %s", + "commands.neoforge.tags.copy_tag_names": "Click to copy all tag names to clipboard", + "commands.neoforge.tags.element_count": "Elements: %s", + "commands.neoforge.tags.copy_element_names": "Click to copy all element names to clipboard", + "commands.neoforge.tags.tag_key": "%s / %s", + "commands.neoforge.tags.containing_tag_count": "Containing tags: %s", + "commands.neoforge.tags.element": "%s : %s", + "commands.neoforge.tags.page_info": "%s ", + "commands.neoforge.chunkgen.progress_bar_title": "Generating chunks...", + "commands.neoforge.chunkgen.progress_bar_progress": "Generating %1$s chunks - ", + "commands.neoforge.chunkgen.progress_bar_errors": "(%1$s errors!)", + "commands.neoforge.chunkgen.already_running": "Generation already running. Please execute '/neoforge generate stop' first and then you can start a new generation.", + "commands.neoforge.chunkgen.started": "Generating %1$s chunks, in an area of %2$sx%3$s chunks (%4$sx%5$s blocks).", + "commands.neoforge.chunkgen.success": "Generation Done!", + "commands.neoforge.chunkgen.error": "Generation experienced %1$s errors! Check the log for more information.", + "commands.neoforge.chunkgen.stopped": "Penjanaan telah dihentikan! %1$s daripada %2$s cebisan telah dijana. (%3$s%%)", + "commands.neoforge.chunkgen.status": "Status penjanaan! %1$s daripada %2$s cebisan telah dijana. (%3$s%%)", + "commands.neoforge.chunkgen.not_running": "No pregeneration currently running. Run `/neoforge generate help` to see commands for starting generation.", + "commands.neoforge.chunkgen.help_line": "§2/neoforge generate start [progressBar] §r§f- Menghasilkan segi empat sama berpusat pada kedudukan yang diberikan iaitu chunkRadius * 2 pada setiap sisi.\n§2/neoforge generate stop §r§f- Menghentikan generasi semasa dan memaparkan kemajuan yang telah diselesaikannya.\n§2/neoforge generate status §r- Memaparkan kemajuan yang telah selesai untuk penjanaan yang sedang berjalan.\n§2/neoforge generate help §r- Memaparkan mesej ini.\nGeneral tips: Jika dijalankan dari konsol pelayan, anda boleh menjalankan generate dalam dimensi berbeza dengan menggunakan /execute in neoforge generate...", + "commands.neoforge.timespeed.query": "Masa dalam %s sedang mengalir pada kadar %sx (%s minit sehari).", + "commands.neoforge.timespeed.query.default": "Masa dalam %s mengalir seperti biasa (20 minit sehari).", + "commands.neoforge.timespeed.set": "Aliran masa dalam %s ditetapkan kepada %sx (%s minit sehari).", + "commands.neoforge.timespeed.set.default": "Aliran masa dalam %s ditetapkan kepada lalai (20 minit sehari).", + "commands.neoforge.data_components.list.error.held_stack_empty": "Anda tidak memegang sebarang item", + "commands.neoforge.data_components.list.title": "Komponen data pada %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Komponen %s memegang nilai lalainya", + "commands.neoforge.data_components.list.tooltip.deleted": "Komponen %s dengan nilai %s telah dipadamkan", + "commands.neoforge.data_components.list.tooltip.modified": "Komponen %s telah diubah suai daripada %s kepada %s", + "commands.neoforge.data_components.list.tooltip.added": "Komponen %s telah ditambah dengan nilai %s", + "commands.config.getwithtype": "Config for %s of type %s found at %s", + "commands.config.noconfig": "Config for %s of type %s not found", + "neoforge.update.beta.1": "%sWARNING: %sNeoForge Beta", + "neoforge.update.beta.2": "Major issues may arise, verify before reporting.", + "neoforge.update.newversion": "New NeoForge version available: %s", + "neoforge.menu.updatescreen.title": "Kemas Kini Mod", + "neoforge.configuration.uitext.title": "Konfigurasi %s", + "neoforge.configuration.uitext.type.client": "Tetapan Klien", + "neoforge.configuration.uitext.type.server": "Tetapan Pelayan", + "neoforge.configuration.uitext.type.common": "Tetapan biasa", + "neoforge.configuration.uitext.type.startup": "Tetapan permulaan", + "neoforge.configuration.uitext.title.client": "Konfigurasi Klien %s", + "neoforge.configuration.uitext.title.server": "Konfigurasi Pelayan %s", + "neoforge.configuration.uitext.title.common": "Konfigurasi Biasa %s", + "neoforge.configuration.uitext.title.startup": "Konfigurasi Permulaan %s", + "neoforge.configuration.uitext.notonline": "Tetapan di sini ditentukan oleh pelayan dan tidak boleh diubah semasa dalam talian.", + "neoforge.configuration.uitext.notlan": "Tetapan di sini tidak boleh disunting semasa permainan anda dibuka kepada LAN. Sila kembali ke menu utama dan muatkan dunia ini sekali lagi.", + "neoforge.configuration.uitext.notloaded": "Tetapan di sini hanya tersedia semasa dunia dimuatkan.", + "neoforge.configuration.uitext.unsupportedelement": "Nilai ini tidak boleh disunting dalam UI. Sila hubungi pengarang mod tentang menyediakan UI tersuai untuknya.", + "neoforge.configuration.uitext.longstring": "Nilai ini terlalu panjang untuk disunting dalam UI. Sila sunting dalam fail konfigurasi.", + "neoforge.configuration.uitext.section": "%s...", + "neoforge.configuration.uitext.sectiontext": "Sunting", + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", + "neoforge.configuration.uitext.listelement": "%s:", + "neoforge.configuration.uitext.undo": "Buat Asal", + "neoforge.configuration.uitext.undo.tooltip": "Mengembalikan perubahan pada skrin ini sahaja.", + "neoforge.configuration.uitext.reset": "Tetap Semula", + "neoforge.configuration.uitext.reset.tooltip": "Mengembalikan segala-galanya pada skrin ini kepada nilai lalainya.", + "neoforge.configuration.uitext.newlistelement": "+", + "neoforge.configuration.uitext.listelementup": "⏶", + "neoforge.configuration.uitext.listelementdown": "⏷", + "neoforge.configuration.uitext.listelementremove": "❌", + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", + "neoforge.configuration.uitext.common": "Pilihan Biasa", + "neoforge.configuration.uitext.client": "Pilihan Klien", + "neoforge.configuration.uitext.server": "Pilihan Pelayan", + "neoforge.configuration.uitext.startup": "Pilihan Permulaan", + "neoforge.configuration.uitext.restart.game.title": "Minecraft perlu dimulakan semula", + "neoforge.configuration.uitext.restart.game.text": "Satu atau lebih pilihan konfigurasi yang telah diubah hanya akan berkuat kuasa apabila permainan dimulakan.", + "neoforge.configuration.uitext.restart.server.title": "Dunia perlu dimuat semula", + "neoforge.configuration.uitext.restart.server.text": "Satu atau lebih pilihan konfigurasi yang telah diubah hanya akan berkuat kuasa apabila dunia dimuat semula.", + "neoforge.configuration.uitext.restart.return": "Abaikan", + "neoforge.configuration.uitext.restart.return.tooltip": "Perubahan anda tidak akan memberi kesan sehingga anda memulakan semula!", + "neoforge.configuration.title": "Konfigurasi NeoForge", + "neoforge.configuration.section.neoforge.client.toml": "Tetapan klien", + "neoforge.configuration.section.neoforge.client.toml.title": "Tetapan klien", + "neoforge.configuration.section.neoforge.common.toml": "Tetapan biasa", + "neoforge.configuration.section.neoforge.common.toml.title": "Tetapan biasa", + "neoforge.configuration.section.neoforge.server.toml": "Tetapan pelayan", + "neoforge.configuration.section.neoforge.server.toml.title": "Tetapan pelayan", + "neoforge.configgui.advertiseDedicatedServerToLan": "Iklankan Pelayan Khusus Kepada LAN", + "neoforge.configgui.advertiseDedicatedServerToLan.tooltip": "Set this to true to enable advertising the dedicated server to local LAN clients so that it shows up in the Multiplayer screen automatically.", + "neoforge.configgui.forgeLightPipelineEnabled": "Talian Paip Cahaya NeoForge", + "neoforge.configgui.forgeLightPipelineEnabled.tooltip": "Enable the NeoForge block rendering pipeline - fixes the lighting of custom models.", + "neoforge.configgui.fullBoundingBoxLadders": "Full Bounding Box Ladders", + "neoforge.configgui.fullBoundingBoxLadders.tooltip": "Set this to true to check the entire entity's collision bounding box for ladders instead of just the block they are in. Causes noticeable differences in mechanics so default is vanilla behavior. Default: false.", + "neoforge.configgui.logLegacyTagWarnings": "Log Tag Legasi", + "neoforge.configgui.logLegacyTagWarnings.tooltip": "Pilihan konfigurasi terutamanya untuk pembangun. Mengelog keluar tag diubah suai yang menggunakan ruang nama 'forge' apabila dijalankan pada pelayan bersepadu. Dilalaikan kepada DEV_SHORT.", + "neoforge.configgui.logUntranslatedConfigurationWarnings": "Log Kunci Konfigurasi Tidak Diterjemah", + "neoforge.configgui.logUntranslatedConfigurationWarnings.tooltip": "Pilihan konfigurasi terutamanya untuk pembangun. Mengelog keluar nilai konfigurasi yang tidak mempunyai terjemahan semasa menjalankan klien dalam persekitaran pembangunan.", + "neoforge.configgui.logUntranslatedItemTagWarnings": "Log Tag Item Tidak Diterjemah", + "neoforge.configgui.logUntranslatedItemTagWarnings.tooltip": "Pilihan konfigurasi terutamanya untuk pembangun. Mengelog keluar tag item yang diubah suai yang tidak mempunyai terjemahan apabila dijalankan pada pelayan bersepadu. Format yang dikehendaki ialah tag.item.. untuk kunci terjemahan. Dilalaikan kepada SILENCED.", + "neoforge.configgui.permissionHandler": "Pengendali Keizinan", + "neoforge.configgui.permissionHandler.tooltip": "Pengendali keizinan yang digunakan oleh pelayan. Dilalaikan kepada neoforge:default_handler jika tiada pengendali dengan nama itu didaftarkan.", + "neoforge.configgui.removeErroringBlockEntities": "Remove Erroring Block Entities", + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "AMARAN INI BOLEH MEROSAKKAN SEGALANYA.\nGUNAKAN SECARA CERMAT.\nKAMI TIDAK BERTANGGUNGJAWAB ATAS KEROSAKAN.", + "neoforge.configgui.removeErroringEntities": "Remove Erroring Entities", + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "AMARAN INI BOLEH MEROSAKKAN SEGALANYA.\nGUNAKAN SECARA CERMAT.\nKAMI TIDAK BERTANGGUNGJAWAB ATAS KEROSAKAN.", + "neoforge.configgui.showLoadWarnings": "Show Load Warnings", + "neoforge.configgui.showLoadWarnings.tooltip": "When enabled, NeoForge will show any warnings that occurred during loading.", + "neoforge.configgui.useCombinedDepthStencilAttachment": "Gunakan gabungan Lampiran DEPTH_STENCIL", + "neoforge.configgui.useCombinedDepthStencilAttachment.tooltip": "Tetapkan kepada true untuk menggunakan lampiran DEPTH_STENCIL gabungan dan bukannya dua lampiran berasingan.", + "neoforge.controlsgui.shift": "SHIFT + %s", + "neoforge.controlsgui.control": "CTRL + %s", + "neoforge.controlsgui.control.mac": "CMD + %s", + "neoforge.controlsgui.alt": "ALT + %s", + "neoforge.container.enchant.limitedEnchantability": "Limited Enchantability", + "neoforge.swim_speed": "Kelajuan Berenang", + "neoforge.name_tag_distance": "Nametag Render Distance", + "neoforge.creative_flight": "Creative Flight", + "fluid_type.minecraft.milk": "Susu", + "fluid_type.minecraft.flowing_milk": "Susu", + "neoforge.froge.warningScreen.title": "NeoForge snapshots notice", + "neoforge.froge.warningScreen.text": "Froge is not officially supported. Bugs and instability are expected.", + "neoforge.froge.supportWarning": "WARNING: Froge is not supported by NeoForge", + "neoforge.gui.exit": "Keluar", + "neoforge.experimentalsettings.tooltip": "This world uses experimental settings, which could stop working at any time.", + "neoforge.selectWorld.backupWarning.experimental.additional": "This message will not show again for this world.", + "neoforge.chatType.system": "%1$s", + "pack.neoforge.description": "NeoForge data/resource pack", + "pack.neoforge.source.child": "anak", + "neoforge.network.negotiation.failure.mod": "Channel of mod \"%1$s\" failed to connect: %2$s", + "neoforge.network.negotiation.failure.missing.client.server": "This channel is missing on the server side, but required on the client!", + "neoforge.network.negotiation.failure.missing.server.client": "This channel is missing on the client side, but required on the server!", + "neoforge.network.negotiation.failure.flow.client.missing": "The client wants the payload to flow: %s, but the server does not support it!", + "neoforge.network.negotiation.failure.flow.server.missing": "The server wants the payload to flow: %s, but the client does not support it!", + "neoforge.network.negotiation.failure.flow.client.mismatch": "The client wants the payload to flow: %s, but the server wants it to flow: %s!", + "neoforge.network.negotiation.failure.flow.server.mismatch": "The server wants the payload to flow: %s, but the client wants it to flow: %s!", + "neoforge.network.negotiation.failure.version.client.missing": "The client wants the payload to be version: %s, but the server does not support it!", + "neoforge.network.negotiation.failure.version.server.missing": "The server wants the payload to be version: %s, but the client does not support it!", + "neoforge.network.negotiation.failure.version.mismatch": "The client wants the payload to be version: %s, but the server wants it to be version: %s!", + "neoforge.network.invalid_flow": "Failed to process a payload that was send with an invalid flow: %s", + "neoforge.network.negotiation.failure.vanilla.client.not_supported": "You are trying to connect to a server that is running NeoForge, but you are not. Please install NeoForge Version: %s to connect to this server.", + "neoforge.network.negotiation.failure.vanilla.server.not_supported": "You are trying to connect to a server that is not running NeoForge, but you have mods that require it. A connection could not be established.", + "neoforge.network.packet_splitter.unknown": "Tried to split a packet without packet splitter!", + "neoforge.network.advanced_add_entity.failed": "Failed to process advanced entity spawn data: %s", + "neoforge.network.advanced_open_screen.failed": "Failed to open a screen with advanced data: %s", + "neoforge.network.registries.sync.missing": "Not all expected registries were received from the server! (missing: %s)", + "neoforge.network.registries.sync.server-with-unknown-keys": "The server send registries with unknown keys: %s", + "neoforge.network.registries.sync.failed": "Failed to sync registries from the server: %s", + "neoforge.network.aux_light_data.failed": "Failed to handle auxiliary light data for chunk %s: %s", + "neoforge.network.data_maps.failed": "Failed to handle registry data map sync for registry %s: %s", + "neoforge.network.data_maps.missing_our": "Cannot connect to server as it is missing mandatory registry data maps present on the client: %s", + "neoforge.network.data_maps.missing_their": "Cannot connect to server as it has mandatory registry data maps not present on the client: %s", + "neoforge.network.extensible_enums.no_vanilla_server": "Klien ini tidak menyokong pelayan vanila kerana ia mempunyai enum lanjutan yang digunakan dalam rangkaian terikat pelayan", + "neoforge.network.extensible_enums.enum_set_mismatch": "Set enum yang boleh diperluaskan pada klien dan pelayan tidak sepadan. Pastikan anda menggunakan versi NeoForge yang sama seperti pelayan", + "neoforge.network.extensible_enums.enum_entry_mismatch": "Set nilai yang ditambahkan pada enum yang boleh diperluaskan pada klien dan pelayan tidak sepadan. Pastikan anda menggunakan mod dan versi NeoForge yang sama seperti pelayan. Lihat log untuk butiran lanjut" +} diff --git a/src/main/resources/assets/neoforge/lang/nl_nl.json b/src/main/resources/assets/neoforge/lang/nl_nl.json index b0f3a822ce..f637964644 100644 --- a/src/main/resources/assets/neoforge/lang/nl_nl.json +++ b/src/main/resources/assets/neoforge/lang/nl_nl.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "Dit commando is afgeschreven voor verwijderd in 1.17, gebruik in plaats daarvan %s.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Het volgen van Entiteiten is ingeschakeld voor %d seconden.", "commands.neoforge.tracking.entity.reset": "Entiteit timing data is gewist!", "commands.neoforge.tracking.invalid": "Ongeldige volggegevens.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Configuratie voor %s van type %s gevonden bij %s", "commands.config.noconfig": "Configuratie voor %s van type %s niet gevonden", "neoforge.update.beta.1": "%sWAARSCHUWING: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Verwijder foutveroorzakende blokentiteiten", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Verwijder foutveroorzakende entiteiten", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Toon Laad Waarschuwingen", "neoforge.configgui.showLoadWarnings.tooltip": "Wanneer ingeschakeld, zal NeoForge elke waarschuwing laten zien die optreed tijdens het laden.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/pl_pl.json b/src/main/resources/assets/neoforge/lang/pl_pl.json index 05ca184988..1e3be0e5c6 100644 --- a/src/main/resources/assets/neoforge/lang/pl_pl.json +++ b/src/main/resources/assets/neoforge/lang/pl_pl.json @@ -62,31 +62,31 @@ "fml.resources.modresources": "Zasoby dla plików modyfikacji %1$s", "fml.resources.moddata": "Dane dla %1$s plików modyfikacji", "loadwarning.neoforge.prbuild": "Ta kompilacja NeoForge została stworzona przez członka społeczności i jest §c§lNIEWSPIERANA§r", - "commands.neoforge.arguments.enum.invalid": "Enum constant must be one of %1$s, found %2$s", - "commands.neoforge.dimensions.list": "Currently registered dimensions by type:", - "commands.neoforge.dump.success": "New file created with %s registry's contents is at %s", - "commands.neoforge.dump.failure": "Failed to create new file with %s registry's contents at %s", + "commands.neoforge.arguments.enum.invalid": "Stała Enum musi być jednym z %1$s, znaleziono %2$s", + "commands.neoforge.dimensions.list": "Aktualnie zarejestrowane wymiary według typu:", + "commands.neoforge.dump.success": "Nowy plik utworzony z zawartością rejestru %s jest w %s", + "commands.neoforge.dump.failure": "Nie udało się utworzyć nowego pliku z zawartością rejestru %s w %s", "commands.neoforge.dump.error.unknown_registry": "Unknown registry '%s'", "commands.neoforge.entity.list.invalid": "Nieprawidłowy filtr, nie pasuje do żadnych bytów. Użyj /neoforge entity list dla właściwej listy", - "commands.neoforge.entity.list.invalidworld": "Could not load world for dimension %1$s. Please select a valid dimension.", + "commands.neoforge.entity.list.invalidworld": "Nie można załadować świata dla wymiaru %1$s. Proszę wybrać prawidłowy wymiar.", "commands.neoforge.entity.list.none": "Nie znaleziono obiektów.", - "commands.neoforge.entity.list.single.header": "Entity: %1$s Total: %2$s", - "commands.neoforge.entity.list.multiple.header": "Total: %1$s", - "commands.neoforge.setdim.invalid.entity": "The entity selected (%1$s) is not valid.", - "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", - "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", + "commands.neoforge.entity.list.single.header": "Byt: %1$s Razem: %2$s", + "commands.neoforge.entity.list.multiple.header": "Łącznie: %1$s", + "commands.neoforge.setdim.invalid.entity": "Wybrany byt (%1$s) jest nieprawidłowy.", + "commands.neoforge.setdim.invalid.dim": "Określone ID Wymiaru (%1$s) jest nieprawidłowe.", + "commands.neoforge.setdim.invalid.nochange": "Wybrany byt (%1$s) jest już w określonym wymiarze (%2$s).", "commands.neoforge.setdim.deprecated": "To polecenie jest przestarzałe i zostanie usunięte w 1.17, użyj %s zamiast niej.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", - "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", + "commands.neoforge.tps.overall": "Łącznie: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Średni TPS; wyższy jest lepszy. Docelowy TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Typ wymiaru: %s)", + "commands.neoforge.mods.list": "Lista modyfikacji: %1$s", "commands.neoforge.tracking.entity.enabled": "Śledzenie bytu zostało uruchomione na %d sekund.", "commands.neoforge.tracking.entity.reset": "Entity timings data has been cleared!", "commands.neoforge.tracking.invalid": "Nieprawidłowe dane śledzenia.", "commands.neoforge.tracking.be.enabled": "Blokowanie śledzenia bytów zostało uruchomione na %d sekund.", "commands.neoforge.tracking.be.reset": "Block entity timings data has been cleared!", - "commands.neoforge.tracking.timing_entry": "%1$s - %2$s [%3$s, %4$s, %5$s]: %6$s", + "commands.neoforge.tracking.timing_entry": "%1$s - %2$s [%3$s,%4$s,%5$s]: %6$s", "commands.neoforge.tracking.no_data": "Nie zarejestrowano jeszcze żadnych danych.", "commands.neoforge.tags.error.unknown_registry": "Nieznany rejestr '%s'", "commands.neoforge.tags.error.unknown_tag": "Nieznany tag '%s' w rejestrze '%s'", @@ -111,184 +111,116 @@ "commands.neoforge.chunkgen.status": "Status generacji! %1$s z %2$s chunków wygenerowanych. (%3$s%%)", "commands.neoforge.chunkgen.not_running": "Aktualnie brak uruchomionych pregeneracji. Uruchom `/neoforge generate help` aby zobaczyć polecenia do rozpoczęcia generacji.", "commands.neoforge.chunkgen.help_line": "§2/neoforge generate start [progressBar] §r§f- Generates a square centered on the given position that is chunkRadius * 2 on each side.\n§2/neoforge generate stop §r§f- Stops the current generation and displays progress that it had completed.\n§2/neoforge generate status §r- Displays the progress completed for the currently running generation.\n§2/neoforge generate help §r- Displays this message.\nGeneral tips: If running from a server console, you can run generate in different dimensions by using /execute in neoforge generate...", - "commands.neoforge.timespeed.query": "Time in %s flows at a rate of %sx (%s minutes per day).", - "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", - "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", - "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", - "commands.config.getwithtype": "Config for %s of type %s found at %s", - "commands.config.noconfig": "Config for %s of type %s not found", - "neoforge.update.beta.1": "%sWARNING: %sNeoForge Beta", - "neoforge.update.beta.2": "Major issues may arise, verify before reporting.", - "neoforge.update.newversion": "New NeoForge version available: %s", + "commands.neoforge.timespeed.query": "Czas w %s przepływa w tempie %sx (%s minut dziennie).", + "commands.neoforge.timespeed.query.default": "Czas w %s przepływa normalnie (20 minut dziennie).", + "commands.neoforge.timespeed.set": "Ustaw przepływ czasu w %s do %sx (%s minut dziennie).", + "commands.neoforge.timespeed.set.default": "Ustaw przepływ czasu w %s na domyślne (20 minut na dzień).", + "commands.neoforge.data_components.list.error.held_stack_empty": "Nie trzymasz żadnego przedmiotu", + "commands.neoforge.data_components.list.title": "Komponenty danych na %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Komponent %s posiada wartość domyślną", + "commands.neoforge.data_components.list.tooltip.deleted": "Komponent %s o wartości %s został usunięty", + "commands.neoforge.data_components.list.tooltip.modified": "Komponent %s został zmodyfikowany z %s na %s", + "commands.neoforge.data_components.list.tooltip.added": "Komponent %s został dodany z wartością %s", + "commands.config.getwithtype": "Opcje dla %s typu %s znaleziona w %s", + "commands.config.noconfig": "Opcje dla %s typu %s nie została znaleziona", + "neoforge.update.beta.1": "%sUWAGA: %sNeoForge Beta", + "neoforge.update.beta.2": "Mogą się pojawić poważne problemy, zweryfikuj przed zgłoszeniem", + "neoforge.update.newversion": "Nowa wersja NeoForge jest dostępna: %s", "neoforge.menu.updatescreen.title": "Aktualizacja modifikacji", - "neoforge.configuration.uitext.title": "%s Configuration", - "neoforge.configuration.uitext.type.client": "Client Settings", - "neoforge.configuration.uitext.type.server": "Server Settings", - "neoforge.configuration.uitext.type.common": "Common settings", - "neoforge.configuration.uitext.type.startup": "Startup settings", - "neoforge.configuration.uitext.title.client": "%s Client Configuration", - "neoforge.configuration.uitext.title.server": "%s Server Configuration", - "neoforge.configuration.uitext.title.common": "%s Common Configuration", - "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.title": "%s Konfiguracja", + "neoforge.configuration.uitext.type.client": "Ustawienia klienta", + "neoforge.configuration.uitext.type.server": "Ustawienia Serwera", + "neoforge.configuration.uitext.type.common": "Ogólne ustawienia", + "neoforge.configuration.uitext.type.startup": "Ustawienia uruchamiania", + "neoforge.configuration.uitext.title.client": "%s Konfiguracja klienta", + "neoforge.configuration.uitext.title.server": "%s Konfiguracja serwera", + "neoforge.configuration.uitext.title.common": "%s Ogólna konfiguracja", + "neoforge.configuration.uitext.title.startup": "%s Konfiguracja uruchamiania", + "neoforge.configuration.uitext.notonline": "Ustawienia w tym świecie są określone przez serwer i nie mogą być zmieniane podczas online.", + "neoforge.configuration.uitext.notlan": "Ustawienia w tym świecie nie mogą być edytowane, gdy gra jest otwarta na LAN. Proszę wrócić do menu głównego i ponownie załadować świat.", + "neoforge.configuration.uitext.notloaded": "Ustawienia tutaj są dostępne tylko wtedy, gdy świat jest ładowany.", + "neoforge.configuration.uitext.unsupportedelement": "Ta wartość nie może być edytowana w interfejsie użytkownika. Skontaktuj się z autorem modyfikacji w celu dostarczenia niestandardowego interfejsu użytkownika.", + "neoforge.configuration.uitext.longstring": "Ta wartość jest zbyt długa, aby być edytowana w interfejsie użytkownika. Proszę edytować ją w pliku konfiguracyjnym.", "neoforge.configuration.uitext.section": "%s...", - "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.sectiontext": "Edytuj", + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", - "neoforge.configuration.uitext.undo": "Undo", - "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", - "neoforge.configuration.uitext.reset": "Reset", - "neoforge.configuration.uitext.reset.tooltip": "Reverts everything on this screen to its default value.", + "neoforge.configuration.uitext.undo": "Cofnij", + "neoforge.configuration.uitext.undo.tooltip": "Odwraca zmiany tylko na tym ekranie.", + "neoforge.configuration.uitext.reset": "Resetuj", + "neoforge.configuration.uitext.reset.tooltip": "Przywraca wszystko na tym ekranie do wartości domyślnej.", "neoforge.configuration.uitext.newlistelement": "+", "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], - "neoforge.configuration.uitext.common": "Common Options", - "neoforge.configuration.uitext.client": "Client Options", - "neoforge.configuration.uitext.server": "Server Options", - "neoforge.configuration.uitext.startup": "Startup Options", - "neoforge.configuration.uitext.restart.game.title": "Minecraft needs to be restarted", - "neoforge.configuration.uitext.restart.game.text": "One or more of the configuration option that were changed will only take effect when the game is started.", - "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", - "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", - "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], - "neoforge.configuration.title": "NeoForge Configuration", - "neoforge.configuration.section.neoforge.client.toml": "Client settings", - "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", - "neoforge.configuration.section.neoforge.common.toml": "Common settings", - "neoforge.configuration.section.neoforge.common.toml.title": "Common settings", - "neoforge.configuration.section.neoforge.server.toml": "Server settings", - "neoforge.configuration.section.neoforge.server.toml.title": "Server settings", - "neoforge.configgui.advertiseDedicatedServerToLan": "Advertise Dedicated Server To LAN", - "neoforge.configgui.advertiseDedicatedServerToLan.tooltip": "Set this to true to enable advertising the dedicated server to local LAN clients so that it shows up in the Multiplayer screen automatically.", - "neoforge.configgui.forgeLightPipelineEnabled": "NeoForge Light Pipeline", + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", + "neoforge.configuration.uitext.common": "Opcje standardowe", + "neoforge.configuration.uitext.client": "Opcje Klienta", + "neoforge.configuration.uitext.server": "Opcje Serwera", + "neoforge.configuration.uitext.startup": "Opcje uruchamiania", + "neoforge.configuration.uitext.restart.game.title": "Minecraft musi zostać uruchomiony ponownie", + "neoforge.configuration.uitext.restart.game.text": "Jedna lub więcej zmienionych opcji konfiguracji zacznie obowiązywać dopiero po uruchomieniu gry.", + "neoforge.configuration.uitext.restart.server.title": "Świat musi zostać ponownie załadowany", + "neoforge.configuration.uitext.restart.server.text": "Jedna lub więcej opcji konfiguracji, które zostały zmienione, zacznie obowiązywać dopiero po przeładowaniu świata.", + "neoforge.configuration.uitext.restart.return": "Ignoruj", + "neoforge.configuration.uitext.restart.return.tooltip": "Twoje zmiany nie będą miały wpływu do czasu ponownego uruchomienia!", + "neoforge.configuration.title": "Konfiguracja NeoForge", + "neoforge.configuration.section.neoforge.client.toml": "Ustawienia klienta", + "neoforge.configuration.section.neoforge.client.toml.title": "Ustawienia klienta", + "neoforge.configuration.section.neoforge.common.toml": "Ogólne ustawienia", + "neoforge.configuration.section.neoforge.common.toml.title": "Ogólne ustawienia", + "neoforge.configuration.section.neoforge.server.toml": "Ustawienia Serwera", + "neoforge.configuration.section.neoforge.server.toml.title": "Ustawienia Serwera", + "neoforge.configgui.advertiseDedicatedServerToLan": "Reklamuj dedykowany serwer do sieci LAN", + "neoforge.configgui.advertiseDedicatedServerToLan.tooltip": "Ustaw to na true, aby włączyć reklamę serwera dedykowanego do lokalnych klientów sieci LAN, tak aby pojawiał się automatycznie na ekranie wieloosobowym.", + "neoforge.configgui.forgeLightPipelineEnabled": "Lekki Rurociąg NeoForge", "neoforge.configgui.forgeLightPipelineEnabled.tooltip": "Włącz proces renderowania bloków NeoForge - poprawia oświetlenie modeli niestandardowych.", "neoforge.configgui.fullBoundingBoxLadders": "Full Bounding Box Ladders", "neoforge.configgui.fullBoundingBoxLadders.tooltip": "Set this to true to check the entire entity's collision bounding box for ladders instead of just the block they are in. Causes noticeable differences in mechanics so default is vanilla behavior. Default: false.", - "neoforge.configgui.logLegacyTagWarnings": "Log Legacy Tags", - "neoforge.configgui.logLegacyTagWarnings.tooltip": "A config option mainly for developers. Logs out modded tags that are using the 'forge' namespace when running on integrated server. Defaults to DEV_SHORT.", - "neoforge.configgui.logUntranslatedConfigurationWarnings": "Log Untranslated Configuration Keys", - "neoforge.configgui.logUntranslatedConfigurationWarnings.tooltip": "A config option mainly for developers. Logs out configuration values that do not have translations when running a client in a development environment.", - "neoforge.configgui.logUntranslatedItemTagWarnings": "Log Untranslated Item Tags", - "neoforge.configgui.logUntranslatedItemTagWarnings.tooltip": "A config option mainly for developers. Logs out modded item tags that do not have translations when running on integrated server. Format desired is tag.item.. for the translation key. Defaults to SILENCED.", - "neoforge.configgui.permissionHandler": "Permission Handler", - "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", + "neoforge.configgui.logLegacyTagWarnings": "Rejestruj starsze tagi", + "neoforge.configgui.logLegacyTagWarnings.tooltip": "Opcja konfiguracyjna głównie dla programistów. Wyloguj modyfikowane tagi, które używają przestrzeni nazw \"forge\" podczas pracy na zintegrowanym serwerze. Domyślnie dla DEV_SHORT.", + "neoforge.configgui.logUntranslatedConfigurationWarnings": "Loguj nieprzetłumaczone klucze konfiguracyjne", + "neoforge.configgui.logUntranslatedConfigurationWarnings.tooltip": "Opcja konfiguracyjna głównie dla programistów. Wyloguje wartości konfiguracyjne, które nie mają tłumaczeń podczas uruchamiania klienta w środowisku programistycznym.", + "neoforge.configgui.logUntranslatedItemTagWarnings": "Loguj nieprzetłumaczone tagi itemów", + "neoforge.configgui.logUntranslatedItemTagWarnings.tooltip": "Opcja konfiguracyjna głównie dla deweloperów. Wyloguj tagi zmodowanego itemu, które nie mają tłumaczeń podczas pracy na zintegrowanym serwerze. Wymagany format to tag.item.. dla klucza tłumaczenia. Domyślnie dla SILENCED.", + "neoforge.configgui.permissionHandler": "Obsługa uprawnień", + "neoforge.configgui.permissionHandler.tooltip": "Obsługa uprawnień używana przez serwer. Domyślnie przekierowuje neoforge:default_handler jeśli nie jest zarejestrowany taki program obsługi o tej nazwie.", "neoforge.configgui.removeErroringBlockEntities": "Remove Erroring Block Entities", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "ZOSTAŁEŚ OSTRZEŻONY TO MOŻE ZEPSUĆ WSZYSTKO\nUŻYJ SPARINGLY\nNIE JESTEŚMY ODPOWIEDZIALNI ZA SZKODY.", "neoforge.configgui.removeErroringEntities": "Remove Erroring Entities", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "ZOSTAŁEŚ OSTRZEŻONY TO MOŻE ZEPSUĆ WSZYSTKO\nUŻYJ SPARINGLY\nNIE JESTEŚMY ODPOWIEDZIALNI ZA SZKODY.", "neoforge.configgui.showLoadWarnings": "Pokaż Ostrzeżenia Ładowania", "neoforge.configgui.showLoadWarnings.tooltip": "Kiedy włączone, NeoForge wyświetli wszelkie ostrzeżenia, które wystąpiły podczas ładowania.", - "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", - "neoforge.configgui.useCombinedDepthStencilAttachment.tooltip": "Set to true to use a combined DEPTH_STENCIL attachment instead of two separate ones.", + "neoforge.configgui.useCombinedDepthStencilAttachment": "Użyj połączonego załącznika DEPTH_STENCIL", + "neoforge.configgui.useCombinedDepthStencilAttachment.tooltip": "Ustaw na true aby użyć połączonego załącznika DEPTH_STENCIL zamiast dwóch oddzielnych.", "neoforge.controlsgui.shift": "SHIFT + %s", "neoforge.controlsgui.control": "CTRL + %s", "neoforge.controlsgui.control.mac": "CMD + %s", "neoforge.controlsgui.alt": "ALT + %s", "neoforge.container.enchant.limitedEnchantability": "Ograniczona zdolność do zaklinania", "neoforge.swim_speed": "Szybkość pływania", - "neoforge.name_tag_distance": "Nametag Render Distance", + "neoforge.name_tag_distance": "Dystans renderowania znaczników", "neoforge.creative_flight": "Creative Flight", "fluid_type.minecraft.milk": "Mleko", "fluid_type.minecraft.flowing_milk": "Mleko", "neoforge.froge.warningScreen.title": "NeoForge snapshots notice", "neoforge.froge.warningScreen.text": "Froge nie jest oficjalnie wspierany. Błędy mogą się pojawić.", - "neoforge.froge.supportWarning": "WARNING: Froge is not supported by NeoForge", + "neoforge.froge.supportWarning": "OSTRZEŻENIE: Froge nie jest wspierane przez NeoForge", "neoforge.gui.exit": "Wyjście", - "neoforge.experimentalsettings.tooltip": "This world uses experimental settings, which could stop working at any time.", - "neoforge.selectWorld.backupWarning.experimental.additional": "This message will not show again for this world.", + "neoforge.experimentalsettings.tooltip": "Ten świat używa ustawień eksperymentalnych, które mogą przestać działać w każdej chwili.", + "neoforge.selectWorld.backupWarning.experimental.additional": "Ta wiadomość nie pojawi się ponownie dla tego świata.", "neoforge.chatType.system": "%1$s", - "pack.neoforge.description": "NeoForge data/resource pack", - "pack.neoforge.source.child": "child", - "neoforge.network.negotiation.failure.mod": "Channel of mod \"%1$s\" failed to connect: %2$s", - "neoforge.network.negotiation.failure.missing.client.server": "This channel is missing on the server side, but required on the client!", - "neoforge.network.negotiation.failure.missing.server.client": "This channel is missing on the client side, but required on the server!", + "pack.neoforge.description": "zasoby NeoForge / pakiet danych", + "pack.neoforge.source.child": "potomstwo", + "neoforge.network.negotiation.failure.mod": "Kanał modyfikacji \"%1$s\" nie mógł się połączyć: %2$s", + "neoforge.network.negotiation.failure.missing.client.server": "Ten kanał brakuje po stronie serwera, ale jest wymagany na kliencie!", + "neoforge.network.negotiation.failure.missing.server.client": "Ten kanał brakuje po stronie klienta, ale jest wymagany na serwerze", "neoforge.network.negotiation.failure.flow.client.missing": "The client wants the payload to flow: %s, but the server does not support it!", "neoforge.network.negotiation.failure.flow.server.missing": "The server wants the payload to flow: %s, but the client does not support it!", "neoforge.network.negotiation.failure.flow.client.mismatch": "The client wants the payload to flow: %s, but the server wants it to flow: %s!", @@ -296,20 +228,20 @@ "neoforge.network.negotiation.failure.version.client.missing": "The client wants the payload to be version: %s, but the server does not support it!", "neoforge.network.negotiation.failure.version.server.missing": "The server wants the payload to be version: %s, but the client does not support it!", "neoforge.network.negotiation.failure.version.mismatch": "The client wants the payload to be version: %s, but the server wants it to be version: %s!", - "neoforge.network.invalid_flow": "Failed to process a payload that was send with an invalid flow: %s", - "neoforge.network.negotiation.failure.vanilla.client.not_supported": "You are trying to connect to a server that is running NeoForge, but you are not. Please install NeoForge Version: %s to connect to this server.", - "neoforge.network.negotiation.failure.vanilla.server.not_supported": "You are trying to connect to a server that is not running NeoForge, but you have mods that require it. A connection could not be established.", - "neoforge.network.packet_splitter.unknown": "Tried to split a packet without packet splitter!", + "neoforge.network.invalid_flow": "Nie powiodło się przetwarzanie ładunku, który został wysłany z nieprawidłowym przepływem: %s", + "neoforge.network.negotiation.failure.vanilla.client.not_supported": "Próbujesz się połączyć się do serwera, który działa na NeoForge, ale nie masz takiej możliwości. Proszę zainstalować Wersję: %s NeoForge, by się połączyć do tego serwera.", + "neoforge.network.negotiation.failure.vanilla.server.not_supported": "Próbujesz się połączyć do serwera, który nie działa na NeoForge, ale masz modyfikacje, które tego wymagają", + "neoforge.network.packet_splitter.unknown": "Spróbowano podzielić pakiet bez rozdzielacza pakietów!", "neoforge.network.advanced_add_entity.failed": "Failed to process advanced entity spawn data: %s", "neoforge.network.advanced_open_screen.failed": "Failed to open a screen with advanced data: %s", - "neoforge.network.registries.sync.missing": "Not all expected registries were received from the server! (missing: %s)", + "neoforge.network.registries.sync.missing": "Nie wszystkie oczekiwane rejestry zostały otrzymane od serwera! (Brakujące: %s)", "neoforge.network.registries.sync.server-with-unknown-keys": "Serwer wysyła rejestry z nieznanymi kluczami: %s", - "neoforge.network.registries.sync.failed": "Failed to sync registries from the server: %s", + "neoforge.network.registries.sync.failed": "Nie powiodła się synchronizacja rejestrów z serwerem: %s ", "neoforge.network.aux_light_data.failed": "Failed to handle auxiliary light data for chunk %s: %s", - "neoforge.network.data_maps.failed": "Failed to handle registry data map sync for registry %s: %s", + "neoforge.network.data_maps.failed": "Nie udało się obsłużyć synchronizacji map danych dla rejestru %s: %s", "neoforge.network.data_maps.missing_our": "Nie można połączyć się z serwerem, ponieważ brakuje obowiązkowych map danych rejestru znajdujących się w kliencie: %s", "neoforge.network.data_maps.missing_their": "Nie można połączyć się z serwerem, ponieważ brakuje obowiązkowych map danych rejestru znajdujących się w kliencie: %s", - "neoforge.network.extensible_enums.no_vanilla_server": "This client does not support vanilla servers as it has extended enums used in serverbound networking", - "neoforge.network.extensible_enums.enum_set_mismatch": "The set of extensible enums on the client and server do not match. Make sure you are using the same NeoForge version as the server", - "neoforge.network.extensible_enums.enum_entry_mismatch": "The set of values added to extensible enums on the client and server do not match. Make sure you are using the same mod and NeoForge versions as the server. See the log for more details" + "neoforge.network.extensible_enums.no_vanilla_server": "Ten klient nie obsługuje serwerów vanilla ponieważ posiada rozszerzone enums używane w sieciach związanych z serwerem", + "neoforge.network.extensible_enums.enum_set_mismatch": "Zestaw rozszerzalnych enumerów na kliencie i serwerze nie pasuje. Upewnij się, że używasz tej samej wersji NeoForge co serwer", + "neoforge.network.extensible_enums.enum_entry_mismatch": "Zestaw wartości dodanych do rozszerzalnych enumów w kliencie i serwerze nie pasuje. Upewnij się, że używasz tych samych wersji modyfikacji i NeoForge co serwer. Więcej informacji znajdziesz w logu" } diff --git a/src/main/resources/assets/neoforge/lang/pt_br.json b/src/main/resources/assets/neoforge/lang/pt_br.json index 70eaf520c6..e931213fac 100644 --- a/src/main/resources/assets/neoforge/lang/pt_br.json +++ b/src/main/resources/assets/neoforge/lang/pt_br.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "This command is deprecated for removal in 1.17, use %s instead.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Entity tracking enabled for %d seconds.", "commands.neoforge.tracking.entity.reset": "Entity timings data has been cleared!", "commands.neoforge.tracking.invalid": "Invalid tracking data.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Config for %s of type %s found at %s", "commands.config.noconfig": "Config for %s of type %s not found", "neoforge.update.beta.1": "%sWARNING: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Remove Erroring Block Entities", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Remove Erroring Entities", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Show Load Warnings", "neoforge.configgui.showLoadWarnings.tooltip": "When enabled, NeoForge will show any warnings that occurred during loading.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/pt_pt.json b/src/main/resources/assets/neoforge/lang/pt_pt.json index 405906c80c..f43c9088b0 100644 --- a/src/main/resources/assets/neoforge/lang/pt_pt.json +++ b/src/main/resources/assets/neoforge/lang/pt_pt.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "This command is deprecated for removal in 1.17, use %s instead.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Entity tracking enabled for %d seconds.", "commands.neoforge.tracking.entity.reset": "Entity timings data has been cleared!", "commands.neoforge.tracking.invalid": "Invalid tracking data.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Config for %s of type %s found at %s", "commands.config.noconfig": "Config for %s of type %s not found", "neoforge.update.beta.1": "%sWARNING: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Remove Erroring Block Entities", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Remove Erroring Entities", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Show Load Warnings", "neoforge.configgui.showLoadWarnings.tooltip": "When enabled, NeoForge will show any warnings that occurred during loading.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/ro_ro.json b/src/main/resources/assets/neoforge/lang/ro_ro.json index c20a393fb6..97e50d1982 100644 --- a/src/main/resources/assets/neoforge/lang/ro_ro.json +++ b/src/main/resources/assets/neoforge/lang/ro_ro.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "This command is deprecated for removal in 1.17, use %s instead.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Entity tracking enabled for %d seconds.", "commands.neoforge.tracking.entity.reset": "Entity timings data has been cleared!", "commands.neoforge.tracking.invalid": "Invalid tracking data.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Config for %s of type %s found at %s", "commands.config.noconfig": "Config for %s of type %s not found", "neoforge.update.beta.1": "%sWARNING: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Remove Erroring Block Entities", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Remove Erroring Entities", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Show Load Warnings", "neoforge.configgui.showLoadWarnings.tooltip": "When enabled, NeoForge will show any warnings that occurred during loading.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/ru_ru.json b/src/main/resources/assets/neoforge/lang/ru_ru.json index d37e1f8a80..0b54ff2c22 100644 --- a/src/main/resources/assets/neoforge/lang/ru_ru.json +++ b/src/main/resources/assets/neoforge/lang/ru_ru.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "Эта команда устарела и помечена для удаления начиная с 1.17, вместо нее используйте %s.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Список модов: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Отслеживание сущностей включено на %d секунд.", "commands.neoforge.tracking.entity.reset": "Данные с таймингами сущностей очищены!", "commands.neoforge.tracking.invalid": "Неверные данные отслеживания.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Конфиг для %s типа %s обнаружен в %s", "commands.config.noconfig": "Конфиг для %s типа %s не найден", "neoforge.update.beta.1": "%sВНИМАНИЕ: %sNeoForge Бета", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Удалять блочные сущности, вызывающие ошибки", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Удалять сущности, вызывающие ошибки", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Показывать предупреждения при загрузке", "neoforge.configgui.showLoadWarnings.tooltip": "Если эта функция включена, NeoForge покажет все предупреждения, возникшие во время загрузки.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/sk_sk.json b/src/main/resources/assets/neoforge/lang/sk_sk.json index f0af09f90b..80b274aa55 100644 --- a/src/main/resources/assets/neoforge/lang/sk_sk.json +++ b/src/main/resources/assets/neoforge/lang/sk_sk.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "Dimenzia s vybraným ID (%1$s) nie je validná.", "commands.neoforge.setdim.invalid.nochange": "Vybraná entita (%1$s) už existuje v špecifikovanej dimenzii (%2$s).", "commands.neoforge.setdim.deprecated": "Tento príkaz je zastaralý a bude vymazaný v 1.17, použite %s namiesto neho.", - "commands.neoforge.tps.invalid": "Invalidná dimenzia %1$s Možné hodnoty: %2$s", - "commands.neoforge.tps.summary.all": "Celkovo: Priemerný čas ticku: %1$s ms. Priemerné TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "List módov: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Priemerný čas ticku: %2$s ms. Priemerné TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Priemerný čas ticku: %3$s ms. Priemerné TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Sledovanie entít povolené na %d sekúnd.", "commands.neoforge.tracking.entity.reset": "Údaje o časovaní entít boli vymazané!", "commands.neoforge.tracking.invalid": "Neplatné dáta sledovania.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Čas v %s plynie normálne (20 minút na deň).", "commands.neoforge.timespeed.set": "Nastaviť plynutie času v %s na %sx (%s minúty za deň).", "commands.neoforge.timespeed.set.default": "Nastaviť plynutie času v %s na predvolené (20 minút za deň).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Konfigurácia pre %s typu %s nájdená v %s", "commands.config.noconfig": "Konfigurácia pre %s typu %s nenájdená", "neoforge.update.beta.1": "%sVAROVANIE: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Konfigurácia Serveru", "neoforge.configuration.uitext.title.common": "%s Bežná Konfigurácia", "neoforge.configuration.uitext.title.startup": "%s Konfigurácia Spustenia", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Nastavenie tu sú určené serverom a nemôžu byť zmenené pokým je online.", - "color": "červená" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Nastavenia tu nemôžu byť upravené pokým je vaša hra otvorená do LAN. Prosím vráťte sa do hlavného menu a načítajte svet znova.", - "color": "červená" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Nastavenia tu sú k dispozícii len keď je svet načítaný.", - "color": "červená" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "Táto hodnota nemôže byť upravená v UI. Prosím kontaktujte autora módu o poskytnutý vlastného UI preň.", - "color": "červená" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "Táto hodnota je pridlhá nato aby mohla byť upravená v UI. Prosím upravte ju v konfiguračnom súbore.", - "color": "červená" - } - ], + "neoforge.configuration.uitext.notonline": "Nastavenie tu sú určené serverom a nemôžu byť zmenené pokým je online.", + "neoforge.configuration.uitext.notlan": "Nastavenia tu nemôžu byť upravené pokým je vaša hra otvorená do LAN. Prosím vráťte sa do hlavného menu a načítajte svet znova.", + "neoforge.configuration.uitext.notloaded": "Nastavenia tu sú k dispozícii len keď je svet načítaný.", + "neoforge.configuration.uitext.unsupportedelement": "Táto hodnota nemôže byť upravená v UI. Prosím kontaktujte autora módu o poskytnutý vlastného UI preň.", + "neoforge.configuration.uitext.longstring": "Táto hodnota je pridlhá nato aby mohla byť upravená v UI. Prosím upravte ju v konfiguračnom súbore.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Upraviť", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "zlato", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Krok naspäť", "neoforge.configuration.uitext.undo.tooltip": "Vráti zmeny len na tejto obrazovke.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRádius: ", - "color": "sivá" - }, - { - "index": 0, - "color": "sivá" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "Súbor: \"", - "color": "sivá" - }, - { - "index": 0, - "color": "sivá" - }, - { - "text": "\"", - "color": "sivá" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Bežné Nastavenia", "neoforge.configuration.uitext.client": "Nastavenia Klienta", "neoforge.configuration.uitext.server": "Nastavenia Serveru", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "Svet treba znova načítať", "neoforge.configuration.uitext.restart.server.text": "Jedno alebo viac z konfiguračných nastavení ktoré boli zmenené budú mať efekt až keď bude hra znova načítaná.", "neoforge.configuration.uitext.restart.return": "Ignorovať", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Vaše zmeny nebudú mať žiadny efekt pokým nereštartujete!", - "color": "červená", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Vaše zmeny nebudú mať žiadny efekt pokým nereštartujete!", "neoforge.configuration.title": "NeoForge Konfigurácia", "neoforge.configuration.section.neoforge.client.toml": "Nastavenia klienta", "neoforge.configuration.section.neoforge.client.toml.title": "Nastavenia klienta", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Manipulátor Povolení", "neoforge.configgui.permissionHandler.tooltip": "Manipulátor povolení používaný serverom. Predvolená hodnota do neoforge:default_handler ak nie je žiadny manipulátor s takým menom registrovaný.", "neoforge.configgui.removeErroringBlockEntities": "Odstrániť blokové entity spôsobujúce error", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Nastavte toto na hodnotu TRUE na odstránenie akejkoľvek Entity, ktorá vyhodí chybu v ich aktualizačnej metóde namiesto uzavretia serveru a nahlásenia logu padnutia.\n\n", - { - "text": "BUDŤE VAROVANÝ, TOTO BY MOHLO VŠETKO ROZBIŤ.\nPOUŽÍVAJTE OPATRNE.\nNIE SME ZODPOVEDNÝ ZA ŠKODY.", - "color": "červená", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BUDŤE VAROVANÝ, TOTO BY MOHLO VŠETKO ROZBIŤ.\nPOUŽÍVAJTE OPATRNE.\nNIE SME ZODPOVEDNÝ ZA ŠKODY.", "neoforge.configgui.removeErroringEntities": "Odstrániť entity spôsobujúce error", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Nastavte toto na hodnotu TRUE na odstránenie akejkoľvek Blokovej Entity, ktorá vyhodí chybu v ich aktualizačnej metóde namiesto uzavretia serveru a nahlásenia logu padnutia.\n\n", - { - "text": "BUDŤE VAROVANÝ, TOTO BY MOHLO VŠETKO ROZBIŤ.\nPOUŽÍVAJTE OPATRNE.\nNIE SME ZODPOVEDNÝ ZA ŠKODY.", - "color": "červená", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BUDŤE VAROVANÝ, TOTO BY MOHLO VŠETKO ROZBIŤ.\nPOUŽÍVAJTE OPATRNE.\nNIE SME ZODPOVEDNÝ ZA ŠKODY.", "neoforge.configgui.showLoadWarnings": "Zobraziť Varovania Načítavania", "neoforge.configgui.showLoadWarnings.tooltip": "Keď je toto povolené, NeoForge zobrazí všetky varovania, ktoré nastali počas načítavania.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Použiť kombinované DEPTH_STENCIL Prílohy", diff --git a/src/main/resources/assets/neoforge/lang/tr_tr.json b/src/main/resources/assets/neoforge/lang/tr_tr.json index fcecf56a33..50e04e5287 100644 --- a/src/main/resources/assets/neoforge/lang/tr_tr.json +++ b/src/main/resources/assets/neoforge/lang/tr_tr.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "This command is deprecated for removal in 1.17, use %s instead.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Entity tracking enabled for %d seconds.", "commands.neoforge.tracking.entity.reset": "Entity timings data has been cleared!", "commands.neoforge.tracking.invalid": "Invalid tracking data.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Config for %s of type %s found at %s", "commands.config.noconfig": "Config for %s of type %s not found", "neoforge.update.beta.1": "%sWARNING: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Remove Erroring Block Entities", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Remove Erroring Entities", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Show Load Warnings", "neoforge.configgui.showLoadWarnings.tooltip": "When enabled, NeoForge will show any warnings that occurred during loading.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/tt_ru.json b/src/main/resources/assets/neoforge/lang/tt_ru.json index 5385dcc2e4..b2a216d165 100644 --- a/src/main/resources/assets/neoforge/lang/tt_ru.json +++ b/src/main/resources/assets/neoforge/lang/tt_ru.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "This command is deprecated for removal in 1.17, use %s instead.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Entity tracking enabled for %d seconds.", "commands.neoforge.tracking.entity.reset": "Entity timings data has been cleared!", "commands.neoforge.tracking.invalid": "Invalid tracking data.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Config for %s of type %s found at %s", "commands.config.noconfig": "Config for %s of type %s not found", "neoforge.update.beta.1": "%sWARNING: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Remove Erroring Block Entities", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Remove Erroring Entities", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Show Load Warnings", "neoforge.configgui.showLoadWarnings.tooltip": "When enabled, NeoForge will show any warnings that occurred during loading.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/uk_ua.json b/src/main/resources/assets/neoforge/lang/uk_ua.json index 81b3422072..da431796eb 100644 --- a/src/main/resources/assets/neoforge/lang/uk_ua.json +++ b/src/main/resources/assets/neoforge/lang/uk_ua.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "Вказаний ID виміру (%1$s) некоректний.", "commands.neoforge.setdim.invalid.nochange": "Обрана сутність (%1$s) вже у вказаному вимірі (%2$s).", "commands.neoforge.setdim.deprecated": "Ця команда застаріла і буде видалена у версії 1.17, використовуйте %s замість цього.", - "commands.neoforge.tps.invalid": "Неприпустимий вимір %1$s Можливі значення: %2$s", - "commands.neoforge.tps.summary.all": "Загалом: Середній час тіку: %1$s мс. Середній TPS: %2$s", + "commands.neoforge.tps.overall": "Загалом: %s TPS (%s мс/тік)", + "commands.neoforge.tps.tooltip": "Середній TPS; чим вище, тим краще. Цільовий TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s мс/тік)", + "commands.neoforge.tps.dimension.tooltip": "%s (Тип виміру: %s)", "commands.neoforge.mods.list": "Список модів: %1$s", - "commands.neoforge.tps.summary.basic": "Вимір %1$s: Середній час тіку: %2$s мс. Середній TPS: %3$s", - "commands.neoforge.tps.summary.named": "Вимір %1$s (%2$s): Середній час тіку: %3$s мс. Середній TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Відстеження сутностей увімкнено на %d секунд.", "commands.neoforge.tracking.entity.reset": "Данні таймінгів сутностей були очищені!", "commands.neoforge.tracking.invalid": "Невірні дані відстеження.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Час в %s тече нормально (20 хвилин на день).", "commands.neoforge.timespeed.set": "Встановіть час в %s до %sx (%s хвилин на день).", "commands.neoforge.timespeed.set.default": "Встановіть потік часу в %s за замовчуванням (20 хвилин на день).", + "commands.neoforge.data_components.list.error.held_stack_empty": "Ви не тримаєте будь-який предмет", + "commands.neoforge.data_components.list.title": "Компоненти даних на %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Компонент %s зберігає його значення за замовчуванням", + "commands.neoforge.data_components.list.tooltip.deleted": "Компонент %s зі значенням %s було видалено", + "commands.neoforge.data_components.list.tooltip.modified": "Компонент %s був змінений з %s в %s", + "commands.neoforge.data_components.list.tooltip.added": "Компонент %s був доданий зі значенням %s", "commands.config.getwithtype": "Конфіг для %s типу %s знайдена в %s", "commands.config.noconfig": "Конфіг для %s типу %s не знайдено", "neoforge.update.beta.1": "%sПОПЕРЕДЖЕННЯ: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "Серверна конфігурація %s", "neoforge.configuration.uitext.title.common": "Загальна конфігурація %s", "neoforge.configuration.uitext.title.startup": "Запускова конфігурація %s", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Налаштування тут визначаються сервером і не можуть бути змінені доки ви в мережі.", - "color": "червоний" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Налаштування тут не можуть бути відредаговані, поки ваша гра відкрита для локальної мережі. Будь ласка, поверніться до головного меню і завантажте світ ще раз.", - "color": "червоний" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Налаштування тут доступні після завантаження світу.", - "color": "червоний" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "Це значення не можна редагувати в інтерфейсі. Будь ласка, зв'яжіться з автором мода про надання користувацького інтерфейсу для нього.", - "color": "червоний" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "Це значення задовге для редагування в інтерфейсі. Будь ласка, відредагуйте його у файлі конфігурації.", - "color": "червоний" - } - ], + "neoforge.configuration.uitext.notonline": "Налаштування тут визначаються сервером і не можуть бути змінені доки ви в мережі.", + "neoforge.configuration.uitext.notlan": "Налаштування тут не можуть бути відредаговані, поки ваша гра відкрита для локальної мережі. Будь ласка, поверніться до головного меню і завантажте світ ще раз.", + "neoforge.configuration.uitext.notloaded": "Налаштування тут доступні після завантаження світу.", + "neoforge.configuration.uitext.unsupportedelement": "Це значення не можна редагувати в інтерфейсі. Будь ласка, зв'яжіться з автором мода про надання користувацького інтерфейсу для нього.", + "neoforge.configuration.uitext.longstring": "Це значення задовге для редагування в інтерфейсі. Будь ласка, відредагуйте його у файлі конфігурації.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Змінити", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "золотий", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Скасувати", "neoforge.configuration.uitext.undo.tooltip": "Повертає зміни тільки на цьому екрані.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nДіапазон: ", - "color": "сірий" - }, - { - "index": 0, - "color": "сірий" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "Файл: \"", - "color": "сірий" - }, - { - "index": 0, - "color": "сірий" - }, - { - "text": "\"", - "color": "сірий" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Загальні параметри", "neoforge.configuration.uitext.client": "Клієнтські параметри", "neoforge.configuration.uitext.server": "Серверні параметри", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "Світ має бути перезавантажений", "neoforge.configuration.uitext.restart.server.text": "Один чи кілька параметрів конфігурації, які були змінені, набудуть чинності лише після перезавантаження світу.", "neoforge.configuration.uitext.restart.return": "Ігнорувати", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Зміни не матимуть ніякого ефекту, поки ви не перезавантажитеся!", - "color": "червоний", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Зміни не матимуть ніякого ефекту, поки ви не перезавантажитеся!", "neoforge.configuration.title": "Конфігурація NeoForge", "neoforge.configuration.section.neoforge.client.toml": "Клієнтські налаштування", "neoforge.configuration.section.neoforge.client.toml.title": "Клієнтські налаштування", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Менеджер дозволів", "neoforge.configgui.permissionHandler.tooltip": "Менеджер дозволів, що використовує сервер. За замовчуванням neoforge:default_handler, коли такого обробника не зареєстровано з таким іменем.", "neoforge.configgui.removeErroringBlockEntities": "Видалити блок-сутності, які викликають помилки", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Встановіть значення \"true\", для видалення будь-якого об'єкта, що спричиняє помилки в методі оновлення, замість закриття сервера та створення журналу про аварію.\n\n", - { - "text": "УВАГА: ЦЕ МОЖЕ ПОШКОДИТИ ВСЕ.\nВИКОРИСТОВУЙТЕ ОБЕРЕЖНО.\nМИ НЕ ВІДПОВІДАЛЬНІ ЗА ПОШКОДЖЕННЯ.", - "color": "червоний", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "УВАГА: ЦЕ МОЖЕ ПОШКОДИТИ ВСЕ.\nВИКОРИСТОВУЙТЕ ОБЕРЕЖНО.\nМИ НЕ ВІДПОВІДАЛЬНІ ЗА ПОШКОДЖЕННЯ.", "neoforge.configgui.removeErroringEntities": "Видалити сутності, які викликають помилки", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Встановіть значення \"true\", для видалення будь-якого блок-сутності, що спричиняє помилки в методі оновлення, замість закриття сервера та створення журналу про аварію.\n\n", - { - "text": "УВАГА: ЦЕ МОЖЕ ПОШКОДИТИ ВСЕ.\nВИКОРИСТОВУЙТЕ ОБЕРЕЖНО.\nМИ НЕ ВІДПОВІДАЛЬНІ ЗА ПОШКОДЖЕННЯ.", - "color": "червоний", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "УВАГА: ЦЕ МОЖЕ ПОШКОДИТИ ВСЕ.\nВИКОРИСТОВУЙТЕ ОБЕРЕЖНО.\nМИ НЕ ВІДПОВІДАЛЬНІ ЗА ПОШКОДЖЕННЯ.", "neoforge.configgui.showLoadWarnings": "Показувати попередження при завантаженні", "neoforge.configgui.showLoadWarnings.tooltip": "Коли увімкнено, NeoForge покаже всі попередження, що сталися під час завантаження.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Використовувати комбінований атрибут DEPTH_STENCIL", diff --git a/src/main/resources/assets/neoforge/lang/vi_vn.json b/src/main/resources/assets/neoforge/lang/vi_vn.json index 405906c80c..f43c9088b0 100644 --- a/src/main/resources/assets/neoforge/lang/vi_vn.json +++ b/src/main/resources/assets/neoforge/lang/vi_vn.json @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", "commands.neoforge.setdim.deprecated": "This command is deprecated for removal in 1.17, use %s instead.", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", + "commands.neoforge.tps.overall": "Overall: %s TPS (%s ms/tick)", + "commands.neoforge.tps.tooltip": "Mean TPS; higher is better. Target TPS: %s", + "commands.neoforge.tps.dimension": "%s: %s TPS (%s ms/tick)", + "commands.neoforge.tps.dimension.tooltip": "%s (Dimension Type: %s)", "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", "commands.neoforge.tracking.entity.enabled": "Entity tracking enabled for %d seconds.", "commands.neoforge.tracking.entity.reset": "Entity timings data has been cleared!", "commands.neoforge.tracking.invalid": "Invalid tracking data.", @@ -115,6 +115,14 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "Config for %s of type %s found at %s", "commands.config.noconfig": "Config for %s of type %s not found", "neoforge.update.beta.1": "%sWARNING: %sNeoForge Beta", @@ -130,51 +138,15 @@ "neoforge.configuration.uitext.title.server": "%s Server Configuration", "neoforge.configuration.uitext.title.common": "%s Common Configuration", "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", "neoforge.configuration.uitext.undo": "Undo", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", @@ -184,30 +156,8 @@ "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], + "neoforge.configuration.uitext.rangetooltip": "Range: %s", + "neoforge.configuration.uitext.filenametooltip": "File: \"%s\"", "neoforge.configuration.uitext.common": "Common Options", "neoforge.configuration.uitext.client": "Client Options", "neoforge.configuration.uitext.server": "Server Options", @@ -217,13 +167,7 @@ "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], + "neoforge.configuration.uitext.restart.return.tooltip": "Your changes will have no effect until you restart!", "neoforge.configuration.title": "NeoForge Configuration", "neoforge.configuration.section.neoforge.client.toml": "Client settings", "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", @@ -246,23 +190,11 @@ "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "Remove Erroring Block Entities", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "Remove Erroring Entities", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "Show Load Warnings", "neoforge.configgui.showLoadWarnings.tooltip": "When enabled, NeoForge will show any warnings that occurred during loading.", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", diff --git a/src/main/resources/assets/neoforge/lang/zh_cn.json b/src/main/resources/assets/neoforge/lang/zh_cn.json index 24107e8cd2..0deca20fe6 100644 --- a/src/main/resources/assets/neoforge/lang/zh_cn.json +++ b/src/main/resources/assets/neoforge/lang/zh_cn.json @@ -13,7 +13,7 @@ "fml.menu.mods.info.credits": "鸣谢:%1$s", "fml.menu.mods.info.authors": "作者:%1$s", "fml.menu.mods.info.displayurl": "主页:%1$s", - "fml.menu.mods.info.license": "开源许可:%1$s", + "fml.menu.mods.info.license": "许可证:%1$s", "fml.menu.mods.info.securejardisabled": "Secure mod 功能已禁用,请更新 JDK", "fml.menu.mods.info.signature": "签名:%1$s", "fml.menu.mods.info.signature.unsigned": "未签名", @@ -21,7 +21,7 @@ "fml.menu.mods.info.trust.noauthority": "无", "fml.menu.mods.info.nochildmods": "未发现子模组", "fml.menu.mods.info.childmods": "子模组:%1$s", - "fml.menu.mods.info.updateavailable": "可用更新: %1$s", + "fml.menu.mods.info.updateavailable": "可用更新:%1$s", "fml.menu.mods.info.changelogheader": "更新日志:", "fml.menu.multiplayer.compatible": "兼容的 FML 服务器\n有 {0,choice,0<%1$s 个} 模组", "fml.menu.multiplayer.incompatible": "不兼容的 FML 模组服务器", @@ -76,11 +76,11 @@ "commands.neoforge.setdim.invalid.dim": "指定的维度 ID(%1$s)无效。", "commands.neoforge.setdim.invalid.nochange": "选定的实体(%1$s)已经在指定的维度(%2$s)中。", "commands.neoforge.setdim.deprecated": "此命令将在 1.17 中被废弃去除,请使用 %s 代替。", - "commands.neoforge.tps.invalid": "无效的维度 %1$s 可能的值:%2$s", - "commands.neoforge.tps.summary.all": "概述:平均游戏刻耗时:%1$s 毫秒。平均 TPS:%2$s", + "commands.neoforge.tps.overall": "总体:%sTPS(%s毫秒/刻)", + "commands.neoforge.tps.tooltip": "平均TPS;越高越好。目标TPS:%s", + "commands.neoforge.tps.dimension": "%s:%sTPS(%s毫秒/刻)", + "commands.neoforge.tps.dimension.tooltip": "%s(维度类型:%s)", "commands.neoforge.mods.list": "模组列表:%1$s", - "commands.neoforge.tps.summary.basic": "维度 %1$s:平均游戏刻耗时:%2$s 毫秒。平均 TPS:%3$s", - "commands.neoforge.tps.summary.named": "维度 %1$s(%2$s):平均游戏刻耗时:%3$s 毫秒。平均 TPS:%4$s", "commands.neoforge.tracking.entity.enabled": "实体跟踪已启用,时长 %d 秒。", "commands.neoforge.tracking.entity.reset": "实体计时数据已被清理!", "commands.neoforge.tracking.invalid": "无效的跟踪数据。", @@ -107,166 +107,98 @@ "commands.neoforge.chunkgen.started": "正在于 %2$sx%3$s 区块范围(%4$sx%5$s 个方块)中生成 %1$s 个区块。", "commands.neoforge.chunkgen.success": "生成完毕!", "commands.neoforge.chunkgen.error": "生成中发生了 %1$s 个错误!请检查日志以获取更多信息。", - "commands.neoforge.chunkgen.stopped": "生成已停止!已生成%2$s中的%1$s个区块(%3$s%%)。", - "commands.neoforge.chunkgen.status": "正在生成! %2$s中的%1$s个区块已生成(%3$s%%)。", + "commands.neoforge.chunkgen.stopped": "生成已停止!预定生成%2$s个区块,已生成%1$s个。(%3$s%%)", + "commands.neoforge.chunkgen.status": "生成状态!预定生成%2$s个区块,已生成%1$s个。(%3$s%%)", "commands.neoforge.chunkgen.not_running": "无进行中的预生成。运行 `/neoforge generate help` 以查看开始生成的命令。", "commands.neoforge.chunkgen.help_line": "§2/neoforge generate start [progressBar] §r§f- 生成一个以给定坐标为中心的、边长为 chunkRadius * 2 的正方形。\n§2/neoforge generate stop §r§f- 停止当前生成,显示完成进度。\n§2/neoforge generate status §r- 显示当前生成的完成进度。\n§2/neoforge generate help §r- 显示此消息\n通用提示:如果从服务器控制台执行,可以通过 '/execute in neoforge generate...' 在特定维度执行。", - "commands.neoforge.timespeed.query": "%s 以 %sx (每天%s 分钟) 的速度流动。", - "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", - "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", - "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.timespeed.query": "%s的时间以%sx的速度流逝(%s分钟每天)。", + "commands.neoforge.timespeed.query.default": "%s的时间以正常速度流逝(20分钟每天)。", + "commands.neoforge.timespeed.set": "已将%s的时间流速设为%sx(%s分钟每天)。", + "commands.neoforge.timespeed.set.default": "已将%s的时间流速设为默认值(20分钟每天)。", + "commands.neoforge.data_components.list.error.held_stack_empty": "你没有拿任何东西", + "commands.neoforge.data_components.list.title": "%s 上的数据组件:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "组件 %s 具有默认值", + "commands.neoforge.data_components.list.tooltip.deleted": "组件 %s 的值 %s 已被删除", + "commands.neoforge.data_components.list.tooltip.modified": "组件 %s 已从 %s 修改为 %s", + "commands.neoforge.data_components.list.tooltip.added": "组件 %s 添加了值 %s", "commands.config.getwithtype": "%s 类型 %s 的配置在 %s 发现", "commands.config.noconfig": "未发现 %s(类型为 %s)的配置", "neoforge.update.beta.1": "%s警告:%s NeoForge 为测试版", "neoforge.update.beta.2": "可能会出现重大问题,请在报告之前进行核实。", "neoforge.update.newversion": "新版本 NeoForge 可用:%s", "neoforge.menu.updatescreen.title": "模组更新", - "neoforge.configuration.uitext.title": "%s Configuration", - "neoforge.configuration.uitext.type.client": "Client Settings", - "neoforge.configuration.uitext.type.server": "Server Settings", - "neoforge.configuration.uitext.type.common": "Common settings", - "neoforge.configuration.uitext.type.startup": "Startup settings", - "neoforge.configuration.uitext.title.client": "%s Client Configuration", - "neoforge.configuration.uitext.title.server": "%s Server Configuration", - "neoforge.configuration.uitext.title.common": "%s Common Configuration", - "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], - "neoforge.configuration.uitext.section": "%s...", - "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], + "neoforge.configuration.uitext.title": "%s 配置", + "neoforge.configuration.uitext.type.client": "客户端设置", + "neoforge.configuration.uitext.type.server": "服务端设置", + "neoforge.configuration.uitext.type.common": "通用设置", + "neoforge.configuration.uitext.type.startup": "启动时设置", + "neoforge.configuration.uitext.title.client": "%s 客户端配置", + "neoforge.configuration.uitext.title.server": "%s 服务端配置", + "neoforge.configuration.uitext.title.common": "%s 通用配置", + "neoforge.configuration.uitext.title.startup": "%s 启动时配置", + "neoforge.configuration.uitext.notonline": "这里的设置由服务端决定,且无法在线更改。", + "neoforge.configuration.uitext.notlan": "在你的游戏已对局域网开放时,无法编辑这里的设置。请返回主菜单并再次加载世界。", + "neoforge.configuration.uitext.notloaded": "这里的设置只有在进入世界后才可用。", + "neoforge.configuration.uitext.unsupportedelement": "此值不能在UI中编辑。请联系模组作者提供自定义UI。", + "neoforge.configuration.uitext.longstring": "该值太长,无法在UI中编辑。请在配置文件中编辑它。", + "neoforge.configuration.uitext.section": "%s…", + "neoforge.configuration.uitext.sectiontext": "编辑", + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", "neoforge.configuration.uitext.listelement": "%s:", - "neoforge.configuration.uitext.undo": "Undo", - "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", - "neoforge.configuration.uitext.reset": "Reset", - "neoforge.configuration.uitext.reset.tooltip": "Reverts everything on this screen to its default value.", + "neoforge.configuration.uitext.undo": "取消", + "neoforge.configuration.uitext.undo.tooltip": "仅恢复当前的更改。", + "neoforge.configuration.uitext.reset": "重置", + "neoforge.configuration.uitext.reset.tooltip": "将此屏幕上的所有内容恢复为默认值。", "neoforge.configuration.uitext.newlistelement": "+", "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], - "neoforge.configuration.uitext.common": "Common Options", - "neoforge.configuration.uitext.client": "Client Options", - "neoforge.configuration.uitext.server": "Server Options", - "neoforge.configuration.uitext.startup": "Startup Options", - "neoforge.configuration.uitext.restart.game.title": "Minecraft needs to be restarted", - "neoforge.configuration.uitext.restart.game.text": "One or more of the configuration option that were changed will only take effect when the game is started.", - "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", - "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", - "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], - "neoforge.configuration.title": "NeoForge Configuration", - "neoforge.configuration.section.neoforge.client.toml": "Client settings", - "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", - "neoforge.configuration.section.neoforge.common.toml": "Common settings", - "neoforge.configuration.section.neoforge.common.toml.title": "Common settings", - "neoforge.configuration.section.neoforge.server.toml": "Server settings", - "neoforge.configuration.section.neoforge.server.toml.title": "Server settings", - "neoforge.configgui.advertiseDedicatedServerToLan": "Advertise Dedicated Server To LAN", - "neoforge.configgui.advertiseDedicatedServerToLan.tooltip": "Set this to true to enable advertising the dedicated server to local LAN clients so that it shows up in the Multiplayer screen automatically.", - "neoforge.configgui.forgeLightPipelineEnabled": "NeoForge Light Pipeline", + "neoforge.configuration.uitext.rangetooltip": "取值范围:%s", + "neoforge.configuration.uitext.filenametooltip": "文件:“%s”", + "neoforge.configuration.uitext.common": "通用选项", + "neoforge.configuration.uitext.client": "客户端选项", + "neoforge.configuration.uitext.server": "服务端选项", + "neoforge.configuration.uitext.startup": "启动时选项", + "neoforge.configuration.uitext.restart.game.title": "Minecraft需要重新启动", + "neoforge.configuration.uitext.restart.game.text": "一个或多个已更改的配置选项只有在下次启动游戏时才会生效。", + "neoforge.configuration.uitext.restart.server.title": "需要重新加载世界", + "neoforge.configuration.uitext.restart.server.text": "一个或多个已更改的配置选项只有在重新加载世界时才会生效。", + "neoforge.configuration.uitext.restart.return": "无视", + "neoforge.configuration.uitext.restart.return.tooltip": "在重启游戏之前,你的更改不会生效!", + "neoforge.configuration.title": "NeoForge 配置", + "neoforge.configuration.section.neoforge.client.toml": "客户端设置", + "neoforge.configuration.section.neoforge.client.toml.title": "客户端设置", + "neoforge.configuration.section.neoforge.common.toml": "通用设置", + "neoforge.configuration.section.neoforge.common.toml.title": "通用设置", + "neoforge.configuration.section.neoforge.server.toml": "服务端设置", + "neoforge.configuration.section.neoforge.server.toml.title": "服务端设置", + "neoforge.configgui.advertiseDedicatedServerToLan": "向局域网开放服务器", + "neoforge.configgui.advertiseDedicatedServerToLan.tooltip": "将此设置为true以启用向本地局域网客户端开放服务器,以便它自动显示在多人游戏屏幕中。", + "neoforge.configgui.forgeLightPipelineEnabled": "NeoForge 光照管线", "neoforge.configgui.forgeLightPipelineEnabled.tooltip": "启用 NeoForge 方块渲染管线 - 修复自定义模型的光照问题。", "neoforge.configgui.fullBoundingBoxLadders": "梯子使用完整实体碰撞箱", "neoforge.configgui.fullBoundingBoxLadders.tooltip": "将此项设置为true,以使梯子检查整个实体的碰撞箱,而不仅仅是它们所处的方块。这将导致明显的机制差异,因此默认使用原版行为。默认:false。", - "neoforge.configgui.logLegacyTagWarnings": "Log Legacy Tags", - "neoforge.configgui.logLegacyTagWarnings.tooltip": "A config option mainly for developers. Logs out modded tags that are using the 'forge' namespace when running on integrated server. Defaults to DEV_SHORT.", - "neoforge.configgui.logUntranslatedConfigurationWarnings": "Log Untranslated Configuration Keys", - "neoforge.configgui.logUntranslatedConfigurationWarnings.tooltip": "A config option mainly for developers. Logs out configuration values that do not have translations when running a client in a development environment.", - "neoforge.configgui.logUntranslatedItemTagWarnings": "Log Untranslated Item Tags", - "neoforge.configgui.logUntranslatedItemTagWarnings.tooltip": "A config option mainly for developers. Logs out modded item tags that do not have translations when running on integrated server. Format desired is tag.item.. for the translation key. Defaults to SILENCED.", - "neoforge.configgui.permissionHandler": "Permission Handler", - "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", + "neoforge.configgui.logLegacyTagWarnings": "记录旧标签", + "neoforge.configgui.logLegacyTagWarnings.tooltip": "一个主要面向开发者的配置选项。在内置服务端上运行时,在日志中记录那些使用“forge”命名空间的模组环境标签。默认值为DEV_SHORT。", + "neoforge.configgui.logUntranslatedConfigurationWarnings": "记录未翻译的配置键", + "neoforge.configgui.logUntranslatedConfigurationWarnings.tooltip": "一个主要面向开发者的配置选项。在开发环境中运行客户端时,在日志中记录没有翻译的配置值。", + "neoforge.configgui.logUntranslatedItemTagWarnings": "记录未翻译的物品标签", + "neoforge.configgui.logUntranslatedItemTagWarnings.tooltip": "一个主要面向开发者的配置选项。在内置服务端上运行时,在日志中记录没有翻译的模组环境物品标签。翻译键要求的格式是tag.item.<命名空间>.<路径>。默认值为SILENCED。", + "neoforge.configgui.permissionHandler": "权限处理", + "neoforge.configgui.permissionHandler.tooltip": "服务器使用的权限处理程序。如果没有注册这样的处理程序,默认为neoforge:default_handler。", "neoforge.configgui.removeErroringBlockEntities": "删除错误方块实体", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "开启此项后,游戏会移除任何在更新方法中出现错误的方块实体,而不是关闭服务端并报告崩溃日志。", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "请注意,这可能会把一切搞砸。\n尽量少使用。\n我们不对损坏负责。", "neoforge.configgui.removeErroringEntities": "删除错误实体", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "开启此项后,游戏会移除任何在更新方法中出现错误的实体,而不是关闭服务端并报告崩溃日志。", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "请注意,这可能会把一切搞砸。\n尽量少使用。\n我们不对损坏负责。", "neoforge.configgui.showLoadWarnings": "显示加载警告", "neoforge.configgui.showLoadWarnings.tooltip": "如果启用,NeoForge 将显示加载过程中出现的任何警告。", - "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", - "neoforge.configgui.useCombinedDepthStencilAttachment.tooltip": "Set to true to use a combined DEPTH_STENCIL attachment instead of two separate ones.", + "neoforge.configgui.useCombinedDepthStencilAttachment": "使用组合DEPTH_STENCIL附件", + "neoforge.configgui.useCombinedDepthStencilAttachment.tooltip": "设置为true将使用组合的DEPTH_STENCIL附件而不是两个单独的附件。", "neoforge.controlsgui.shift": "SHIFT + %s", "neoforge.controlsgui.control": "CTRL + %s", "neoforge.controlsgui.control.mac": "CMD + %s", @@ -309,7 +241,7 @@ "neoforge.network.data_maps.failed": "处理注册表数据映射同步失败 %s: %s", "neoforge.network.data_maps.missing_our": "无法连接至服务器,因为客户端缺少必要的注册表数据映射:%s", "neoforge.network.data_maps.missing_their": "无法连接至服务器,因为客户端上不存在必要的注册表数据映射:%s", - "neoforge.network.extensible_enums.no_vanilla_server": "This client does not support vanilla servers as it has extended enums used in serverbound networking", - "neoforge.network.extensible_enums.enum_set_mismatch": "The set of extensible enums on the client and server do not match. Make sure you are using the same NeoForge version as the server", - "neoforge.network.extensible_enums.enum_entry_mismatch": "The set of values added to extensible enums on the client and server do not match. Make sure you are using the same mod and NeoForge versions as the server. See the log for more details" + "neoforge.network.extensible_enums.no_vanilla_server": "该客户端不支持原版服务器,因为它在服务器端网络中使用了不同连接方式。", + "neoforge.network.extensible_enums.enum_set_mismatch": "客户端和服务器上的模组不匹配。请确保您使用的 NeoForge 版本与服务器上的版本相同。", + "neoforge.network.extensible_enums.enum_entry_mismatch": "客户端和服务器上所需要的模组不匹配。请确保您使用的模组和 NeoForge 版本与服务器上的版本相同。请查看日志以获取更多详细信息。" } diff --git a/src/main/resources/assets/neoforge/lang/zh_hk.json b/src/main/resources/assets/neoforge/lang/zh_tw.json similarity index 64% rename from src/main/resources/assets/neoforge/lang/zh_hk.json rename to src/main/resources/assets/neoforge/lang/zh_tw.json index e3a39d17ba..2f1eab530d 100644 --- a/src/main/resources/assets/neoforge/lang/zh_hk.json +++ b/src/main/resources/assets/neoforge/lang/zh_tw.json @@ -8,43 +8,43 @@ "fml.menu.mods.config": "設定", "fml.menu.mods.openmodsfolder": "開啟模組資料夾", "fml.menu.modoptions": "模組選項...", - "fml.menu.mods.info.version": "Version: %1$s", - "fml.menu.mods.info.idstate": "ModID: %1$s State: {1,lower}", - "fml.menu.mods.info.credits": "Credits: %1$s", - "fml.menu.mods.info.authors": "Authors: %1$s", - "fml.menu.mods.info.displayurl": "Homepage: %1$s", - "fml.menu.mods.info.license": "License: %1$s", + "fml.menu.mods.info.version": "版本:%1$s", + "fml.menu.mods.info.idstate": "模組 ID:%1$s 狀態:{1,lower}", + "fml.menu.mods.info.credits": "鳴謝:%1$s", + "fml.menu.mods.info.authors": "作者:%1$s", + "fml.menu.mods.info.displayurl": "首頁:%1$s", + "fml.menu.mods.info.license": "授權條款:%1$s", "fml.menu.mods.info.securejardisabled": "安全模組功能已被停用,請更新 JDK", - "fml.menu.mods.info.signature": "Signature: %1$s", + "fml.menu.mods.info.signature": "簽章:%1$s", "fml.menu.mods.info.signature.unsigned": "未簽署", - "fml.menu.mods.info.trust": "Trust: %1$s", + "fml.menu.mods.info.trust": "信任:%1$s", "fml.menu.mods.info.trust.noauthority": "無", "fml.menu.mods.info.nochildmods": "未發現子模組", - "fml.menu.mods.info.childmods": "Child mods: %1$s", - "fml.menu.mods.info.updateavailable": "Update available: %1$s", - "fml.menu.mods.info.changelogheader": "更新日誌:", - "fml.menu.multiplayer.compatible": "Compatible FML modded server\n{0,choice,1#1 mod|1<%1$s mods} present", + "fml.menu.mods.info.childmods": "子模組:%1$s", + "fml.menu.mods.info.updateavailable": "有更新可用:%1$s", + "fml.menu.mods.info.changelogheader": "變更紀錄:", + "fml.menu.multiplayer.compatible": "相容的 FML 模組伺服器\n已安裝 {0,choice,1#1 mod|1<%1$s mods} 個模組", "fml.menu.multiplayer.incompatible": "不相容 FML 模組伺服器", - "fml.menu.multiplayer.incompatible.extra": "Incompatible FML modded server\n%1$s", + "fml.menu.multiplayer.incompatible.extra": "不相容 FML 模組伺服器\n%1$s", "fml.menu.multiplayer.truncated": "由於協定大小限制,資料可能不準確。", "fml.menu.multiplayer.vanilla": "原版伺服器", "fml.menu.multiplayer.vanilla.incompatible": "不相容的原版伺服器", - "fml.menu.multiplayer.unknown": "Unknown server %1$s", + "fml.menu.multiplayer.unknown": "未知的伺服器 %1$s", "fml.menu.multiplayer.serveroutdated": "NeoForge 伺服器端網路版本太舊", "fml.menu.multiplayer.clientoutdated": "NeoForge 用戶端網路版本太舊", - "fml.menu.multiplayer.extraservermods": "伺服器有客戶端可能需要的附加模組", + "fml.menu.multiplayer.extraservermods": "伺服器有用戶端可能需要的額外模組", "fml.menu.multiplayer.modsincompatible": "伺服器模組清單不相容", "fml.menu.multiplayer.networkincompatible": "伺服器網路訊息清單不相容", - "fml.menu.multiplayer.missingdatapackregistries": "Missing required datapack registries: %1$s", - "fml.menu.branding": "%s (%s mods)", + "fml.menu.multiplayer.missingdatapackregistries": "缺少所需資料包登錄:%1$s", + "fml.menu.branding": "%s(%s 個模組)", "fml.menu.notification.title": "啟動提醒", - "fml.menu.accessdenied.title": "伺服器存取被拒絕", - "fml.menu.accessdenied.message": "Fancy Mod Loader could not connect to this server\nThe server %1$s has forbidden modded access", + "fml.menu.accessdenied.title": "伺服器存取被拒", + "fml.menu.accessdenied.message": "Fancy Mod Loader 無法連線到此伺服器\n伺服器 %1$s 禁止模組存取", "fml.menu.backupfailed.title": "備份失敗", - "fml.menu.backupfailed.message": "There was an error saving the archive %1$s\nPlease fix the problem and try again", - "fml.button.open.file": "Open %1$s", - "fml.button.open.log": "Open log file", - "fml.button.open.crashreport": "Open crash report", + "fml.menu.backupfailed.message": "儲存存檔 %1$s 時發生錯誤\n請修正這個問題,然後再試一次", + "fml.button.open.file": "開啟 %1$s", + "fml.button.open.log": "開啟記錄檔", + "fml.button.open.crashreport": "開啟崩潰報告", "fml.button.open.mods.folder": "開啟模組資料夾", "fml.button.continue.launch": "繼續前往標題畫面", "fml.modmismatchscreen.missingmods.client": "您的用戶端缺少下列模組,請安裝這些模組以加入此伺服器:", @@ -54,33 +54,33 @@ "fml.modmismatchscreen.table.youneed": "你需要", "fml.modmismatchscreen.table.youhave": "你擁有", "fml.modmismatchscreen.table.serverhas": "伺服器已安裝", - "fml.modmismatchscreen.additional": "[%1$s additional, see latest.log for the full list]", + "fml.modmismatchscreen.additional": "[還有 %1$s 個,查看 latest.log 取得完整清單]", "fml.modmismatchscreen.homepage": "點擊以前往這個模組的主頁", "fml.modmismatchscreen.table.reason": "原因", "fml.modmismatchscreen.table.visit.mod_page": "開啟登錄此頻道的模組(%s)頁面", - "fml.modmismatchscreen.simplifiedview": "Simplified view", - "fml.resources.modresources": "Resources for %1$s mod files", - "fml.resources.moddata": "Data for %1$s mod files", + "fml.modmismatchscreen.simplifiedview": "簡化檢視", + "fml.resources.modresources": "用於 %1$s 模組檔案的資源", + "fml.resources.moddata": "%1$s 模組檔案資料", "loadwarning.neoforge.prbuild": "這個 NeoForge 由社群成員建立,是 §c§l不受支援§r 的", - "commands.neoforge.arguments.enum.invalid": "Enum constant must be one of %1$s, found %2$s", + "commands.neoforge.arguments.enum.invalid": "枚舉常數必須是 %1$s 之一,找到 %2$s", "commands.neoforge.dimensions.list": "目前依照類型註冊的維度:", - "commands.neoforge.dump.success": "New file created with %s registry's contents is at %s", - "commands.neoforge.dump.failure": "Failed to create new file with %s registry's contents at %s", + "commands.neoforge.dump.success": "新建立的 %s 註冊檔案位於 %s", + "commands.neoforge.dump.failure": "無法建立 %s 註冊檔案於 %s", "commands.neoforge.dump.error.unknown_registry": "未知註冊表 '%s'", "commands.neoforge.entity.list.invalid": "無效的篩選器,與任何實體不相符。請使用 /neoforge entity list 以提供正確清單", - "commands.neoforge.entity.list.invalidworld": "Could not load world for dimension %1$s. Please select a valid dimension.", + "commands.neoforge.entity.list.invalidworld": "無法載入維度 %1$s 的世界。請選擇一個有效的維度。", "commands.neoforge.entity.list.none": "找不到實體。", - "commands.neoforge.entity.list.single.header": "Entity: %1$s Total: %2$s", - "commands.neoforge.entity.list.multiple.header": "Total: %1$s", - "commands.neoforge.setdim.invalid.entity": "The entity selected (%1$s) is not valid.", - "commands.neoforge.setdim.invalid.dim": "The dimension ID specified (%1$s) is not valid.", - "commands.neoforge.setdim.invalid.nochange": "The entity selected (%1$s) is already in the dimension specified (%2$s).", - "commands.neoforge.setdim.deprecated": "此指令以在 1.17 中被棄用,請使用 %s 代替。", - "commands.neoforge.tps.invalid": "Invalid dimension %1$s Possible values: %2$s", - "commands.neoforge.tps.summary.all": "Overall: Mean tick time: %1$s ms. Mean TPS: %2$s", - "commands.neoforge.mods.list": "Mod List: %1$s", - "commands.neoforge.tps.summary.basic": "Dim %1$s: Mean tick time: %2$s ms. Mean TPS: %3$s", - "commands.neoforge.tps.summary.named": "Dim %1$s (%2$s): Mean tick time: %3$s ms. Mean TPS: %4$s", + "commands.neoforge.entity.list.single.header": "實體:%1$s 總共:%2$s", + "commands.neoforge.entity.list.multiple.header": "總共:%1$s", + "commands.neoforge.setdim.invalid.entity": "所選實體 (%1$s) 無效。", + "commands.neoforge.setdim.invalid.dim": "指定的維度 ID (%1$s) 無效。", + "commands.neoforge.setdim.invalid.nochange": "所選實體 (%1$s) 已存在於指定的維度 (%2$s) 中。", + "commands.neoforge.setdim.deprecated": "這個指令已在 1.17 中被棄用,請使用 %s 代替。", + "commands.neoforge.tps.overall": "總體:%s TPS(%s 毫秒/刻)", + "commands.neoforge.tps.tooltip": "平均 TPS;數值越高越好。目標 TPS:%s", + "commands.neoforge.tps.dimension": "%s:%s TPS(%s 毫秒/刻)", + "commands.neoforge.tps.dimension.tooltip": "%s(維度類型:%s)", + "commands.neoforge.mods.list": "模組清單:%1$s", "commands.neoforge.tracking.entity.enabled": "實體追踪已啟用,時長 %d 秒。", "commands.neoforge.tracking.entity.reset": "實體計時資料已被清除!", "commands.neoforge.tracking.invalid": "無效的追蹤資料", @@ -101,8 +101,8 @@ "commands.neoforge.tags.element": "%s:%s", "commands.neoforge.tags.page_info": "%s ", "commands.neoforge.chunkgen.progress_bar_title": "正在生成區塊...", - "commands.neoforge.chunkgen.progress_bar_progress": "Generating %1$s chunks - ", - "commands.neoforge.chunkgen.progress_bar_errors": "(%1$s errors!)", + "commands.neoforge.chunkgen.progress_bar_progress": "正在生成 %1$s 個區塊 ", + "commands.neoforge.chunkgen.progress_bar_errors": "(%1$s 個錯誤!)", "commands.neoforge.chunkgen.already_running": "生成已在進行。請先執行 '/neoforge generate stop' 再開始新生成。", "commands.neoforge.chunkgen.started": "Generating %1$s chunks, in an area of %2$sx%3$s chunks (%4$sx%5$s blocks).", "commands.neoforge.chunkgen.success": "生成完畢!", @@ -115,154 +115,86 @@ "commands.neoforge.timespeed.query.default": "Time in %s flows normally (20 minutes per day).", "commands.neoforge.timespeed.set": "Set flow of time in %s to %sx (%s minutes per day).", "commands.neoforge.timespeed.set.default": "Set flow of time in %s to default (20 minutes per day).", + "commands.neoforge.data_components.list.error.held_stack_empty": "You are not holding any item", + "commands.neoforge.data_components.list.title": "Data components on %s:", + "commands.neoforge.data_components.list.entry": "\n - %s", + "commands.neoforge.data_components.list.entry.key_value": "%s: %s", + "commands.neoforge.data_components.list.tooltip.default": "Component %s holds its default value", + "commands.neoforge.data_components.list.tooltip.deleted": "Component %s with value %s was deleted", + "commands.neoforge.data_components.list.tooltip.modified": "Component %s was modified from %s to %s", + "commands.neoforge.data_components.list.tooltip.added": "Component %s was added with value %s", "commands.config.getwithtype": "%s 類型 %s 的配置在 %s 發現", "commands.config.noconfig": "%s 類型 %s 的配置未發現", "neoforge.update.beta.1": "%s警告:%s NeoForge 為測試版", "neoforge.update.beta.2": "可能會出現重大問題,請在回報問題之前進行核實。", "neoforge.update.newversion": "最新 NeoForge 版本可用:%s", "neoforge.menu.updatescreen.title": "模組更新", - "neoforge.configuration.uitext.title": "%s Configuration", - "neoforge.configuration.uitext.type.client": "Client Settings", - "neoforge.configuration.uitext.type.server": "Server Settings", - "neoforge.configuration.uitext.type.common": "Common settings", - "neoforge.configuration.uitext.type.startup": "Startup settings", - "neoforge.configuration.uitext.title.client": "%s Client Configuration", - "neoforge.configuration.uitext.title.server": "%s Server Configuration", - "neoforge.configuration.uitext.title.common": "%s Common Configuration", - "neoforge.configuration.uitext.title.startup": "%s Startup Configuration", - "neoforge.configuration.uitext.notonline": [ - { - "text": "Settings in here are determined by the server and cannot be changed while online.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notlan": [ - { - "text": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", - "color": "red" - } - ], - "neoforge.configuration.uitext.notloaded": [ - { - "text": "Settings in here are only available while a world is loaded.", - "color": "red" - } - ], - "neoforge.configuration.uitext.unsupportedelement": [ - { - "text": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", - "color": "red" - } - ], - "neoforge.configuration.uitext.longstring": [ - { - "text": "This value is too long to be edited in the UI. Please edit it in the config file.", - "color": "red" - } - ], + "neoforge.configuration.uitext.title": "%s 設定", + "neoforge.configuration.uitext.type.client": "用戶端設定", + "neoforge.configuration.uitext.type.server": "伺服器端設定", + "neoforge.configuration.uitext.type.common": "一般設定", + "neoforge.configuration.uitext.type.startup": "啟動設定", + "neoforge.configuration.uitext.title.client": "%s 用戶端設定", + "neoforge.configuration.uitext.title.server": "%s 伺服器端設定", + "neoforge.configuration.uitext.title.common": "%s 一般設定", + "neoforge.configuration.uitext.title.startup": "%s 啟動設定", + "neoforge.configuration.uitext.notonline": "Settings in here are determined by the server and cannot be changed while online.", + "neoforge.configuration.uitext.notlan": "Settings in here cannot be edited while your game is open to LAN. Please return to the main menu and load the world again.", + "neoforge.configuration.uitext.notloaded": "Settings in here are only available while a world is loaded.", + "neoforge.configuration.uitext.unsupportedelement": "This value cannot be edited in the UI. Please contact the mod author about providing a custom UI for it.", + "neoforge.configuration.uitext.longstring": "This value is too long to be edited in the UI. Please edit it in the config file.", "neoforge.configuration.uitext.section": "%s...", - "neoforge.configuration.uitext.sectiontext": "Edit", - "neoforge.configuration.uitext.breadcrumb": [ - { - "index": 0 - }, - { - "text": " > ", - "color": "gold", - "bold": true - }, - { - "index": 1 - } - ], - "neoforge.configuration.uitext.listelement": "%s:", - "neoforge.configuration.uitext.undo": "Undo", + "neoforge.configuration.uitext.sectiontext": "編輯", + "neoforge.configuration.uitext.breadcrumb.order": "%1$s %2$s %3$s", + "neoforge.configuration.uitext.breadcrumb.separator": ">", + "neoforge.configuration.uitext.listelement": "%s:", + "neoforge.configuration.uitext.undo": "取消復原", "neoforge.configuration.uitext.undo.tooltip": "Reverts changes on this screen only.", - "neoforge.configuration.uitext.reset": "Reset", + "neoforge.configuration.uitext.reset": "重設", "neoforge.configuration.uitext.reset.tooltip": "Reverts everything on this screen to its default value.", "neoforge.configuration.uitext.newlistelement": "+", "neoforge.configuration.uitext.listelementup": "⏶", "neoforge.configuration.uitext.listelementdown": "⏷", "neoforge.configuration.uitext.listelementremove": "❌", - "neoforge.configuration.uitext.rangetooltip": [ - { - "text": "\n\nRange: ", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - } - ], - "neoforge.configuration.uitext.filenametooltip": [ - { - "text": "File: \"", - "color": "gray" - }, - { - "index": 0, - "color": "gray" - }, - { - "text": "\"", - "color": "gray" - } - ], - "neoforge.configuration.uitext.common": "Common Options", - "neoforge.configuration.uitext.client": "Client Options", - "neoforge.configuration.uitext.server": "Server Options", - "neoforge.configuration.uitext.startup": "Startup Options", - "neoforge.configuration.uitext.restart.game.title": "Minecraft needs to be restarted", + "neoforge.configuration.uitext.rangetooltip": "範圍:%s", + "neoforge.configuration.uitext.filenametooltip": "檔案:\"%s\"", + "neoforge.configuration.uitext.common": "一般選項", + "neoforge.configuration.uitext.client": "用戶端選項", + "neoforge.configuration.uitext.server": "伺服器端選項", + "neoforge.configuration.uitext.startup": "啟動選項", + "neoforge.configuration.uitext.restart.game.title": "Minecraft 需要重新啟動", "neoforge.configuration.uitext.restart.game.text": "One or more of the configuration option that were changed will only take effect when the game is started.", - "neoforge.configuration.uitext.restart.server.title": "World needs to be reloaded", + "neoforge.configuration.uitext.restart.server.title": "世界需要重新載入", "neoforge.configuration.uitext.restart.server.text": "One or more of the configuration option that were changed will only take effect when the world is reloaded.", - "neoforge.configuration.uitext.restart.return": "Ignore", - "neoforge.configuration.uitext.restart.return.tooltip": [ - { - "text": "Your changes will have no effect until you restart!", - "color": "red", - "bold": true - } - ], - "neoforge.configuration.title": "NeoForge Configuration", - "neoforge.configuration.section.neoforge.client.toml": "Client settings", - "neoforge.configuration.section.neoforge.client.toml.title": "Client settings", - "neoforge.configuration.section.neoforge.common.toml": "Common settings", - "neoforge.configuration.section.neoforge.common.toml.title": "Common settings", - "neoforge.configuration.section.neoforge.server.toml": "Server settings", - "neoforge.configuration.section.neoforge.server.toml.title": "Server settings", + "neoforge.configuration.uitext.restart.return": "忽略", + "neoforge.configuration.uitext.restart.return.tooltip": "你的變更將於重啟遊戲後生效!", + "neoforge.configuration.title": "NeoForge 設定", + "neoforge.configuration.section.neoforge.client.toml": "用戶端設定", + "neoforge.configuration.section.neoforge.client.toml.title": "用戶端設定", + "neoforge.configuration.section.neoforge.common.toml": "一般設定", + "neoforge.configuration.section.neoforge.common.toml.title": "一般設定", + "neoforge.configuration.section.neoforge.server.toml": "伺服器端設定", + "neoforge.configuration.section.neoforge.server.toml.title": "伺服器端設定", "neoforge.configgui.advertiseDedicatedServerToLan": "Advertise Dedicated Server To LAN", "neoforge.configgui.advertiseDedicatedServerToLan.tooltip": "Set this to true to enable advertising the dedicated server to local LAN clients so that it shows up in the Multiplayer screen automatically.", "neoforge.configgui.forgeLightPipelineEnabled": "NeoForge Light Pipeline", "neoforge.configgui.forgeLightPipelineEnabled.tooltip": "啟用 NeoForge 方塊繪製管線 - 修復自訂模型的光照問題。", "neoforge.configgui.fullBoundingBoxLadders": "全邊界框梯子", - "neoforge.configgui.fullBoundingBoxLadders.tooltip": "將此設為 true 可以檢查整個實體的碰撞邊界框以尋找梯子,而不僅僅是它們所在的方塊。這會導致遊戲機制有明顯的不同,因此預設值是遵循原版的遊戲行為。預設值:false。", - "neoforge.configgui.logLegacyTagWarnings": "Log Legacy Tags", + "neoforge.configgui.fullBoundingBoxLadders.tooltip": "將這項選項設為 true 可以檢查整個實體的碰撞邊界框以尋找梯子,而不僅僅是它們所在的方塊。這會導致遊戲機制有明顯的不同,因此預設值是遵循原版的遊戲行為。預設值:false。", + "neoforge.configgui.logLegacyTagWarnings": "記錄舊版標籤", "neoforge.configgui.logLegacyTagWarnings.tooltip": "A config option mainly for developers. Logs out modded tags that are using the 'forge' namespace when running on integrated server. Defaults to DEV_SHORT.", - "neoforge.configgui.logUntranslatedConfigurationWarnings": "Log Untranslated Configuration Keys", + "neoforge.configgui.logUntranslatedConfigurationWarnings": "記錄未翻譯的設定鍵", "neoforge.configgui.logUntranslatedConfigurationWarnings.tooltip": "A config option mainly for developers. Logs out configuration values that do not have translations when running a client in a development environment.", - "neoforge.configgui.logUntranslatedItemTagWarnings": "Log Untranslated Item Tags", + "neoforge.configgui.logUntranslatedItemTagWarnings": "記錄未翻譯的物品標籤", "neoforge.configgui.logUntranslatedItemTagWarnings.tooltip": "A config option mainly for developers. Logs out modded item tags that do not have translations when running on integrated server. Format desired is tag.item.. for the translation key. Defaults to SILENCED.", "neoforge.configgui.permissionHandler": "Permission Handler", "neoforge.configgui.permissionHandler.tooltip": "The permission handler used by the server. Defaults to neoforge:default_handler if no such handler with that name is registered.", "neoforge.configgui.removeErroringBlockEntities": "移除錯誤方塊實體", - "neoforge.configgui.removeErroringBlockEntities.tooltip": [ - "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringBlockEntities.tooltip": "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringBlockEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.removeErroringEntities": "移除錯誤實體", - "neoforge.configgui.removeErroringEntities.tooltip": [ - "Set this to true to remove any BlockEntity that throws an error in its update method instead of closing the server and reporting a crash log.\n\n", - { - "text": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", - "color": "red", - "bold": true - } - ], + "neoforge.configgui.removeErroringEntities.tooltip": "Set this to true to remove any Entity that throws an error in its update method instead of closing the server and reporting a crash log.", + "neoforge.configgui.removeErroringEntities.tooltip.warning": "BE WARNED THIS COULD SCREW UP EVERYTHING.\nUSE SPARINGLY.\nWE ARE NOT RESPONSIBLE FOR DAMAGES.", "neoforge.configgui.showLoadWarnings": "顯示加載警告", "neoforge.configgui.showLoadWarnings.tooltip": "若啟用,NeoForge 將顯示在載入過程中發生的任何警告。", "neoforge.configgui.useCombinedDepthStencilAttachment": "Use combined DEPTH_STENCIL Attachment", @@ -274,7 +206,7 @@ "neoforge.container.enchant.limitedEnchantability": "有限可附魔性", "neoforge.swim_speed": "游泳速度", "neoforge.name_tag_distance": "命名牌顯示距離", - "neoforge.creative_flight": "Creative Flight", + "neoforge.creative_flight": "創造模式飛行", "fluid_type.minecraft.milk": "奶", "fluid_type.minecraft.flowing_milk": "奶", "neoforge.froge.warningScreen.title": "NeoForge 快照提醒", diff --git a/src/main/resources/coremods/add_bouncer_method.js b/src/main/resources/coremods/add_bouncer_method.js deleted file mode 100644 index b4a25494dd..0000000000 --- a/src/main/resources/coremods/add_bouncer_method.js +++ /dev/null @@ -1,44 +0,0 @@ -var ASMAPI = Java.type('net.neoforged.coremod.api.ASMAPI') -var Opcodes = Java.type('org.objectweb.asm.Opcodes') -var MethodNode = Java.type('org.objectweb.asm.tree.MethodNode') -var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode') -var MethodInsnNode = Java.type('org.objectweb.asm.tree.MethodInsnNode') -var InsnNode = Java.type('org.objectweb.asm.tree.InsnNode') - -function initializeCoreMod() { - return { - "getLanguage_bouncer": addBouncer("net.minecraft.network.play.client.CClientSettingsPacket", "func_149524_c", "getLanguage", "()Ljava/lang/String;"), - } -} - -function addBouncer(className, conflictedName, expectedName, descriptor, signature) { - if (signature == null) - signature = descriptor; - return { - 'target': { - 'type': 'CLASS', - 'name': className - }, - 'transformer': function(node) { - var mappedName = ASMAPI.mapMethod(conflictedName); - if (mappedName == expectedName) - return node; // No work to do! - - var method = new MethodNode( - /* access = */ Opcodes.ACC_PUBLIC, - /* name = */ expectedName, - /* descriptor = */ descriptor, - /* signature = */ signature, - /* exceptions = */ null - ); - - method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); /*this*/ - method.instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, className.replaceAll("\\.","/"), mappedName, descriptor)); - method.instructions.add(new InsnNode(Opcodes.ARETURN)); - - node.methods.add(method); - - return node; - } - } -} \ No newline at end of file diff --git a/src/main/resources/coremods/field_to_instanceof.js b/src/main/resources/coremods/field_to_instanceof.js deleted file mode 100644 index b7a12fa546..0000000000 --- a/src/main/resources/coremods/field_to_instanceof.js +++ /dev/null @@ -1,58 +0,0 @@ -var ASMAPI = Java.type('net.neoforged.coremod.api.ASMAPI') -var Opcodes = Java.type('org.objectweb.asm.Opcodes') - -function initializeCoreMod() { - var data = ASMAPI.loadData('coremods/field_to_instanceof.json') - //ASMAPI.log('DEBUG', JSON.stringify(data, null, 2)) - - var ret = {} - for (name in data) { - addTargets(ret, name, data[name]) - } - return ret -} - -function addTargets(ret, name, data) { - var owner = data.cls - var field = ASMAPI.mapField(data.name) - var replacement = data.replacement - for (x = 0; x < data.targets.length; x++) { - var key = name + '.' + x - var entry = data.targets[x] - - //ASMAPI.log('DEBUG', 'Entry ' + key + ' ' + JSON.stringify(entry)) - - ret[key] = { - 'target': { - 'type': 'METHOD', - 'class': entry.owner, - 'methodName': entry.name, - 'methodDesc': entry.desc - }, - 'transformer': function(entry) { return function(node) { - return transform(node, entry.owner, owner, field, replacement) - }}(entry) // We have to do this annoying double function imediate call, so that JS will capture the entry value - } - } -} - -function transform(node, parent, owner, field, replacement) { - var count = 0 - var last = null - for (x = 0; x < node.instructions.size(); x++) { - var current = node.instructions.get(x) - if (current.getOpcode() == Opcodes.IF_ACMPEQ || current.getOpcode() == Opcodes.IF_ACMPNE) { - if (last != null && (last.getOpcode() == Opcodes.GETSTATIC || last.getOpcode() == Opcodes.GETFIELD)) { - if (last.owner.equals(owner) && last.name.equals(field)) { - node.instructions.set(last, new org.objectweb.asm.tree.TypeInsnNode(Opcodes.INSTANCEOF, replacement)) - node.instructions.set(current, new org.objectweb.asm.tree.JumpInsnNode(current.getOpcode() == Opcodes.IF_ACMPEQ ? Opcodes.IFNE: Opcodes.IFEQ, current.label)) - count++ - } - } - } - last = current - } - //ASMAPI.log('DEBUG', 'Transforming: ' + parent + '.' + node.name + node.desc) - //ASMAPI.log('DEBUG', 'field_to_instance: Replaced {} checks', count) - return node -} diff --git a/src/main/resources/coremods/field_to_instanceof.json b/src/main/resources/coremods/field_to_instanceof.json deleted file mode 100644 index 544b7b4ddd..0000000000 --- a/src/main/resources/coremods/field_to_instanceof.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - -} \ No newline at end of file diff --git a/src/main/resources/coremods/field_to_method.js b/src/main/resources/coremods/field_to_method.js deleted file mode 100644 index 98f4d556ba..0000000000 --- a/src/main/resources/coremods/field_to_method.js +++ /dev/null @@ -1,40 +0,0 @@ -var ASMAPI = Java.type('net.neoforged.coremod.api.ASMAPI') - -// If you add or remove a new field, -// please also add or remove a corresponding comment in the source code, -// in the interest of modders reading it. -function initializeCoreMod() { - return { - 'biome': { - 'target': { - 'type': 'CLASS', - 'name': 'net.minecraft.world.level.biome.Biome' - }, - 'transformer': function(classNode) { - ASMAPI.redirectFieldToMethod(classNode, 'climateSettings', 'getModifiedClimateSettings') - ASMAPI.redirectFieldToMethod(classNode, 'specialEffects', 'getModifiedSpecialEffects') - return classNode; - } - }, - 'structure': { - 'target': { - 'type': 'CLASS', - 'name': 'net.minecraft.world.level.levelgen.structure.Structure' - }, - 'transformer': function(classNode) { - ASMAPI.redirectFieldToMethod(classNode, 'settings', 'getModifiedStructureSettings') - return classNode; - } - }, - 'flowerpotblock': { - 'target': { - 'type': 'CLASS', - 'name': 'net.minecraft.world.level.block.FlowerPotBlock' - }, - 'transformer': function(classNode) { - ASMAPI.redirectFieldToMethod(classNode, 'potted', 'getPotted') // flower - return classNode; - } - } - } -} diff --git a/src/main/resources/coremods/method_redirector.js b/src/main/resources/coremods/method_redirector.js deleted file mode 100644 index 80417a48ee..0000000000 --- a/src/main/resources/coremods/method_redirector.js +++ /dev/null @@ -1,77 +0,0 @@ -var ASMAPI = Java.type('net.neoforged.coremod.api.ASMAPI'); -var Opcodes = Java.type('org.objectweb.asm.Opcodes'); -var Handle = Java.type('org.objectweb.asm.Handle'); -var MethodInsnNode = Java.type('org.objectweb.asm.tree.MethodInsnNode'); - -function finalizeSpawnNode(node){ - return new MethodInsnNode( - Opcodes.INVOKESTATIC, - "net/neoforged/neoforge/event/EventHooks", - "finalizeMobSpawn", - "(Lnet/minecraft/world/entity/Mob;Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/MobSpawnType;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;", - false); -} - -function contains(list, target) { - for(var i = 0; i < list.length; i++) { - if(list[i] == target) return true; - } - return false; -} - -function search(className, node, replacements) { - for(var i = 0; i < replacements.length; i++){ - var r = replacements[i]; - if(contains(r.targets, className) && node.getOpcode() == r.opcode && node.name == r.name && node.desc == r.desc) { - return r; - } - } - return null; -} - -var replacements = [ - { - 'opcode': Opcodes.INVOKEVIRTUAL, - 'name': 'finalizeSpawn', - 'desc': '(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/MobSpawnType;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;', - 'targets': 'coremods/finalize_spawn_targets.json', - 'factory': finalizeSpawnNode - } -]; - -function initializeCoreMod() { - var mergedTargets = []; - for(var i = 0; i < replacements.length; i++){ - var r = replacements[i]; - r.targets = ASMAPI.loadData(r.targets); - for(var k = 0; k < r.targets.length; k++){ - mergedTargets.push(r.targets[k]); - } - } - - return { - 'neoforge_method_redirector': { - 'target': { - 'type': 'CLASS', - 'names': function(listofclasses) { - return mergedTargets - } - }, - 'transformer': function(classNode) { - var methods = classNode.methods; - var count = 0; - for(var i = 0; i < methods.size(); i++){ - var instr = methods.get(i).instructions; - for(var ix = 0; ix < instr.size(); ix++){ - var node = instr.get(ix); - var temp = search(classNode.name, node, replacements); - if (temp != null) { - instr.set(node, temp.factory(node)); - } - } - } - return classNode; - } - } - } -} diff --git a/testframework/src/main/java/net/neoforged/testframework/impl/TestFrameworkImpl.java b/testframework/src/main/java/net/neoforged/testframework/impl/TestFrameworkImpl.java index bd92bd892a..9eed8f6bdb 100644 --- a/testframework/src/main/java/net/neoforged/testframework/impl/TestFrameworkImpl.java +++ b/testframework/src/main/java/net/neoforged/testframework/impl/TestFrameworkImpl.java @@ -84,6 +84,7 @@ public class TestFrameworkImpl implements MutableTestFramework { private @Nullable MinecraftServer server; private final DynamicStructureTemplates structures; + private boolean inClientWorld = false; private @UnknownNullability String commandName; @@ -237,6 +238,11 @@ public void init(final IEventBus modBus, final ModContainer container) { modBus.addListener(new TestFrameworkPayloadInitialization(this)::onNetworkSetup); modBus.addListener((final RegisterGameTestsEvent event) -> event.register(GameTestRegistration.REGISTER_METHOD)); + synchronized (tests().enabled) { + List.copyOf(tests().enabled).forEach(tests()::disable); + } + tests().initialiseDefaultEnabledTests(); + if (FMLLoader.getDist().isClient()) { setupClient(this, modBus, container); } @@ -248,12 +254,14 @@ public void init(final IEventBus modBus, final ModContainer container) { private static void setupClient(TestFrameworkImpl impl, IEventBus modBus, ModContainer container) { if (impl.client != null) impl.client.init(modBus, container); - NeoForge.EVENT_BUS.addListener((final ClientPlayerNetworkEvent.LoggingIn logOut) -> { + NeoForge.EVENT_BUS.addListener((final ClientPlayerNetworkEvent.LoggingIn logIn) -> { synchronized (impl.tests().enabled) { List.copyOf(impl.tests().enabled).forEach(impl.tests()::disable); } impl.tests().initialiseDefaultEnabledTests(); + impl.inClientWorld = true; }); + NeoForge.EVENT_BUS.addListener((final ClientPlayerNetworkEvent.LoggingOut logOut) -> impl.inClientWorld = false); } @Override @@ -304,6 +312,8 @@ public void changeStatus(Test test, Test.Status newStatus, @Nullable Entity chan logger.info("Status of test '{}' has had status changed to {}{}.", test.id(), newStatus, changer instanceof Player player ? " by " + player.getGameProfile().getName() : ""); + if (server == null && !inClientWorld) return; + final ChangeStatusPayload packet = new ChangeStatusPayload(this, test.id(), newStatus); sendPacketIfOn( () -> PacketDistributor.sendToAllPlayers(packet), diff --git a/tests/build.gradle b/tests/build.gradle index 83f5f7dcc0..2da20a4e40 100644 --- a/tests/build.gradle +++ b/tests/build.gradle @@ -8,6 +8,7 @@ plugins { def neoforgeProject = project(':neoforge') def testframeworkProject = project(':testframework') +def coremodsProject = project(':neoforge-coremods') repositories { mavenLocal() @@ -68,7 +69,7 @@ runs { data { configure neoforgeProject.runTypes.data - programArguments.addAll '--flat', '--all', '--validate', + arguments.addAll '--flat', '--all', '--validate', '--mod', 'data_gen_test', '--mod', 'global_loot_test', '--mod', 'scaffolding_test', @@ -90,24 +91,26 @@ runs { gameDir.mkdirs(); workingDirectory.set gameDir - programArguments.addAll '--gameDir', gameDir.absolutePath + arguments.addAll '--gameDir', gameDir.absolutePath } } //We need the assets and natives tasks from the forge project. runs.configureEach { - dependsOn(neoforgeProject.runtime.assets, neoforgeProject.runtime.natives) + dependsOn.add(neoforgeProject.runtime.assets) + dependsOn.add(neoforgeProject.runtime.natives) modSource neoforgeProject.sourceSets.main + modSource coremodsProject.sourceSets.main modSource testframeworkProject.sourceSets.main } afterEvaluate { runs.data { // Override --output that forge already has - def args = new ArrayList(programArguments.get()); + def args = new ArrayList(arguments.get()); def outputIndex = args.indexOf('--output'); args.set(outputIndex+1, file('src/generated/resources/').absolutePath); - programArguments.set(args); + arguments.set(args); } runs.junit.modSources.all().get().values().remove(sourceSets.main) } diff --git a/tests/src/generated/resources/assets/data_gen_test/models/block/acacia_hanging_sign.json b/tests/src/generated/resources/assets/data_gen_test/models/block/acacia_hanging_sign.json new file mode 100644 index 0000000000..9d088d1113 --- /dev/null +++ b/tests/src/generated/resources/assets/data_gen_test/models/block/acacia_hanging_sign.json @@ -0,0 +1,5 @@ +{ + "textures": { + "particle": "minecraft:block/stripped_acacia_log" + } +} \ No newline at end of file diff --git a/tests/src/generated/resources/assets/minecraft/blockstates/acacia_hanging_sign.json b/tests/src/generated/resources/assets/minecraft/blockstates/acacia_hanging_sign.json new file mode 100644 index 0000000000..21adab31a7 --- /dev/null +++ b/tests/src/generated/resources/assets/minecraft/blockstates/acacia_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "data_gen_test:block/acacia_hanging_sign" + } + } +} \ No newline at end of file diff --git a/tests/src/generated/resources/assets/minecraft/blockstates/acacia_wall_hanging_sign.json b/tests/src/generated/resources/assets/minecraft/blockstates/acacia_wall_hanging_sign.json new file mode 100644 index 0000000000..21adab31a7 --- /dev/null +++ b/tests/src/generated/resources/assets/minecraft/blockstates/acacia_wall_hanging_sign.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "data_gen_test:block/acacia_hanging_sign" + } + } +} \ No newline at end of file diff --git a/tests/src/generated/resources/assets/minecraft/models/item/acacia_planks.json b/tests/src/generated/resources/assets/minecraft/models/item/acacia_planks.json new file mode 100644 index 0000000000..3c90abef53 --- /dev/null +++ b/tests/src/generated/resources/assets/minecraft/models/item/acacia_planks.json @@ -0,0 +1,3 @@ +{ + "parent": "minecraft:block/acacia_planks" +} \ No newline at end of file diff --git a/tests/src/generated/resources/assets/minecraft/models/item/sheep_spawn_egg.json b/tests/src/generated/resources/assets/minecraft/models/item/sheep_spawn_egg.json new file mode 100644 index 0000000000..d1aaa9d6ef --- /dev/null +++ b/tests/src/generated/resources/assets/minecraft/models/item/sheep_spawn_egg.json @@ -0,0 +1,3 @@ +{ + "parent": "minecraft:item/template_spawn_egg" +} \ No newline at end of file diff --git a/tests/src/generated/resources/assets/minecraft/models/item/wooden_sword.json b/tests/src/generated/resources/assets/minecraft/models/item/wooden_sword.json new file mode 100644 index 0000000000..4024a58a08 --- /dev/null +++ b/tests/src/generated/resources/assets/minecraft/models/item/wooden_sword.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "minecraft:item/wooden_sword" + } +} \ No newline at end of file diff --git a/tests/src/junit/java/net/neoforged/neoforge/unittest/EntityModelSerializationTest.java b/tests/src/junit/java/net/neoforged/neoforge/unittest/EntityModelSerializationTest.java new file mode 100644 index 0000000000..ee201e6909 --- /dev/null +++ b/tests/src/junit/java/net/neoforged/neoforge/unittest/EntityModelSerializationTest.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.unittest; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.mojang.serialization.JsonOps; +import net.minecraft.client.animation.definitions.BreezeAnimation; +import net.neoforged.neoforge.client.entity.animation.json.AnimationParser; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +/** + * Tests that animations can be serialized into json and deserialized to be identical to the original. + */ +@TestMethodOrder(MethodOrderer.MethodName.class) +public class EntityModelSerializationTest { + @Test + void breezeRoundTripTest() { + final var beforeSerialize = BreezeAnimation.JUMP; + final var serialized = AnimationParser.CODEC.encodeStart(JsonOps.INSTANCE, beforeSerialize).getOrThrow(); + final var afterDeserialize = AnimationParser.CODEC.parse(JsonOps.INSTANCE, serialized).getOrThrow(); + assertThat(afterDeserialize).usingRecursiveComparison().isEqualTo(beforeSerialize); + } +} diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/client/ClientTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/client/ClientTests.java index 6f6b09ec42..658df7f778 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/client/ClientTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/client/ClientTests.java @@ -11,6 +11,8 @@ import javax.sound.sampled.AudioFormat; import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.resources.sounds.AbstractSoundInstance; import net.minecraft.client.resources.sounds.Sound; import net.minecraft.client.resources.sounds.SoundInstance; @@ -26,6 +28,7 @@ import net.neoforged.neoforge.client.event.ClientChatEvent; import net.neoforged.neoforge.client.event.ClientTickEvent; import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; +import net.neoforged.neoforge.client.event.TextureAtlasStitchedEvent; import net.neoforged.neoforge.common.data.LanguageProvider; import net.neoforged.testframework.DynamicTest; import net.neoforged.testframework.annotation.ForEachTest; @@ -81,6 +84,29 @@ static void keyMappingTest(final DynamicTest test) { }); } + @TestHolder(description = "Tests that the NamespacedDirectoryLister only collects resources from the specified namespace", enabledByDefault = true) + static void namespacedDirectoryListerTest(final DynamicTest test) { + final ResourceLocation MUST_BE_PRESENT = ResourceLocation.fromNamespaceAndPath("neotests_dir_list_present", "test/dir_list_test_present"); + final ResourceLocation MUST_BE_ABSENT = ResourceLocation.fromNamespaceAndPath("neotests_dir_list_absent", "test/dir_list_test_absent"); + + test.framework().modEventBus().addListener((final TextureAtlasStitchedEvent event) -> { + if (!event.getAtlas().location().equals(TextureAtlas.LOCATION_BLOCKS)) { + return; + } + + ResourceLocation missing = MissingTextureAtlasSprite.getLocation(); + if (event.getAtlas().getSprite(MUST_BE_PRESENT).contents().name().equals(missing)) { + test.fail("dir_list_test_present.png must be present but returned the missing texture"); + return; + } + if (!event.getAtlas().getSprite(MUST_BE_ABSENT).contents().name().equals(missing)) { + test.fail("dir_list_test_absent.png must be absent but returned something other than the missing texture"); + return; + } + test.pass(); + }); + } + private static final class SineSound extends AbstractSoundInstance { SineSound(Vec3 position) { super(ResourceLocation.fromNamespaceAndPath("neotests_audio_stream_test", "sine_wave"), SoundSource.BLOCKS, SoundInstance.createUnseededRandom()); diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/client/DimensionTransitionScreenTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/client/DimensionTransitionScreenTests.java new file mode 100644 index 0000000000..fdf77428fb --- /dev/null +++ b/tests/src/main/java/net/neoforged/neoforge/debug/client/DimensionTransitionScreenTests.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforge.debug.client; + +import java.util.function.BooleanSupplier; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.ReceivingLevelScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.neoforge.client.event.RegisterDimensionTransitionScreenEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import net.neoforged.testframework.DynamicTest; +import net.neoforged.testframework.annotation.ForEachTest; +import net.neoforged.testframework.annotation.TestHolder; +import net.neoforged.testframework.gametest.EmptyTemplate; + +@ForEachTest(side = Dist.CLIENT, groups = { DimensionTransitionScreenTests.GROUP, "manual" }) +public class DimensionTransitionScreenTests { + public static final String GROUP = "dimension_transition"; + public static final ResourceLocation NETHER_BG = ResourceLocation.withDefaultNamespace("textures/block/netherrack.png"); + public static final ResourceLocation END_BG = ResourceLocation.withDefaultNamespace("textures/block/end_stone.png"); + + @EmptyTemplate + @TestHolder(description = "Tests if a custom dimension transition screen is properly displayed when exiting the Nether") + static void netherOutgoingTransition(DynamicTest test) { + test.framework().modEventBus().addListener((RegisterDimensionTransitionScreenEvent event) -> event.registerOutgoingEffect(Level.NETHER, (supplier, reason) -> new CustomLevelScreen(supplier, reason, NETHER_BG, Component.literal("This displays when returning from the nether!")))); + + test.eventListeners().forge().addListener((PlayerEvent.PlayerChangedDimensionEvent event) -> { + Player player = event.getEntity(); + if (event.getFrom() == Level.NETHER) { + test.requestConfirmation(player, Component.literal("Did the screen display a netherrack background when traveling through the portal?")); + } + }); + } + + @EmptyTemplate + @TestHolder(description = "Tests if a custom dimension transition screen is properly displayed when entering the End") + static void endIncomingTransition(DynamicTest test) { + test.framework().modEventBus().addListener((RegisterDimensionTransitionScreenEvent event) -> event.registerIncomingEffect(Level.END, (supplier, reason) -> new CustomLevelScreen(supplier, reason, END_BG, Component.literal("This displays when going to the end!")))); + + test.eventListeners().forge().addListener((PlayerEvent.PlayerChangedDimensionEvent event) -> { + Player player = event.getEntity(); + if (event.getTo() == Level.END) { + test.requestConfirmation(player, Component.literal("Did the screen display an end stone background when traveling through the portal?")); + } + }); + } + + public static class CustomLevelScreen extends ReceivingLevelScreen { + private final ResourceLocation bgTexture; + private final Component message; + + public CustomLevelScreen(BooleanSupplier supplier, Reason reason, ResourceLocation bgTexture, Component message) { + super(supplier, reason); + this.bgTexture = bgTexture; + this.message = message; + } + + @Override + public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) { + this.renderBackground(graphics, mouseX, mouseY, partialTick); + graphics.drawCenteredString(this.font, this.message, this.width / 2, this.height / 2 - 50, 0xFFFFFF); + } + + @Override + public void renderBackground(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) { + graphics.blit(this.bgTexture, 0, 0, 0, 0.0F, 0.0F, this.width, this.height, 32, 32); + } + } +} diff --git a/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java b/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java index b57efcec2e..7099e33cca 100644 --- a/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java +++ b/tests/src/main/java/net/neoforged/neoforge/debug/entity/EntityEventTests.java @@ -6,6 +6,7 @@ package net.neoforged.neoforge.debug.entity; import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.gametest.framework.GameTest; @@ -13,6 +14,7 @@ import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.damagesource.DamageTypes; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.ai.attributes.RangedAttribute; import net.minecraft.world.entity.animal.Cow; import net.minecraft.world.entity.animal.Pig; @@ -27,8 +29,10 @@ import net.neoforged.neoforge.event.entity.EntityInvulnerabilityCheckEvent; import net.neoforged.neoforge.event.entity.EntityTeleportEvent; import net.neoforged.neoforge.event.entity.EntityTravelToDimensionEvent; +import net.neoforged.neoforge.event.entity.living.FinalizeSpawnEvent; import net.neoforged.neoforge.event.level.ExplosionKnockbackEvent; import net.neoforged.testframework.DynamicTest; +import net.neoforged.testframework.Test; import net.neoforged.testframework.annotation.ForEachTest; import net.neoforged.testframework.annotation.TestHolder; import net.neoforged.testframework.gametest.EmptyTemplate; @@ -165,4 +169,39 @@ static void entityTravelToDimensionEvent(final DynamicTest test) { .thenExecute(helper::killAllEntities) .thenSucceed()); } + + @GameTest + @EmptyTemplate(floor = true) + @TestHolder(description = "Tests that the FinalizeSpawnEvent is emitted at all") + static void entityFinalizeSpawnEvent(final DynamicTest test) { + // Identify the entity we spawn in this test by their spawn location, since we do not have + // access to the entity object at all before the event is emitted. + AtomicReference spawnPosRef = new AtomicReference<>(); + test.eventListeners().forge().addListener((final FinalizeSpawnEvent event) -> { + if (Objects.equals(spawnPosRef.get(), event.getEntity().blockPosition())) { + event.setSpawnCancelled(true); + test.pass(); + } + }); + + test.onGameTest(helper -> helper.startSequence() + .thenExecute(() -> { + var spawnPos = helper.absolutePos(BlockPos.ZERO); + spawnPosRef.set(spawnPos); + EntityType.PIG.create( + helper.getLevel(), + ignored -> {}, + spawnPos, + MobSpawnType.SPAWN_EGG, + false, + false); + }) + .thenExecute(() -> { + // The event handler canceled the spawn + helper.assertEntityNotPresent(EntityType.PIG); + }) + .thenWaitUntil(() -> helper.assertValueEqual(test.status(), Test.Status.PASSED, "listener called")) + .thenExecute(helper::killAllEntities) + .thenSucceed()); + } } diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/DataGeneratorTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/DataGeneratorTest.java index f92fb5b82d..104839af33 100644 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/DataGeneratorTest.java +++ b/tests/src/main/java/net/neoforged/neoforge/oldtest/DataGeneratorTest.java @@ -86,6 +86,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.ButtonBlock; +import net.minecraft.world.level.block.CeilingHangingSignBlock; import net.minecraft.world.level.block.DoorBlock; import net.minecraft.world.level.block.FenceGateBlock; import net.minecraft.world.level.block.FurnaceBlock; @@ -96,6 +97,7 @@ import net.minecraft.world.level.block.StairBlock; import net.minecraft.world.level.block.StandingSignBlock; import net.minecraft.world.level.block.TrapDoorBlock; +import net.minecraft.world.level.block.WallHangingSignBlock; import net.minecraft.world.level.block.WallSignBlock; import net.minecraft.world.level.dimension.BuiltinDimensionTypes; import net.minecraft.world.level.dimension.DimensionType; @@ -742,6 +744,7 @@ protected void registerStatesAndModels() { pressurePlateBlock((PressurePlateBlock) Blocks.ACACIA_PRESSURE_PLATE, blockTexture(Blocks.ACACIA_PLANKS)); signBlock((StandingSignBlock) Blocks.ACACIA_SIGN, (WallSignBlock) Blocks.ACACIA_WALL_SIGN, blockTexture(Blocks.ACACIA_PLANKS)); + hangingSignBlock((CeilingHangingSignBlock) Blocks.ACACIA_HANGING_SIGN, (WallHangingSignBlock) Blocks.ACACIA_WALL_HANGING_SIGN, blockTexture(Blocks.STRIPPED_ACACIA_LOG)); simpleBlock(Blocks.TORCH, models().torch("torch", mcLoc("block/torch"))); horizontalBlock(Blocks.WALL_TORCH, models().torchWall("wall_torch", mcLoc("block/torch")), 90); diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/DeferredRegistryTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/DeferredRegistryTest.java index 3cd673b8fc..6f85a772e3 100644 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/DeferredRegistryTest.java +++ b/tests/src/main/java/net/neoforged/neoforge/oldtest/DeferredRegistryTest.java @@ -41,7 +41,7 @@ public class DeferredRegistryTest { private static final Logger LOGGER = LogManager.getLogger(); private static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(MODID); - private static final DeferredRegister.DataComponents COMPONENTS = DeferredRegister.createDataComponents(MODID); + private static final DeferredRegister.DataComponents COMPONENTS = DeferredRegister.createDataComponents(Registries.DATA_COMPONENT_TYPE, MODID); private static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(MODID); private static final ResourceKey> CUSTOM_REGISTRY_KEY = ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(MODID, "test_registry")); private static final DeferredRegister CUSTOMS = DeferredRegister.create(CUSTOM_REGISTRY_KEY, MODID); diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/FinalizeSpawnTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/FinalizeSpawnTest.java deleted file mode 100644 index 8c440fcff6..0000000000 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/FinalizeSpawnTest.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.neoforged.neoforge.oldtest; - -import net.minecraft.network.chat.Component; -import net.minecraft.world.entity.EntityType; -import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.common.NeoForge; -import net.neoforged.neoforge.event.entity.living.FinalizeSpawnEvent; - -@Mod(FinalizeSpawnTest.ID) -public class FinalizeSpawnTest { - public static final String ID = "finalize_spawn_fix_test"; - public static final boolean ENABLED = false; - - public FinalizeSpawnTest() { - NeoForge.EVENT_BUS.addListener(FinalizeSpawnEvent.class, event -> { - var entityType = EntityType.WANDERING_TRADER; - var entity = event.getEntity(); - - // testing with wandering trader to validate the following - // - ambient sounds dont play for cancelled mob spawns - // - llamas dont spawn for cancelled trader spawns - // but this test is not specific to wandering traders - if (ENABLED && entity.getType() == entityType) { - // some debug message to say entity spawn was cancelled - event.getLevel().players().forEach(player -> player.displayClientMessage(Component.literal("Cancelled %s spawn @ %s".formatted(entityType.getDescription().getString(), entity.position())), true)); - event.setSpawnCancelled(true); - } - }); - } -} diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/block/FullPotsAccessorDemo.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/block/FullPotsAccessorDemo.java index f04c814e50..207a9aeb14 100644 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/block/FullPotsAccessorDemo.java +++ b/tests/src/main/java/net/neoforged/neoforge/oldtest/block/FullPotsAccessorDemo.java @@ -165,7 +165,7 @@ private static class DioriteFlowerPotBlockEntity extends BlockEntity { public DioriteFlowerPotBlockEntity(BlockPos pos, BlockState state) { super(DIORITE_POT_BLOCK_ENTITY.get(), pos, state); - modelData = ModelData.builder().with(PLANT_PROPERTY, plant).build(); + modelData = ModelData.of(PLANT_PROPERTY, plant); } public void setPlant(Block plant) { diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/client/CustomSpriteSourceTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/client/CustomSpriteSourceTest.java index 3c108b31f3..c0608a4f23 100644 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/client/CustomSpriteSourceTest.java +++ b/tests/src/main/java/net/neoforged/neoforge/oldtest/client/CustomSpriteSourceTest.java @@ -47,16 +47,15 @@ public CustomSpriteSourceTest(IEventBus modEventBus) { ITEMS.register(modEventBus); } - private static SpriteSourceType tasLoader; - private void registerTextureAtlasSpriteLoaders(RegisterSpriteSourceTypesEvent event) { - tasLoader = event.register(ResourceLocation.fromNamespaceAndPath(MOD_ID, "custom_sprite_source"), CustomSpriteSource.CODEC); + event.register(ResourceLocation.fromNamespaceAndPath(MOD_ID, "custom_sprite_source"), CustomSpriteSource.TYPE); } private record CustomSpriteSource(ResourceLocation id) implements SpriteSource { private static final Logger LOGGER = LogUtils.getLogger(); private static final MapCodec CODEC = RecordCodecBuilder.mapCodec(inst -> inst.group( ResourceLocation.CODEC.fieldOf("id").forGetter(CustomSpriteSource::id)).apply(inst, CustomSpriteSource::new)); + private static final SpriteSourceType TYPE = new SpriteSourceType(CustomSpriteSource.CODEC); @Override public void run(ResourceManager manager, Output output) { @@ -72,7 +71,7 @@ public void run(ResourceManager manager, Output output) { @Override public SpriteSourceType type() { - return tasLoader; + return TYPE; } static final class CustomSpriteContents extends SpriteContents { diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/client/model/CustomItemDisplayContextTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/client/model/CustomItemDisplayContextTest.java index 9c6ce94624..17f8a3cb3a 100644 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/client/model/CustomItemDisplayContextTest.java +++ b/tests/src/main/java/net/neoforged/neoforge/oldtest/client/model/CustomItemDisplayContextTest.java @@ -34,6 +34,7 @@ import net.minecraft.world.item.Items; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.HorizontalDirectionalBlock; import net.minecraft.world.level.block.RenderShape; @@ -167,6 +168,12 @@ protected void registerModels() { .translation(-2.25f, 1.5f, -0.25f).scale(0.48f) .end() .end(); + + handheldItem(Items.WOODEN_SWORD); + + spawnEggItem(Items.SHEEP_SPAWN_EGG); + + simpleBlockItem(Blocks.ACACIA_PLANKS); } } diff --git a/tests/src/main/java/net/neoforged/neoforge/oldtest/client/model/MegaModelTest.java b/tests/src/main/java/net/neoforged/neoforge/oldtest/client/model/MegaModelTest.java index 2fdbf63445..fd787f71ec 100644 --- a/tests/src/main/java/net/neoforged/neoforge/oldtest/client/model/MegaModelTest.java +++ b/tests/src/main/java/net/neoforged/neoforge/oldtest/client/model/MegaModelTest.java @@ -133,11 +133,11 @@ public Entity(BlockPos pos, BlockState state) { @Override public ModelData getModelData() { - return ModelData.builder().with(TestData.PROPERTY, new TestData(new Transformation( + return ModelData.of(TestData.PROPERTY, new TestData(new Transformation( new Vector3f(0, y * 0.2f, 0), new Quaternionf(1f, 1f, 1f, 1f), Transformation.identity().getScale(), - new Quaternionf(1f, 1f, 1f, 1f)))).build(); + new Quaternionf(1f, 1f, 1f, 1f)))); } } } diff --git a/tests/src/main/resources/assets/minecraft/atlases/blocks.json b/tests/src/main/resources/assets/minecraft/atlases/blocks.json index 546f163471..e8d0700f11 100644 --- a/tests/src/main/resources/assets/minecraft/atlases/blocks.json +++ b/tests/src/main/resources/assets/minecraft/atlases/blocks.json @@ -3,6 +3,12 @@ { "type": "custom_sprite_source_test:custom_sprite_source", "id": "custom_sprite_source_test:test_item" + }, + { + "type": "neoforge:namespaced_directory", + "namespace": "neotests_dir_list_present", + "source": "test", + "prefix": "test/" } ] } diff --git a/tests/src/main/resources/assets/neotests_dir_list_absent/textures/test/dir_list_test_absent.png b/tests/src/main/resources/assets/neotests_dir_list_absent/textures/test/dir_list_test_absent.png new file mode 100644 index 0000000000..3f90638ec5 Binary files /dev/null and b/tests/src/main/resources/assets/neotests_dir_list_absent/textures/test/dir_list_test_absent.png differ diff --git a/tests/src/main/resources/assets/neotests_dir_list_present/textures/test/dir_list_test_present.png b/tests/src/main/resources/assets/neotests_dir_list_present/textures/test/dir_list_test_present.png new file mode 100644 index 0000000000..0cdde54cdb Binary files /dev/null and b/tests/src/main/resources/assets/neotests_dir_list_present/textures/test/dir_list_test_present.png differ