From 3f35151102c1591aa68143ac15e3c8c8e9b26e01 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Mon, 17 Jun 2024 21:27:25 +0800 Subject: [PATCH 01/50] bump: minecraft 1.21 --- .gitignore | 3 +++ build.gradle | 2 +- gradle.properties | 17 +++++++++-------- src/main/java/io/github/sakurawald/Fuji.java | 2 ++ .../sakurawald/config/model/ConfigModel.java | 2 +- .../module/initializer/head/api/Category.java | 1 - .../module/initializer/skin/SkinRestorer.java | 13 ++----------- .../initializer/teleport_warmup/Position.java | 2 +- .../initializer/top_chunks/TopChunksModule.java | 2 +- .../module/initializer/works/WorksModule.java | 2 +- .../works/work_type/ProductionWork.java | 2 +- .../ServerPlayNetworkHandlerMixin.java | 3 ++- .../ServerPlayNetworkHandlerMixin.java | 3 ++- .../mixin/tick_chunk_cache/ChunkMapMixin.java | 4 ++-- .../ThreadedAnvilChunkStorageMixin.java | 4 ++-- src/main/resources/fabric.mod.json | 2 +- src/main/resources/fuji.mixins.json | 1 + 17 files changed, 32 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 5707f0add..2f533c7b1 100755 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,6 @@ replay_*.log output/ logs/ .vim/ + +# yarn +remappedSrc \ No newline at end of file diff --git a/build.gradle b/build.gradle index 25c034d31..e73b280a7 100755 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,7 @@ base { } repositories { + mavenCentral() maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots/" } maven { url "https://oss.sonatype.org/content/repositories/snapshots" } maven { url "https://jitpack.io" } @@ -59,7 +60,6 @@ dependencies { modImplementation include("me.lucko:fabric-permissions-api:${project.fabric_permissions_version}") modImplementation include("net.kyori:adventure-platform-fabric:${project.adventure_platform_fabric_version}") include(implementation "net.kyori:adventure-text-minimessage:${project.adventure_api_version}") - include(implementation "net.kyori:adventure-text-serializer-plain:${project.adventure_api_version}") modImplementation include("eu.pb4:sgui:${project.sgui_version}") diff --git a/gradle.properties b/gradle.properties index 779eefaac..ce4328faa 100755 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,5 @@ -org.gradle.jvmargs=-Xmx4G +# gradle +org.gradle.jvmargs=-Xmx8G org.gradle.parallel=true # mod properties @@ -7,16 +8,16 @@ maven_group=io.github.sakurawald archives_base_name=fuji # fabric deps -minecraft_version=1.20.6 +minecraft_version=1.21 loader_version=0.15.11 -yarn_mappings=1.20.6+build.1 +yarn_mappings=1.21+build.2 # mod deps -fabric_api_version=0.98.0+1.20.6 -carpet_core_version=1.20.6-1.4.141+v240429 -sgui_version=1.5.1+1.20.5 -adventure_api_version=4.15.0 -adventure_platform_fabric_version=5.13.0 +fabric_api_version=0.100.1+1.21 +carpet_core_version=1.21-1.4.147+v240613 +sgui_version=1.6.0+1.21 +adventure_api_version=4.17.0 +adventure_platform_fabric_version=5.14.0-SNAPSHOT # common deps fabric_permissions_version=0.2-SNAPSHOT diff --git a/src/main/java/io/github/sakurawald/Fuji.java b/src/main/java/io/github/sakurawald/Fuji.java index 77e8ecaa1..f9e286bbe 100644 --- a/src/main/java/io/github/sakurawald/Fuji.java +++ b/src/main/java/io/github/sakurawald/Fuji.java @@ -24,6 +24,8 @@ // TODO: kit module -> spec-command // TODO: luckperms context calculate module +// TODO: remove tick chunk cache module + public class Fuji implements ModInitializer { public static final String MOD_ID = "fuji"; public static final Logger LOGGER = LogUtil.createLogger("Fuji"); diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index 851be4d2a..a8e56f23a 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -2,7 +2,7 @@ import com.mojang.authlib.properties.Property; -import io.github.sakurawald.config.serializer.Comment; +import io.github.sakurawald.config.annotation.Comment; import io.github.sakurawald.module.initializer.command_alias.CommandAliasEntry; import java.util.ArrayList; diff --git a/src/main/java/io/github/sakurawald/module/initializer/head/api/Category.java b/src/main/java/io/github/sakurawald/module/initializer/head/api/Category.java index 40d5fd26c..160577e0b 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/head/api/Category.java +++ b/src/main/java/io/github/sakurawald/module/initializer/head/api/Category.java @@ -3,7 +3,6 @@ import io.github.sakurawald.util.MessageUtil; import java.util.UUID; -import net.minecraft.component.DataComponentType; import net.minecraft.component.DataComponentTypes; import net.minecraft.item.ItemStack; import net.minecraft.server.network.ServerPlayerEntity; diff --git a/src/main/java/io/github/sakurawald/module/initializer/skin/SkinRestorer.java b/src/main/java/io/github/sakurawald/module/initializer/skin/SkinRestorer.java index eb1d2161e..836186470 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/skin/SkinRestorer.java +++ b/src/main/java/io/github/sakurawald/module/initializer/skin/SkinRestorer.java @@ -11,16 +11,7 @@ import lombok.Getter; import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.network.packet.s2c.play.EntitiesDestroyS2CPacket; -import net.minecraft.network.packet.s2c.play.EntityPositionS2CPacket; -import net.minecraft.network.packet.s2c.play.EntitySpawnS2CPacket; -import net.minecraft.network.packet.s2c.play.EntityStatusEffectS2CPacket; -import net.minecraft.network.packet.s2c.play.EntityTrackerUpdateS2CPacket; -import net.minecraft.network.packet.s2c.play.ExperienceBarUpdateS2CPacket; -import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; -import net.minecraft.network.packet.s2c.play.PlayerRemoveS2CPacket; -import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket; -import net.minecraft.network.packet.s2c.play.UpdateSelectedSlotS2CPacket; +import net.minecraft.network.packet.s2c.play.*; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; import org.jetbrains.annotations.NotNull; @@ -84,7 +75,7 @@ public static CompletableFuture, Collection< observer1.networkHandler.sendPacket(new PlayerListS2CPacket(PlayerListS2CPacket.Action.ADD_PLAYER, player)); // refresh the player information if (player != observer1 && observer1.canSee(player)) { observer1.networkHandler.sendPacket(new EntitiesDestroyS2CPacket(player.getId())); - observer1.networkHandler.sendPacket(new EntitySpawnS2CPacket(player)); + observer1.networkHandler.sendPacket(new EntitySpawnS2CPacket(player, 0, player.getBlockPos())); observer1.networkHandler.sendPacket(new EntityPositionS2CPacket(player)); observer1.networkHandler.sendPacket(new EntityTrackerUpdateS2CPacket(player.getId(), player.getDataTracker().getChangedEntries())); } else if (player == observer1) { diff --git a/src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/Position.java b/src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/Position.java index 5e4dfa611..37d8c7f3f 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/Position.java +++ b/src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/Position.java @@ -50,7 +50,7 @@ public double distanceToSqr(Position position) { } public void teleport(ServerPlayerEntity player) { - RegistryKey worldKey = RegistryKey.of(RegistryKeys.WORLD, new Identifier(this.level)); + RegistryKey worldKey = RegistryKey.of(RegistryKeys.WORLD, Identifier.of(this.level)); ServerWorld serverLevel = Fuji.SERVER.getWorld(worldKey); if (serverLevel == null) { MessageUtil.sendMessage(player, "level.no_exists", this.level); diff --git a/src/main/java/io/github/sakurawald/module/initializer/top_chunks/TopChunksModule.java b/src/main/java/io/github/sakurawald/module/initializer/top_chunks/TopChunksModule.java index 8c6b852e5..0c09c5c87 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/top_chunks/TopChunksModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/top_chunks/TopChunksModule.java @@ -54,7 +54,7 @@ public void registerCommand(CommandDispatcher dispatcher, C } /* block-entity in this world */ - ThreadedAnvilChunkStorageMixin threadedAnvilChunkStorage = (ThreadedAnvilChunkStorageMixin) world.getChunkManager().threadedAnvilChunkStorage; + ThreadedAnvilChunkStorageMixin threadedAnvilChunkStorage = (ThreadedAnvilChunkStorageMixin) world.getChunkManager().chunkLoadingManager; Iterable chunkHolders = threadedAnvilChunkStorage.$getChunks(); for (ChunkHolder chunkHolder : chunkHolders) { WorldChunk worldChunk = chunkHolder.getWorldChunk(); diff --git a/src/main/java/io/github/sakurawald/module/initializer/works/WorksModule.java b/src/main/java/io/github/sakurawald/module/initializer/works/WorksModule.java index 924219760..f681ebbd9 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/works/WorksModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/works/WorksModule.java @@ -141,7 +141,7 @@ private boolean hasPermission(ServerPlayerEntity player, Work work) { .setCallback((index, clickType, actionType) -> { /* left click -> visit */ if (clickType.isLeft) { - RegistryKey worldKey = RegistryKey.of(RegistryKeys.WORLD, new Identifier(work.level)); + RegistryKey worldKey = RegistryKey.of(RegistryKeys.WORLD, Identifier.of(work.level)); ServerWorld level = Fuji.SERVER.getWorld(worldKey); //noinspection DataFlowIssue player.teleport(level, work.x, work.y, work.z, work.yaw, work.pitch); diff --git a/src/main/java/io/github/sakurawald/module/initializer/works/work_type/ProductionWork.java b/src/main/java/io/github/sakurawald/module/initializer/works/work_type/ProductionWork.java index 61ebf639c..2df93b2e2 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/works/work_type/ProductionWork.java +++ b/src/main/java/io/github/sakurawald/module/initializer/works/work_type/ProductionWork.java @@ -192,7 +192,7 @@ public int resolveHoppers(ServerPlayerEntity player) { int hopperBlockCount = 0; int minecartHopperCount = 0; ServerWorld world = player.getServerWorld(); - ThreadedAnvilChunkStorageMixin threadedAnvilChunkStorage = (ThreadedAnvilChunkStorageMixin) world.getChunkManager().threadedAnvilChunkStorage; + ThreadedAnvilChunkStorageMixin threadedAnvilChunkStorage = (ThreadedAnvilChunkStorageMixin) world.getChunkManager().chunkLoadingManager; Iterable chunkHolders = threadedAnvilChunkStorage.$getChunks(); for (ChunkHolder chunkHolder : chunkHolders) { WorldChunk worldChunk = chunkHolder.getWorldChunk(); diff --git a/src/main/java/io/github/sakurawald/module/mixin/main_stats/ServerPlayNetworkHandlerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/main_stats/ServerPlayNetworkHandlerMixin.java index c14586821..1359198de 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/main_stats/ServerPlayNetworkHandlerMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/main_stats/ServerPlayNetworkHandlerMixin.java @@ -2,6 +2,7 @@ import io.github.sakurawald.module.initializer.main_stats.MainStats; +import net.minecraft.network.DisconnectionInfo; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; @@ -18,7 +19,7 @@ public class ServerPlayNetworkHandlerMixin { public ServerPlayerEntity player; @Inject(at = @At("HEAD"), method = "onDisconnected") - private void $disconnect(Text reason, CallbackInfo info) { + private void $disconnect(DisconnectionInfo disconnectionInfo, CallbackInfo ci) { String uuid = player.getUuid().toString(); MainStats.uuid2stats.remove(uuid); } diff --git a/src/main/java/io/github/sakurawald/module/mixin/op_protect/ServerPlayNetworkHandlerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/op_protect/ServerPlayNetworkHandlerMixin.java index d4f93fc91..5f845b42b 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/op_protect/ServerPlayNetworkHandlerMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/op_protect/ServerPlayNetworkHandlerMixin.java @@ -2,6 +2,7 @@ import io.github.sakurawald.Fuji; +import net.minecraft.network.DisconnectionInfo; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; @@ -19,7 +20,7 @@ public class ServerPlayNetworkHandlerMixin { public ServerPlayerEntity player; @Inject(at = @At(value = "HEAD"), method = "onDisconnected") - private void $onDisconnected(Text reason, CallbackInfo info) { + private void $onDisconnected(DisconnectionInfo disconnectionInfo, CallbackInfo ci) { if (Fuji.SERVER.getPlayerManager().isOperator(player.getGameProfile())) { Fuji.LOGGER.info("op protect -> deop " + player.getGameProfile().getName()); Fuji.SERVER.getPlayerManager().removeFromOperators(player.getGameProfile()); diff --git a/src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ChunkMapMixin.java b/src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ChunkMapMixin.java index c75803dfb..41a41eb95 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ChunkMapMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ChunkMapMixin.java @@ -4,7 +4,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; import net.minecraft.server.world.ChunkHolder; import net.minecraft.server.world.ChunkLevelType; -import net.minecraft.server.world.ThreadedAnvilChunkStorage; +import net.minecraft.server.world.ServerChunkLoadingManager; import net.minecraft.util.math.ChunkPos; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(ThreadedAnvilChunkStorage.class) +@Mixin(ServerChunkLoadingManager.class) public class ChunkMapMixin implements ITickableChunkSource { @Shadow diff --git a/src/main/java/io/github/sakurawald/module/mixin/top_chunks/ThreadedAnvilChunkStorageMixin.java b/src/main/java/io/github/sakurawald/module/mixin/top_chunks/ThreadedAnvilChunkStorageMixin.java index ca3f70691..375814236 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/top_chunks/ThreadedAnvilChunkStorageMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/top_chunks/ThreadedAnvilChunkStorageMixin.java @@ -1,11 +1,11 @@ package io.github.sakurawald.module.mixin.top_chunks; import net.minecraft.server.world.ChunkHolder; -import net.minecraft.server.world.ThreadedAnvilChunkStorage; +import net.minecraft.server.world.ServerChunkLoadingManager; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin(ThreadedAnvilChunkStorage.class) +@Mixin(ServerChunkLoadingManager.class) public interface ThreadedAnvilChunkStorageMixin { @Invoker("entryIterator") Iterable $getChunks(); diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index cb64370bd..2f37427ae 100755 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -24,7 +24,7 @@ ], "depends": { "fabricloader": ">=0.14.22", - "minecraft": "~1.20.1", + "minecraft": "~1.21", "java": ">=17", "fabric-api": "*" } diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index 3ff8841ce..46391e272 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -27,6 +27,7 @@ "main_stats.PlayerListMixin", "main_stats.ServerPlayNetworkHandlerMixin", "motd.ServerStatusPacketListenerImplMixin", + "multi_obsidian_platform.EndPortalBlockMixin", "multi_obsidian_platform.EntityMixin", "newbie_welcome.PlayerListMixin", "op_protect.ServerPlayNetworkHandlerMixin", From 57aa2419c8b694868eae182c6228484beb4889e1 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Mon, 17 Jun 2024 21:30:43 +0800 Subject: [PATCH 02/50] bump: minecraft 1.20.6 --- .../resource_world/ResourceWorldModule.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldModule.java b/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldModule.java index d542cc099..2a75f7063 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldModule.java @@ -11,6 +11,7 @@ import io.github.sakurawald.module.initializer.newbie_welcome.random_teleport.RandomTeleport; import io.github.sakurawald.module.initializer.resource_world.interfaces.DimensionOptionsMixinInterface; import io.github.sakurawald.module.initializer.resource_world.interfaces.SimpleRegistryMixinInterface; +import io.github.sakurawald.module.mixin.resource_world.ServerWorldMixin; import io.github.sakurawald.util.CommandUtil; import io.github.sakurawald.util.MessageUtil; import io.github.sakurawald.util.ScheduleUtil; @@ -31,13 +32,17 @@ import net.minecraft.util.Identifier; import net.minecraft.util.Util; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Position; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.random.RandomSeed; +import net.minecraft.world.ServerWorldAccess; import net.minecraft.world.World; import net.minecraft.world.biome.source.BiomeAccess; import net.minecraft.world.dimension.DimensionOptions; import net.minecraft.world.dimension.DimensionType; import net.minecraft.world.dimension.DimensionTypes; import net.minecraft.world.gen.chunk.ChunkGenerator; +import net.minecraft.world.gen.feature.EndPlatformFeature; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; @@ -160,7 +165,7 @@ private void createWorld(MinecraftServer server, RegistryKey dime /* create the world */ // note: we use the same WorldData from OVERWORLD ResourceWorldProperties resourceWorldProperties = new ResourceWorldProperties(server.getSaveProperties(), seed); - RegistryKey worldRegistryKey = RegistryKey.of(RegistryKeys.WORLD, new Identifier(DEFAULT_RESOURCE_WORLD_NAMESPACE, path)); + RegistryKey worldRegistryKey = RegistryKey.of(RegistryKeys.WORLD, Identifier.of(DEFAULT_RESOURCE_WORLD_NAMESPACE, path)); DimensionOptions dimensionOptions = createDimensionOptions(server, dimensionTypeRegistryKey); ServerWorld world = new ResourceWorld(server, Util.getMainWorkerExecutor(), @@ -198,7 +203,7 @@ private void createWorld(MinecraftServer server, RegistryKey dime } private ServerWorld getResourceWorldByPath(MinecraftServer server, String path) { - RegistryKey worldKey = RegistryKey.of(RegistryKeys.WORLD, new Identifier(DEFAULT_RESOURCE_WORLD_NAMESPACE, path)); + RegistryKey worldKey = RegistryKey.of(RegistryKeys.WORLD, Identifier.of(DEFAULT_RESOURCE_WORLD_NAMESPACE, path)); return server.getWorld(worldKey); } @@ -213,7 +218,8 @@ private ServerWorld getResourceWorldByPath(MinecraftServer server, String path) Optional> type = world.getDimensionEntry().getKey(); if (type.isPresent() && type.get() == DimensionTypes.THE_END) { - ServerWorld.createEndSpawnPlatform(world); + this.createEndSpawnPlatform(world); + BlockPos endSpawnPos = ServerWorld.END_SPAWN_POS; player.teleport(world, endSpawnPos.getX() + 0.5, endSpawnPos.getY(), endSpawnPos.getZ() + 0.5, 90, 0); } else { @@ -225,6 +231,11 @@ private ServerWorld getResourceWorldByPath(MinecraftServer server, String path) }); } + private void createEndSpawnPlatform(ServerWorld world) { + BlockPos endSpawnPos = ServerWorld.END_SPAWN_POS; + Vec3d vec3d = endSpawnPos.toBottomCenterPos(); + EndPlatformFeature.generate(world, BlockPos.ofFloored(vec3d).down(), true); + } private void deleteWorld(MinecraftServer server, String path) { ServerWorld world = getResourceWorldByPath(server, path); From 4d5df7062e62b31b739f573ae46993f38a696f4b Mon Sep 17 00:00:00 2001 From: sakurawald Date: Mon, 17 Jun 2024 21:56:26 +0800 Subject: [PATCH 03/50] bump: minecraft 1.20.6 --- .../EndPortalBlockMixin.java | 45 ++++++++++++++++ .../multi_obsidian_platform/EntityMixin.java | 51 ------------------- .../ServerChunkCacheMixin.java | 9 ++-- src/main/resources/fuji.mixins.json | 1 - 4 files changed, 49 insertions(+), 57 deletions(-) create mode 100644 src/main/java/io/github/sakurawald/module/mixin/multi_obsidian_platform/EndPortalBlockMixin.java delete mode 100644 src/main/java/io/github/sakurawald/module/mixin/multi_obsidian_platform/EntityMixin.java diff --git a/src/main/java/io/github/sakurawald/module/mixin/multi_obsidian_platform/EndPortalBlockMixin.java b/src/main/java/io/github/sakurawald/module/mixin/multi_obsidian_platform/EndPortalBlockMixin.java new file mode 100644 index 000000000..455fb9ee2 --- /dev/null +++ b/src/main/java/io/github/sakurawald/module/mixin/multi_obsidian_platform/EndPortalBlockMixin.java @@ -0,0 +1,45 @@ +package io.github.sakurawald.module.mixin.multi_obsidian_platform; + +import com.llamalad7.mixinextras.sugar.Local; +import io.github.sakurawald.module.ModuleManager; +import io.github.sakurawald.module.initializer.multi_obsidian_platform.MultiObsidianPlatformModule; +import net.minecraft.block.EndPortalBlock; +import net.minecraft.entity.Entity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(EndPortalBlock.class) +public class EndPortalBlockMixin { + + @Unique + private static final MultiObsidianPlatformModule module = ModuleManager.getInitializer(MultiObsidianPlatformModule.class); + + @Unique + BlockPos getTransformedEndSpawnPoint(Entity entity) { + return module.transform(entity.getBlockPos()); + } + + @Unique + World getEntityCurrentLevel(Entity entity) { + return entity.getWorld(); + } + + @Redirect(method = "createTeleportTarget", at = @At(value = "FIELD", target = "Lnet/minecraft/server/world/ServerWorld;END_SPAWN_POS:Lnet/minecraft/util/math/BlockPos;") + ) + /* This method will NOT be called when an entity (including player, item and other entities) jump into overworld's ender-portal-frame */ + BlockPos $createTeleportTarget(@Local(argsOnly = true) Entity entity) { + if (getEntityCurrentLevel(entity).getRegistryKey() != World.OVERWORLD) { + // modify: resource_world:overworld -> minecraft:the_end (default obsidian platform) + // feature: https://bugs.mojang.com/browse/MC-252361 + return ServerWorld.END_SPAWN_POS; + } + BlockPos transformedEndSpawnPoint = getTransformedEndSpawnPoint(entity); + return transformedEndSpawnPoint; + } + +} diff --git a/src/main/java/io/github/sakurawald/module/mixin/multi_obsidian_platform/EntityMixin.java b/src/main/java/io/github/sakurawald/module/mixin/multi_obsidian_platform/EntityMixin.java deleted file mode 100644 index 131372756..000000000 --- a/src/main/java/io/github/sakurawald/module/mixin/multi_obsidian_platform/EntityMixin.java +++ /dev/null @@ -1,51 +0,0 @@ -package io.github.sakurawald.module.mixin.multi_obsidian_platform; - -import io.github.sakurawald.module.ModuleManager; -import io.github.sakurawald.module.initializer.multi_obsidian_platform.MultiObsidianPlatformModule; -import net.minecraft.entity.Entity; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(Entity.class) - -public abstract class EntityMixin { - - @Unique - private static final MultiObsidianPlatformModule module = ModuleManager.getInitializer(MultiObsidianPlatformModule.class); - - @Unique - BlockPos getTransformedEndSpawnPoint() { - Entity entity = (Entity) (Object) this; - return module.transform(entity.getBlockPos()); - } - - @Unique - World getEntityCurrentLevel() { - Entity entity = (Entity) (Object) this; - return entity.getWorld(); - } - - @Redirect(method = "getTeleportTarget", at = @At(value = "FIELD", target = "Lnet/minecraft/server/world/ServerWorld;END_SPAWN_POS:Lnet/minecraft/util/math/BlockPos;"), require = 1) - BlockPos $findDimensionEntryPoint(ServerWorld toLevel) { - // modify: resource_world:overworld -> minecraft:the_end (default obsidian platform) - // feature: https://bugs.mojang.com/browse/MC-252361 - if (getEntityCurrentLevel().getRegistryKey() != World.OVERWORLD) return ServerWorld.END_SPAWN_POS; - return getTransformedEndSpawnPoint(); - } - - /* This method will NOT be called when a PLAYER jump into overworld's ender-portal-frame */ - @Redirect(method = "moveToWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerWorld;createEndSpawnPlatform(Lnet/minecraft/server/world/ServerWorld;)V"), require = 1) - public void $changeDimension(ServerWorld toLevel) { - // modify: resource_world:overworld -> minecraft:the_end (default obsidian platform) - if (getEntityCurrentLevel().getRegistryKey() != World.OVERWORLD) { - ServerWorld.createEndSpawnPlatform(toLevel); - return; - } - module.makeObsidianPlatform(toLevel, getTransformedEndSpawnPoint()); - } -} diff --git a/src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ServerChunkCacheMixin.java b/src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ServerChunkCacheMixin.java index ccc7575bc..42d9fc8d1 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ServerChunkCacheMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ServerChunkCacheMixin.java @@ -3,7 +3,6 @@ import io.github.sakurawald.module.initializer.tick_chunk_cache.ITickableChunkSource; import net.minecraft.server.world.ChunkHolder; import net.minecraft.server.world.ServerChunkManager; -import net.minecraft.server.world.ThreadedAnvilChunkStorage; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; @@ -11,9 +10,9 @@ @Mixin(ServerChunkManager.class) public class ServerChunkCacheMixin { - @Redirect(method = "tickChunks", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ThreadedAnvilChunkStorage;entryIterator()Ljava/lang/Iterable;")) - private Iterable $tickChunks(ThreadedAnvilChunkStorage instance) { - return ((ITickableChunkSource) instance).fuji$tickableChunksIterator(); - } +// @Redirect(method = "tickChunks", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ThreadedAnvilChunkStorage;entryIterator()Ljava/lang/Iterable;")) +// private Iterable $tickChunks(ThreadedAnvilChunkStorage instance) { +// return ((ITickableChunkSource) instance).fuji$tickableChunksIterator(); +// } } diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index 46391e272..bb8484aab 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -28,7 +28,6 @@ "main_stats.ServerPlayNetworkHandlerMixin", "motd.ServerStatusPacketListenerImplMixin", "multi_obsidian_platform.EndPortalBlockMixin", - "multi_obsidian_platform.EntityMixin", "newbie_welcome.PlayerListMixin", "op_protect.ServerPlayNetworkHandlerMixin", "pvp.PvpToggleMixin", From 3d45b9920d7b8390487af8f69841bbd661aaf4cc Mon Sep 17 00:00:00 2001 From: sakurawald Date: Mon, 17 Jun 2024 21:59:14 +0800 Subject: [PATCH 04/50] bump: minecraft 1.20.6 --- .../mixin/resource_world/EndGatewayBlockEntityMixin.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/github/sakurawald/module/mixin/resource_world/EndGatewayBlockEntityMixin.java b/src/main/java/io/github/sakurawald/module/mixin/resource_world/EndGatewayBlockEntityMixin.java index 828128796..ec8cd1622 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/resource_world/EndGatewayBlockEntityMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/resource_world/EndGatewayBlockEntityMixin.java @@ -2,6 +2,7 @@ import net.minecraft.block.entity.EndGatewayBlockEntity; import net.minecraft.registry.RegistryKey; +import net.minecraft.server.world.ServerWorld; import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -11,8 +12,8 @@ public abstract class EndGatewayBlockEntityMixin { // note: for a resource end, we force make World.END == World.END a true condition, so that the end gateway in resource end can work. - @Redirect(method = "tryTeleportingEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;getRegistryKey()Lnet/minecraft/registry/RegistryKey;")) - private static RegistryKey $tryTeleportingEntity(World instance) { + @Redirect(method = "getOrCreateExitPortalPos", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerWorld;getRegistryKey()Lnet/minecraft/registry/RegistryKey;")) + private RegistryKey $tryTeleportingEntity(ServerWorld instance) { return World.END; } } From 9a149be0e80edf6d76cd0c9a821521df616bd304 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Mon, 17 Jun 2024 21:59:43 +0800 Subject: [PATCH 05/50] bump: minecraft 1.20.6 --- .../mixin/multi_obsidian_platform/EndPortalBlockMixin.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/io/github/sakurawald/module/mixin/multi_obsidian_platform/EndPortalBlockMixin.java b/src/main/java/io/github/sakurawald/module/mixin/multi_obsidian_platform/EndPortalBlockMixin.java index 455fb9ee2..1c00f03f2 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/multi_obsidian_platform/EndPortalBlockMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/multi_obsidian_platform/EndPortalBlockMixin.java @@ -38,8 +38,7 @@ World getEntityCurrentLevel(Entity entity) { // feature: https://bugs.mojang.com/browse/MC-252361 return ServerWorld.END_SPAWN_POS; } - BlockPos transformedEndSpawnPoint = getTransformedEndSpawnPoint(entity); - return transformedEndSpawnPoint; + return getTransformedEndSpawnPoint(entity); } } From 09a62c03290fe1e220aa4ceb8744eef54e300f2a Mon Sep 17 00:00:00 2001 From: sakurawald Date: Mon, 17 Jun 2024 22:04:12 +0800 Subject: [PATCH 06/50] fix: regex group reference error if insert `pos` in resource worlds --- .../github/sakurawald/module/initializer/chat/ChatModule.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java b/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java index 9b0a38429..6a04988f2 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java @@ -143,11 +143,12 @@ private Component resolvePositionTag(ServerPlayerEntity player, Component compon } else { hoverText = MessageUtil.ofString(player, "chat.current_pos"); + Fuji.LOGGER.warn("str = {}",player.getWorld().getRegistryKey().getValue().toString()); dim_name = player.getWorld().getRegistryKey().getValue().toString().replaceFirst("minecraft:", ""); x = player.getBlockX(); y = Integer.toString(player.getBlockY()); z = player.getBlockZ(); - click_command = MessageUtil.ofString(player, "chat.xaero_waypoint_add.command", x, y, z, dim_name.replaceAll(":", "$")); + click_command = MessageUtil.ofString(player, "chat.xaero_waypoint_add.command", x, y, z, dim_name.replaceAll(":", "\\$")); } switch (dim_name) { case "overworld": From 5ab7dacf51f872ddae3f9d3329d002fab4b9e24c Mon Sep 17 00:00:00 2001 From: sakurawald Date: Wed, 19 Jun 2024 11:30:10 +0800 Subject: [PATCH 07/50] remove: TickChunkCache module --- build.gradle | 2 +- .../sakurawald/config/model/ConfigModel.java | 5 -- .../module/initializer/chat/ChatModule.java | 2 - .../ITickableChunkSource.java | 10 ---- .../mixin/tick_chunk_cache/ChunkMapMixin.java | 47 ------------------- .../ServerChunkCacheMixin.java | 18 ------- src/main/resources/fuji.mixins.json | 2 - 7 files changed, 1 insertion(+), 85 deletions(-) delete mode 100644 src/main/java/io/github/sakurawald/module/initializer/tick_chunk_cache/ITickableChunkSource.java delete mode 100644 src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ChunkMapMixin.java delete mode 100644 src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ServerChunkCacheMixin.java diff --git a/build.gradle b/build.gradle index e73b280a7..076758f99 100755 --- a/build.gradle +++ b/build.gradle @@ -125,7 +125,7 @@ modrinth { versionNumber = "$mod_version" versionType = "release" uploadFile = remapJar - gameVersions = ['1.20.6'] + gameVersions = ['1.21'] loaders = ["fabric"] dependencies { required.project "fabric-api" diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index a8e56f23a..5a1febdd9 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -61,7 +61,6 @@ public class Modules { public BypassMoveSpeed bypass_move_speed = new BypassMoveSpeed(); public BypassMaxPlayerLimit bypass_max_player_limit = new BypassMaxPlayerLimit(); public BiomeLookupCache biome_lookup_cache = new BiomeLookupCache(); - public TickChunkCache tick_chunk_cache = new TickChunkCache(); public Config config = new Config(); public Test test = new Test(); public Hat hat = new Hat(); @@ -405,10 +404,6 @@ public class BiomeLookupCache { public boolean enable = false; } - public class TickChunkCache { - public boolean enable = false; - } - public class Config { public boolean enable = false; } diff --git a/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java b/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java index 6a04988f2..7e8b3c249 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java @@ -142,8 +142,6 @@ private Component resolvePositionTag(ServerPlayerEntity player, Component compon .replaceAll("-waypoints$", "_waypoints"); } else { hoverText = MessageUtil.ofString(player, "chat.current_pos"); - - Fuji.LOGGER.warn("str = {}",player.getWorld().getRegistryKey().getValue().toString()); dim_name = player.getWorld().getRegistryKey().getValue().toString().replaceFirst("minecraft:", ""); x = player.getBlockX(); y = Integer.toString(player.getBlockY()); diff --git a/src/main/java/io/github/sakurawald/module/initializer/tick_chunk_cache/ITickableChunkSource.java b/src/main/java/io/github/sakurawald/module/initializer/tick_chunk_cache/ITickableChunkSource.java deleted file mode 100644 index cf1f7bd21..000000000 --- a/src/main/java/io/github/sakurawald/module/initializer/tick_chunk_cache/ITickableChunkSource.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.sakurawald.module.initializer.tick_chunk_cache; - - -import net.minecraft.server.world.ChunkHolder; - -public interface ITickableChunkSource { - - Iterable fuji$tickableChunksIterator(); - -} diff --git a/src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ChunkMapMixin.java b/src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ChunkMapMixin.java deleted file mode 100644 index 41a41eb95..000000000 --- a/src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ChunkMapMixin.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.github.sakurawald.module.mixin.tick_chunk_cache; - -import io.github.sakurawald.module.initializer.tick_chunk_cache.ITickableChunkSource; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import net.minecraft.server.world.ChunkHolder; -import net.minecraft.server.world.ChunkLevelType; -import net.minecraft.server.world.ServerChunkLoadingManager; -import net.minecraft.util.math.ChunkPos; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(ServerChunkLoadingManager.class) -public class ChunkMapMixin implements ITickableChunkSource { - - @Shadow - @Final - private Long2ObjectLinkedOpenHashMap currentChunkHolders; - - @Unique - private Long2ObjectLinkedOpenHashMap tickingChunksCache = new Long2ObjectLinkedOpenHashMap<>(); - - @Inject(method = "", at = @At("RETURN")) - private void onInit(CallbackInfo ci) { - this.tickingChunksCache = new Long2ObjectLinkedOpenHashMap<>(); - } - - @Inject(method = "onChunkStatusChange", at = @At("HEAD")) - private void $onChunkStatusChange(ChunkPos chunkPos, ChunkLevelType levelType, CallbackInfo ci) { - final ChunkHolder chunkHolder = this.currentChunkHolders.get(chunkPos.toLong()); - if (chunkHolder == null) return; - if (chunkHolder.getLevelType().isAfter(ChunkLevelType.BLOCK_TICKING)) { - this.tickingChunksCache.put(chunkPos.toLong(), chunkHolder); - } else { - this.tickingChunksCache.remove(chunkPos.toLong()); - } - } - - @Override - public Iterable fuji$tickableChunksIterator() { - return this.tickingChunksCache.values(); - } -} diff --git a/src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ServerChunkCacheMixin.java b/src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ServerChunkCacheMixin.java deleted file mode 100644 index 42d9fc8d1..000000000 --- a/src/main/java/io/github/sakurawald/module/mixin/tick_chunk_cache/ServerChunkCacheMixin.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.github.sakurawald.module.mixin.tick_chunk_cache; - -import io.github.sakurawald.module.initializer.tick_chunk_cache.ITickableChunkSource; -import net.minecraft.server.world.ChunkHolder; -import net.minecraft.server.world.ServerChunkManager; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(ServerChunkManager.class) -public class ServerChunkCacheMixin { - -// @Redirect(method = "tickChunks", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ThreadedAnvilChunkStorage;entryIterator()Ljava/lang/Iterable;")) -// private Iterable $tickChunks(ThreadedAnvilChunkStorage instance) { -// return ((ITickableChunkSource) instance).fuji$tickableChunksIterator(); -// } - -} diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index bb8484aab..153dbd004 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -47,8 +47,6 @@ "stronger_player_list.ServerLevelMixin", "system_message.ComponentMixin", "teleport_warmup.ServerPlayerMixin", - "tick_chunk_cache.ChunkMapMixin", - "tick_chunk_cache.ServerChunkCacheMixin", "top_chunks.ThreadedAnvilChunkStorageMixin", "whitelist_fix.UserWhiteListMixin", "works.HopperBlockEntityMixin", From e557a542fcdb930813e83d5caac8eefb37e3598f Mon Sep 17 00:00:00 2001 From: sakurawald Date: Wed, 19 Jun 2024 11:37:04 +0800 Subject: [PATCH 08/50] refactor: rename BetterFakePlayerModule into FakePlayerManagerModule --- .../sakurawald/config/model/ConfigModel.java | 4 ++-- .../FakePlayerManagerModule.java} | 20 +++++++++---------- .../PlayerCommandMixin.java | 14 ++++++------- .../PlayerListMixin.java | 6 +++--- .../PlayerMixin.java | 10 +++++----- .../module/mixin/skin/PlayerListMixin.java | 2 +- .../resources/assets/fuji/lang/en_us.json | 12 +++++------ .../resources/assets/fuji/lang/zh_cn.json | 12 +++++------ src/main/resources/fuji.mixins.json | 6 +++--- 9 files changed, 43 insertions(+), 43 deletions(-) rename src/main/java/io/github/sakurawald/module/initializer/{better_fake_player/BetterFakePlayerModule.java => fake_player_manager/FakePlayerManagerModule.java} (88%) rename src/main/java/io/github/sakurawald/module/mixin/{better_fake_player => fake_player_manager}/PlayerCommandMixin.java (83%) rename src/main/java/io/github/sakurawald/module/mixin/{better_fake_player => fake_player_manager}/PlayerListMixin.java (79%) rename src/main/java/io/github/sakurawald/module/mixin/{better_fake_player => fake_player_manager}/PlayerMixin.java (77%) diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index 5a1febdd9..f762e2da9 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -35,7 +35,7 @@ public class Modules { public NewbieWelcome newbie_welcome = new NewbieWelcome(); public TeleportWarmup teleport_warmup = new TeleportWarmup(); public MOTD motd = new MOTD(); - public BetterFakePlayer better_fake_player = new BetterFakePlayer(); + public FakePlayerManager fake_player_manager = new FakePlayerManager(); public BetterInfo better_info = new BetterInfo(); public CommandCooldown command_cooldown = new CommandCooldown(); public TopChunks top_chunks = new TopChunks(); @@ -135,7 +135,7 @@ public class TeleportWarmup { public double interrupt_distance = 1d; } - public class BetterFakePlayer { + public class FakePlayerManager { public boolean enable = false; @Comment("How many fake-player can each player spawn? The tuple means (day_of_week, minutes_of_the_day, max_fake_player_per_player)." + "The range of day_of_week is [1,7]. " + diff --git a/src/main/java/io/github/sakurawald/module/initializer/better_fake_player/BetterFakePlayerModule.java b/src/main/java/io/github/sakurawald/module/initializer/fake_player_manager/FakePlayerManagerModule.java similarity index 88% rename from src/main/java/io/github/sakurawald/module/initializer/better_fake_player/BetterFakePlayerModule.java rename to src/main/java/io/github/sakurawald/module/initializer/fake_player_manager/FakePlayerManagerModule.java index fc85890c5..1ce3861ee 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/better_fake_player/BetterFakePlayerModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/fake_player_manager/FakePlayerManagerModule.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.module.initializer.better_fake_player; +package io.github.sakurawald.module.initializer.fake_player_manager; import com.mojang.authlib.GameProfile; import com.mojang.brigadier.Command; @@ -27,7 +27,7 @@ import java.time.LocalTime; import java.util.*; -public class BetterFakePlayerModule extends ModuleInitializer { +public class FakePlayerManagerModule extends ModuleInitializer { private final ArrayList CONSTANT_EMPTY_LIST = new ArrayList<>(); private final HashMap> player2fakePlayers = new HashMap<>(); private final HashMap player2expiration = new HashMap<>(); @@ -74,7 +74,7 @@ public void registerCommand(CommandDispatcher dispatcher, C builder.append("\n"); } ServerCommandSource source = context.getSource(); - source.sendMessage(MessageUtil.ofComponent(source, "better_fake_player.who.header").append(Component.text(builder.toString()))); + source.sendMessage(MessageUtil.ofComponent(source, "fake_player_manager.who.header").append(Component.text(builder.toString()))); return Command.SINGLE_SUCCESS; } @@ -85,10 +85,10 @@ public boolean hasFakePlayers(ServerPlayerEntity player) { public void renewFakePlayers(ServerPlayerEntity player) { String name = player.getGameProfile().getName(); - int duration = Configs.configHandler.model().modules.better_fake_player.renew_duration_ms; + int duration = Configs.configHandler.model().modules.fake_player_manager.renew_duration_ms; long newTime = System.currentTimeMillis() + duration; player2expiration.put(name, newTime); - MessageUtil.sendMessage(player, "better_fake_player.renew.success", DateUtil.toStandardDateFormat(newTime)); + MessageUtil.sendMessage(player, "fake_player_manager.renew.success", DateUtil.toStandardDateFormat(newTime)); } private void validateFakePlayers() { @@ -140,7 +140,7 @@ public boolean canManipulateFakePlayer(CommandContext ctx, } private int getCurrentAmountLimit() { - ArrayList> rules = Configs.configHandler.model().modules.better_fake_player.caps_limit_rule; + ArrayList> rules = Configs.configHandler.model().modules.fake_player_manager.caps_limit_rule; LocalDate currentDate = LocalDate.now(); LocalTime currentTime = LocalTime.now(); int currentDays = currentDate.getDayOfWeek().getValue(); @@ -155,7 +155,7 @@ private int getCurrentAmountLimit() { public void registerScheduleTask(MinecraftServer server) { ScheduleUtil.addJob(ManageFakePlayersJob.class, null, null, ScheduleUtil.CRON_EVERY_MINUTE, new JobDataMap() { { - this.put(BetterFakePlayerModule.class.getName(), BetterFakePlayerModule.this); + this.put(FakePlayerManagerModule.class.getName(), FakePlayerManagerModule.this); } }); } @@ -174,7 +174,7 @@ public static class ManageFakePlayersJob implements Job { @Override public void execute(JobExecutionContext context) { /* validate */ - BetterFakePlayerModule module = (BetterFakePlayerModule) context.getJobDetail().getJobDataMap().get(BetterFakePlayerModule.class.getName()); + FakePlayerManagerModule module = (FakePlayerManagerModule) context.getJobDetail().getJobDataMap().get(FakePlayerManagerModule.class.getName()); module.validateFakePlayers(); int limit = module.getCurrentAmountLimit(); @@ -195,7 +195,7 @@ public void execute(JobExecutionContext context) { ServerPlayerEntity fakePlayer = Fuji.SERVER.getPlayerManager().getPlayer(fakePlayerName); if (fakePlayer == null) return; fakePlayer.kill(); - MessageUtil.sendBroadcast("better_fake_player.kick_for_expiration", fakePlayer.getGameProfile().getName(), playerName); + MessageUtil.sendBroadcast("fake_player_manager.kick_for_expiration", fakePlayer.getGameProfile().getName(), playerName); } // remove entry module.player2expiration.remove(playerName); @@ -210,7 +210,7 @@ public void execute(JobExecutionContext context) { if (fakePlayer == null) continue; fakePlayer.kill(); - MessageUtil.sendBroadcast("better_fake_player.kick_for_amount", fakePlayer.getGameProfile().getName(), playerName); + MessageUtil.sendBroadcast("fake_player_manager.kick_for_amount", fakePlayer.getGameProfile().getName(), playerName); } } } diff --git a/src/main/java/io/github/sakurawald/module/mixin/better_fake_player/PlayerCommandMixin.java b/src/main/java/io/github/sakurawald/module/mixin/fake_player_manager/PlayerCommandMixin.java similarity index 83% rename from src/main/java/io/github/sakurawald/module/mixin/better_fake_player/PlayerCommandMixin.java rename to src/main/java/io/github/sakurawald/module/mixin/fake_player_manager/PlayerCommandMixin.java index 6b119f8bc..c2eacc53c 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/better_fake_player/PlayerCommandMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/fake_player_manager/PlayerCommandMixin.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.module.mixin.better_fake_player; +package io.github.sakurawald.module.mixin.fake_player_manager; import carpet.commands.PlayerCommand; import com.mojang.brigadier.arguments.StringArgumentType; @@ -6,7 +6,7 @@ import io.github.sakurawald.Fuji; import io.github.sakurawald.config.Configs; import io.github.sakurawald.module.ModuleManager; -import io.github.sakurawald.module.initializer.better_fake_player.BetterFakePlayerModule; +import io.github.sakurawald.module.initializer.fake_player_manager.FakePlayerManagerModule; import io.github.sakurawald.util.MessageUtil; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; @@ -22,11 +22,11 @@ public abstract class PlayerCommandMixin { @Unique - private static final BetterFakePlayerModule module = ModuleManager.getInitializer(BetterFakePlayerModule.class); + private static final FakePlayerManagerModule module = ModuleManager.getInitializer(FakePlayerManagerModule.class); @Unique private static String transformFakePlayerName(String fakePlayerName) { - return Configs.configHandler.model().modules.better_fake_player.transform_name.replace("%name%", fakePlayerName); + return Configs.configHandler.model().modules.fake_player_manager.transform_name.replace("%name%", fakePlayerName); } @Redirect(method = "cantSpawn", at = @At( @@ -51,12 +51,12 @@ private static String transformFakePlayerName(String fakePlayerName) { if (player == null) return; if (!module.canSpawnFakePlayer(player)) { - MessageUtil.sendMessage(player, "better_fake_player.spawn.limit_exceed"); + MessageUtil.sendMessage(player, "fake_player_manager.spawn.limit_exceed"); cir.setReturnValue(0); } /* fix: fake-player auth network laggy */ - if (Configs.configHandler.model().modules.better_fake_player.use_local_random_skins_for_fake_player) { + if (Configs.configHandler.model().modules.fake_player_manager.use_local_random_skins_for_fake_player) { String fakePlayerName = StringArgumentType.getString(context, "player"); fakePlayerName = transformFakePlayerName(fakePlayerName); Fuji.SERVER.getUserCache().add(module.createOfflineGameProfile(fakePlayerName)); @@ -76,7 +76,7 @@ private static String transformFakePlayerName(String fakePlayerName) { private static void $cantManipulate(CommandContext context, CallbackInfoReturnable cir) { String fakePlayerName = StringArgumentType.getString(context, "player"); if (!module.canManipulateFakePlayer(context, fakePlayerName)) { - MessageUtil.sendMessage(context.getSource(), "better_fake_player.manipulate.forbidden"); + MessageUtil.sendMessage(context.getSource(), "fake_player_manager.manipulate.forbidden"); cir.setReturnValue(true); } } diff --git a/src/main/java/io/github/sakurawald/module/mixin/better_fake_player/PlayerListMixin.java b/src/main/java/io/github/sakurawald/module/mixin/fake_player_manager/PlayerListMixin.java similarity index 79% rename from src/main/java/io/github/sakurawald/module/mixin/better_fake_player/PlayerListMixin.java rename to src/main/java/io/github/sakurawald/module/mixin/fake_player_manager/PlayerListMixin.java index ceb0d99fd..5ff6c893e 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/better_fake_player/PlayerListMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/fake_player_manager/PlayerListMixin.java @@ -1,7 +1,7 @@ -package io.github.sakurawald.module.mixin.better_fake_player; +package io.github.sakurawald.module.mixin.fake_player_manager; import io.github.sakurawald.module.ModuleManager; -import io.github.sakurawald.module.initializer.better_fake_player.BetterFakePlayerModule; +import io.github.sakurawald.module.initializer.fake_player_manager.FakePlayerManagerModule; import io.github.sakurawald.util.CarpetUtil; import net.minecraft.network.ClientConnection; import net.minecraft.server.PlayerManager; @@ -16,7 +16,7 @@ @Mixin(PlayerManager.class) public abstract class PlayerListMixin { @Unique - private static final BetterFakePlayerModule module = ModuleManager.getInitializer(BetterFakePlayerModule.class); + private static final FakePlayerManagerModule module = ModuleManager.getInitializer(FakePlayerManagerModule.class); @Inject(at = @At(value = "TAIL"), method = "onPlayerConnect") private void $onPlayerConnect(ClientConnection connection, ServerPlayerEntity serverPlayer, ConnectedClientData commonListenerCookie, CallbackInfo ci) { diff --git a/src/main/java/io/github/sakurawald/module/mixin/better_fake_player/PlayerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/fake_player_manager/PlayerMixin.java similarity index 77% rename from src/main/java/io/github/sakurawald/module/mixin/better_fake_player/PlayerMixin.java rename to src/main/java/io/github/sakurawald/module/mixin/fake_player_manager/PlayerMixin.java index b55deafa0..01af05798 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/better_fake_player/PlayerMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/fake_player_manager/PlayerMixin.java @@ -1,8 +1,8 @@ -package io.github.sakurawald.module.mixin.better_fake_player; +package io.github.sakurawald.module.mixin.fake_player_manager; import carpet.patches.EntityPlayerMPFake; import io.github.sakurawald.module.ModuleManager; -import io.github.sakurawald.module.initializer.better_fake_player.BetterFakePlayerModule; +import io.github.sakurawald.module.initializer.fake_player_manager.FakePlayerManagerModule; import io.github.sakurawald.util.MessageUtil; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; @@ -25,7 +25,7 @@ public abstract class PlayerMixin extends LivingEntity { @Unique - private static final BetterFakePlayerModule betterFakePlayerModule = ModuleManager.getInitializer(BetterFakePlayerModule.class); + private static final FakePlayerManagerModule FAKE_PLAYER_MANAGER_MODULE = ModuleManager.getInitializer(FakePlayerManagerModule.class); protected PlayerMixin(EntityType entityType, World level) { super(entityType, level); @@ -36,13 +36,13 @@ protected PlayerMixin(EntityType entityType, World level private void $interact(Entity target, Hand hand, CallbackInfoReturnable cir) { if (target instanceof EntityPlayerMPFake fakePlayer) { ServerPlayerEntity source = (ServerPlayerEntity) (Object) this; - if (!betterFakePlayerModule.isMyFakePlayer(source, fakePlayer)) { + if (!FAKE_PLAYER_MANAGER_MODULE.isMyFakePlayer(source, fakePlayer)) { // cancel this event cir.setReturnValue(ActionResult.FAIL); // main-hand and off-hand will both trigger this event if (hand == Hand.MAIN_HAND) { - MessageUtil.sendMessage(source, "better_fake_player.manipulate.forbidden"); + MessageUtil.sendMessage(source, "fake_player_manager.manipulate.forbidden"); } } } diff --git a/src/main/java/io/github/sakurawald/module/mixin/skin/PlayerListMixin.java b/src/main/java/io/github/sakurawald/module/mixin/skin/PlayerListMixin.java index 85045248c..1ba039563 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/skin/PlayerListMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/skin/PlayerListMixin.java @@ -42,7 +42,7 @@ private void disconnectAllPlayers(CallbackInfo ci) { private void onPlayerConnected(ClientConnection connection, ServerPlayerEntity serverPlayer, ConnectedClientData commonListenerCookie, CallbackInfo ci) { // if the player isn't a server player entity, it must be someone's fake player if (serverPlayer.getClass() != ServerPlayerEntity.class - && Configs.configHandler.model().modules.better_fake_player.use_local_random_skins_for_fake_player) { + && Configs.configHandler.model().modules.fake_player_manager.use_local_random_skins_for_fake_player) { SkinRestorer.setSkinAsync(server, Collections.singleton(serverPlayer.getGameProfile()), () -> SkinRestorer.getSkinStorage().getRandomSkin(serverPlayer.getUuid())); } } diff --git a/src/main/resources/assets/fuji/lang/en_us.json b/src/main/resources/assets/fuji/lang/en_us.json index 33b9e31d7..e6e5ce546 100755 --- a/src/main/resources/assets/fuji/lang/en_us.json +++ b/src/main/resources/assets/fuji/lang/en_us.json @@ -28,12 +28,12 @@ "pvp.check.off.me": "PvP for you is now off!", "pvp.check.off.others": "PvP for %s is now off!", "back.no_previous_position": "No previous position", - "better_fake_player.who.header": "--- Fake Players ---\n", - "better_fake_player.renew.success": "Your fake-player has been renewed until %s", - "better_fake_player.kick_for_expiration": "Kick fake-player %s (%s) for the expiration", - "better_fake_player.kick_for_amount": "Kick fake-player %s (%s) for the limit", - "better_fake_player.spawn.limit_exceed": "You have reach current fake-player limit", - "better_fake_player.manipulate.forbidden": "You can't manipulate this player", + "fake_player_manager.who.header": "--- Fake Players ---\n", + "fake_player_manager.renew.success": "Your fake-player has been renewed until %s", + "fake_player_manager.kick_for_expiration": "Kick fake-player %s (%s) for the expiration", + "fake_player_manager.kick_for_amount": "Kick fake-player %s (%s) for the limit", + "fake_player_manager.spawn.limit_exceed": "You have reach current fake-player limit", + "fake_player_manager.manipulate.forbidden": "You can't manipulate this player", "command_cooldown.cooldown": "%d s", "reload": "Reload successfully.", "newbie_welcome.welcome_message": "Welcome new player %s to join us!", diff --git a/src/main/resources/assets/fuji/lang/zh_cn.json b/src/main/resources/assets/fuji/lang/zh_cn.json index 534f2286d..9af139c2f 100755 --- a/src/main/resources/assets/fuji/lang/zh_cn.json +++ b/src/main/resources/assets/fuji/lang/zh_cn.json @@ -28,12 +28,12 @@ "pvp.check.off.me": "您已禁用PvP!", "pvp.check.off.others": "玩家 %s 已禁用PvP", "back.no_previous_position": "无保存的位置", - "better_fake_player.who.header": "--- 假人 ---\n", - "better_fake_player.renew.success": "您的假人已续约到 %s", - "better_fake_player.kick_for_expiration": "踢出假人 %s (%s) 因租约到期", - "better_fake_player.kick_for_amount": "踢出假人 %s (%s) 因数量限制动态调整", - "better_fake_player.spawn.limit_exceed": "您已经达到了可生成假人的最大限制", - "better_fake_player.manipulate.forbidden": "您无法操作该假人", + "fake_player_manager.who.header": "--- 假人 ---\n", + "fake_player_manager.renew.success": "您的假人已续约到 %s", + "fake_player_manager.kick_for_expiration": "踢出假人 %s (%s) 因租约到期", + "fake_player_manager.kick_for_amount": "踢出假人 %s (%s) 因数量限制动态调整", + "fake_player_manager.spawn.limit_exceed": "您已经达到了可生成假人的最大限制", + "fake_player_manager.manipulate.forbidden": "您无法操作该假人", "command_cooldown.cooldown": "%d 秒", "reload": "重载完成", "newbie_welcome.welcome_message": "欢迎新玩家 %s 加入我们~", diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index 153dbd004..a77b38e67 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -8,9 +8,9 @@ "afk.PlayerListMixin", "afk.ServerPlayerMixin", "back.ServerPlayerMixin", - "better_fake_player.PlayerCommandMixin", - "better_fake_player.PlayerListMixin", - "better_fake_player.PlayerMixin", + "fake_player_manager.PlayerCommandMixin", + "fake_player_manager.PlayerListMixin", + "fake_player_manager.PlayerMixin", "better_info.InfoCommandMixin", "biome_lookup_cache.NaturalSpawnerMixin", "bypass_chat_speed.ServerGamePacketListenerImplMixin", From 7a88b1bdc4c1d481f0d2d59a5f8b2c80e55f0664 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Wed, 19 Jun 2024 11:41:32 +0800 Subject: [PATCH 09/50] refactor: rename StrongerPlayerList module into FixPlayerListCME module --- .../java/io/github/sakurawald/config/model/ConfigModel.java | 4 ++-- .../PlayerListMixin.java | 4 ++-- .../ServerLevelMixin.java | 4 ++-- src/main/resources/fuji.mixins.json | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) rename src/main/java/io/github/sakurawald/module/mixin/{stronger_player_list => fix_player_list_cme}/PlayerListMixin.java (85%) rename src/main/java/io/github/sakurawald/module/mixin/{stronger_player_list => fix_player_list_cme}/ServerLevelMixin.java (84%) diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index f762e2da9..b88123a74 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -50,7 +50,7 @@ public class Modules { public MultiObsidianPlatform multi_obsidian_platform = new MultiObsidianPlatform(); public OpProtect op_protect = new OpProtect(); public Pvp pvp = new Pvp(); - public StrongerPlayerList stronger_player_list = new StrongerPlayerList(); + public FixPlayerListCME fix_player_list_cme = new FixPlayerListCME(); public WhitelistFix whitelist_fix = new WhitelistFix(); public ZeroCommandPermission zero_command_permission = new ZeroCommandPermission(); public Head head = new Head(); @@ -369,7 +369,7 @@ public class Pvp { public boolean enable = false; } - public class StrongerPlayerList { + public class FixPlayerListCME { public boolean enable = false; } diff --git a/src/main/java/io/github/sakurawald/module/mixin/stronger_player_list/PlayerListMixin.java b/src/main/java/io/github/sakurawald/module/mixin/fix_player_list_cme/PlayerListMixin.java similarity index 85% rename from src/main/java/io/github/sakurawald/module/mixin/stronger_player_list/PlayerListMixin.java rename to src/main/java/io/github/sakurawald/module/mixin/fix_player_list_cme/PlayerListMixin.java index 7e8a82bac..8efddba5a 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/stronger_player_list/PlayerListMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/fix_player_list_cme/PlayerListMixin.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.module.mixin.stronger_player_list; +package io.github.sakurawald.module.mixin.fix_player_list_cme; import io.github.sakurawald.Fuji; import org.spongepowered.asm.mixin.Final; @@ -27,7 +27,7 @@ public abstract class PlayerListMixin { private void $init(CallbackInfo ci) { players = new CopyOnWriteArrayList<>() { { - Fuji.LOGGER.info("Patch stronger player list for Server#PlayerList"); + Fuji.LOGGER.info("Fix player list CME for Server#PlayerList"); } }; } diff --git a/src/main/java/io/github/sakurawald/module/mixin/stronger_player_list/ServerLevelMixin.java b/src/main/java/io/github/sakurawald/module/mixin/fix_player_list_cme/ServerLevelMixin.java similarity index 84% rename from src/main/java/io/github/sakurawald/module/mixin/stronger_player_list/ServerLevelMixin.java rename to src/main/java/io/github/sakurawald/module/mixin/fix_player_list_cme/ServerLevelMixin.java index a37ae3ce8..f0e750910 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/stronger_player_list/ServerLevelMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/fix_player_list_cme/ServerLevelMixin.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.module.mixin.stronger_player_list; +package io.github.sakurawald.module.mixin.fix_player_list_cme; import io.github.sakurawald.Fuji; import org.spongepowered.asm.mixin.Final; @@ -28,7 +28,7 @@ public abstract class ServerLevelMixin { ServerWorld that = (ServerWorld) (Object) this; players = new CopyOnWriteArrayList<>() { { - Fuji.LOGGER.info("Patch stronger player list for {}", that.getRegistryKey().getValue()); + Fuji.LOGGER.info("Fix player list CME for {}", that.getRegistryKey().getValue()); } }; } diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index a77b38e67..aff52b7a2 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -43,8 +43,8 @@ "sit.InteractModifierMixin", "skin.PlayerListMixin", "skin.ServerLoginNetworkHandlerMixin", - "stronger_player_list.PlayerListMixin", - "stronger_player_list.ServerLevelMixin", + "fix_player_list_cme.PlayerListMixin", + "fix_player_list_cme.ServerLevelMixin", "system_message.ComponentMixin", "teleport_warmup.ServerPlayerMixin", "top_chunks.ThreadedAnvilChunkStorageMixin", From 8643e57d936502d258aac351c1f4c4b08feabc72 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Wed, 19 Jun 2024 11:43:06 +0800 Subject: [PATCH 10/50] refactor: rename WhitelistFix module into FixWhitelist module --- .../java/io/github/sakurawald/config/model/ConfigModel.java | 4 ++-- .../{whitelist_fix => fix_whitelist}/UserWhiteListMixin.java | 2 +- src/main/resources/fuji.mixins.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/main/java/io/github/sakurawald/module/mixin/{whitelist_fix => fix_whitelist}/UserWhiteListMixin.java (96%) diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index b88123a74..8e0188ba6 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -51,7 +51,7 @@ public class Modules { public OpProtect op_protect = new OpProtect(); public Pvp pvp = new Pvp(); public FixPlayerListCME fix_player_list_cme = new FixPlayerListCME(); - public WhitelistFix whitelist_fix = new WhitelistFix(); + public FixWhitelist fix_whitelist = new FixWhitelist(); public ZeroCommandPermission zero_command_permission = new ZeroCommandPermission(); public Head head = new Head(); public Profiler profiler = new Profiler(); @@ -373,7 +373,7 @@ public class FixPlayerListCME { public boolean enable = false; } - public class WhitelistFix { + public class FixWhitelist { public boolean enable = false; } diff --git a/src/main/java/io/github/sakurawald/module/mixin/whitelist_fix/UserWhiteListMixin.java b/src/main/java/io/github/sakurawald/module/mixin/fix_whitelist/UserWhiteListMixin.java similarity index 96% rename from src/main/java/io/github/sakurawald/module/mixin/whitelist_fix/UserWhiteListMixin.java rename to src/main/java/io/github/sakurawald/module/mixin/fix_whitelist/UserWhiteListMixin.java index fb31a07c2..781d6cde5 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/whitelist_fix/UserWhiteListMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/fix_whitelist/UserWhiteListMixin.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.module.mixin.whitelist_fix; +package io.github.sakurawald.module.mixin.fix_whitelist; import com.mojang.authlib.GameProfile; import net.minecraft.network.ClientConnection; diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index aff52b7a2..2b5be8479 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -48,7 +48,7 @@ "system_message.ComponentMixin", "teleport_warmup.ServerPlayerMixin", "top_chunks.ThreadedAnvilChunkStorageMixin", - "whitelist_fix.UserWhiteListMixin", + "fix_whitelist.UserWhiteListMixin", "works.HopperBlockEntityMixin", "zero_command_permission.CommandNodeAccessor" ], From b58b6ac55438f2032fc114309bb3a24664a16edc Mon Sep 17 00:00:00 2001 From: sakurawald Date: Wed, 19 Jun 2024 11:48:41 +0800 Subject: [PATCH 11/50] refactor: rename ZeroCommandPermissionModule.java module into CommandPermissionModule module --- README.md | 16 ++++++++-------- .../sakurawald/config/model/ConfigModel.java | 4 ++-- .../CommandPermissionModule.java} | 18 +++++++++--------- .../CommandNodeAccessor.java | 2 +- src/main/resources/fuji.mixins.json | 2 +- 5 files changed, 21 insertions(+), 21 deletions(-) rename src/main/java/io/github/sakurawald/module/initializer/{zero_command_permission/ZeroCommandPermissionModule.java => command_permission/CommandPermissionModule.java} (77%) rename src/main/java/io/github/sakurawald/module/mixin/{zero_command_permission => command_permission}/CommandNodeAccessor.java (85%) diff --git a/README.md b/README.md index fc1830010..ef0ea8a6b 100755 --- a/README.md +++ b/README.md @@ -118,13 +118,13 @@ provides /head command to buy player heads. #### ProfilerModule provides /profiler to sample the server health. (Including os, vm, cpu, ram, tps, mspt and gc) -#### ZeroCommandPermissionModule -this module modifies ALL commands (even the command is registered from other mods) and adds a prefix-permission (we called it zero-permission) for the command. If the player has zero-permission, then we check zero-permission for that command, otherwise check the command's original requires-permission. +#### CommandPermissionModule +this module modifies ALL commands (even the command is registered from other mods) and adds a prefix-permission (we called it fuji-permission) for the command. If the player has fuji-permission, then we check fuji-permission for that command, otherwise check the command's original requires-permission. -> Tips: if you don't know how to determine command-node name, you can just type `/lp> group default permission zero.` and let luckperms tell you what command-node names you can use. -> - Allow the default group to use a command by adding a zero-permission (e.g. /seed) -> `/lp group default permission set zero.seed true` -> - Disallow the default group to use a command by adding a zero-permission (e.g. /help) -> `/lp group default permission set zero.help false` -> - Disallow the default group to use a sub-command from a command by adding a zero-permission (e.g. /player [player] mount) -> `/lp group default permission set zero.player.player.mount false` +> Tips: if you don't know how to determine command-node name, you can just type `/lp group default permission fuji.` and let luckperms tell you what command-node names you can use. +> - Allow the default group to use a command by adding a fuji-permission (e.g. /seed) -> `/lp group default permission set fuji.seed true` +> - Disallow the default group to use a command by adding a fuji-permission (e.g. /help) -> `/lp group default permission set fuji.help false` +> - Disallow the default group to use a sub-command from a command by adding a fuji-permission (e.g. /player [player] mount) -> `/lp group default permission set fuji.player.player.mount false` #### BypassThingsModule provides options to bypass some annoyed things. @@ -282,9 +282,9 @@ that you don't need to find out where the config files are. Normally, the newer version will generate missing configuration keys automatically, but if this doesn't work, you can delete the old config file and restart the server to let the newer version generate the default config file. # Permission -This mod uses a low-level permission system, which means that most of the admin commands are required level-permission to use. However, if you really want a command-permission-node for every command, you can use the `zero-command-permission` module (This module adds a prefix command-permission for ALL commands, even the command is not provided by this mod!). +This mod uses a low-level permission system, which means that most of the admin commands are required level-permission to use. However, if you really want a command-permission-node for every command, you can use the `fuji-command-permission` module (This module adds a prefix command-permission for ALL commands, even the command is not provided by this mod!). -> In other words, most of the commands doesn't require any permission to use, but if you want, you can use `ZeroPermissionModule` to add a prefix-permission for every command! +> In other words, most of the commands doesn't require any permission to use, but if you want, you can use `CommandPermissionModule` to add a prefix-permission for every command! # Optimization For a better server performance and without vanilla sacrifice, we recommend you to use `Lithium` and `Krypton` with this mod. diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index 8e0188ba6..1148a32e9 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -52,7 +52,7 @@ public class Modules { public Pvp pvp = new Pvp(); public FixPlayerListCME fix_player_list_cme = new FixPlayerListCME(); public FixWhitelist fix_whitelist = new FixWhitelist(); - public ZeroCommandPermission zero_command_permission = new ZeroCommandPermission(); + public CommandPermission command_permission = new CommandPermission(); public Head head = new Head(); public Profiler profiler = new Profiler(); public CommandSpy command_spy = new CommandSpy(); @@ -378,7 +378,7 @@ public class FixWhitelist { public boolean enable = false; } - public class ZeroCommandPermission { + public class CommandPermission { public boolean enable = false; } diff --git a/src/main/java/io/github/sakurawald/module/initializer/zero_command_permission/ZeroCommandPermissionModule.java b/src/main/java/io/github/sakurawald/module/initializer/command_permission/CommandPermissionModule.java similarity index 77% rename from src/main/java/io/github/sakurawald/module/initializer/zero_command_permission/ZeroCommandPermissionModule.java rename to src/main/java/io/github/sakurawald/module/initializer/command_permission/CommandPermissionModule.java index cbe19f435..8837e0d85 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/zero_command_permission/ZeroCommandPermissionModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/command_permission/CommandPermissionModule.java @@ -1,9 +1,9 @@ -package io.github.sakurawald.module.initializer.zero_command_permission; +package io.github.sakurawald.module.initializer.command_permission; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.tree.CommandNode; import io.github.sakurawald.module.initializer.ModuleInitializer; -import io.github.sakurawald.module.mixin.zero_command_permission.CommandNodeAccessor; +import io.github.sakurawald.module.mixin.command_permission.CommandNodeAccessor; import me.lucko.fabric.api.permissions.v0.Permissions; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.util.TriState; @@ -12,7 +12,7 @@ import java.util.function.Predicate; -public class ZeroCommandPermissionModule extends ModuleInitializer { +public class CommandPermissionModule extends ModuleInitializer { @Override public void onInitialize() { @@ -36,23 +36,23 @@ private void alterCommandNode(CommandDispatcher dispatcher, for (CommandNode child : node.getChildren()) { alterCommandNode(dispatcher, child); } - ((CommandNodeAccessor) node).setRequirement(createZeroPermission(commandPath, node.getRequirement())); + ((CommandNodeAccessor) node).setRequirement(createWrappedPermission(commandPath, node.getRequirement())); } - private Predicate createZeroPermission(String commandPath, Predicate original) { + private Predicate createWrappedPermission(String commandPath, Predicate original) { return source -> { // ignore the non-player command source if (source.getPlayer() == null) return original.test(source); try { - /* By default, command /seed has no permission. So we can create a zero-permission "zero.seed" + /* By default, command /seed has no permission. So we can create a wrapped-permission "fuji.seed" and then grant this permission to anyone so that he can use /seed command. - And also set other's permission zero.seed false to dis-allow them to use /seed command. - If a command doesn't have a zero-permission, then it will use the original requirement-supplier. + And also set other's permission fuji.seed false to dis-allow them to use /seed command. + If a command doesn't have a wrapped-permission, then it will use the original requirement-supplier. Only valid command has its command path (command-alias also has its path, but it will redirect the execution to the real command-path) */ - TriState triState = Permissions.getPermissionValue(source, "zero.%s".formatted(commandPath)); + TriState triState = Permissions.getPermissionValue(source, "fuji.%s".formatted(commandPath)); return triState.orElseGet(() -> original.test(source)); } catch (Throwable use_original_predicate_if_failed) { return original.test(source); diff --git a/src/main/java/io/github/sakurawald/module/mixin/zero_command_permission/CommandNodeAccessor.java b/src/main/java/io/github/sakurawald/module/mixin/command_permission/CommandNodeAccessor.java similarity index 85% rename from src/main/java/io/github/sakurawald/module/mixin/zero_command_permission/CommandNodeAccessor.java rename to src/main/java/io/github/sakurawald/module/mixin/command_permission/CommandNodeAccessor.java index 4ca3ffa95..243f3d3d7 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/zero_command_permission/CommandNodeAccessor.java +++ b/src/main/java/io/github/sakurawald/module/mixin/command_permission/CommandNodeAccessor.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.module.mixin.zero_command_permission; +package io.github.sakurawald.module.mixin.command_permission; import com.mojang.brigadier.tree.CommandNode; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index 2b5be8479..dc6b10c8a 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -50,7 +50,7 @@ "top_chunks.ThreadedAnvilChunkStorageMixin", "fix_whitelist.UserWhiteListMixin", "works.HopperBlockEntityMixin", - "zero_command_permission.CommandNodeAccessor" + "command_permission.CommandNodeAccessor" ], "injectors": { "defaultRequire": 1 From 5ef282da99416fea13052cfe638988cfa8b38de3 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Wed, 19 Jun 2024 13:01:55 +0800 Subject: [PATCH 12/50] refactor: rename some classes + remove: unused methods --- build.gradle | 13 +++------ src/main/java/io/github/sakurawald/Fuji.java | 3 -- .../teleport_warmup => common}/Position.java | 2 +- .../sakurawald/config/model/HomeModel.java | 2 +- .../module/initializer/afk/AfkModule.java | 4 +-- ...ateAccessor.java => AfkStateAccessor.java} | 2 +- .../module/initializer/back/BackModule.java | 2 +- .../module/initializer/home/HomeModule.java | 2 +- .../module/initializer/motd/MotdModule.java | 1 - .../MultiObsidianPlatformModule.java | 9 ------ .../initializer/repair/RepairModule.java | 1 - .../resource_world/ResourceWorldManager.java | 2 +- .../teleport_warmup/TeleportTicket.java | 1 + .../module/initializer/test/TestModule.java | 29 ------------------- .../module/initializer/tpa/TpaModule.java | 1 - .../module/mixin/ModuleMixinConfigPlugin.java | 3 ++ .../module/mixin/afk/PlayerListMixin.java | 4 +-- .../module/mixin/afk/ServerPlayerMixin.java | 8 ++--- .../ServerStatusPacketListenerImplMixin.java | 1 - .../ServerPlayNetworkHandlerMixin.java | 3 +- .../teleport_warmup/ServerPlayerMixin.java | 2 +- .../github/sakurawald/util/MessageUtil.java | 1 - .../github/sakurawald/util/RegistryUtil.java | 2 ++ .../github/sakurawald/util/ScheduleUtil.java | 2 ++ 24 files changed, 29 insertions(+), 71 deletions(-) rename src/main/java/io/github/sakurawald/{module/initializer/teleport_warmup => common}/Position.java (96%) rename src/main/java/io/github/sakurawald/module/initializer/afk/{ServerPlayerAfkStateAccessor.java => AfkStateAccessor.java} (82%) diff --git a/build.gradle b/build.gradle index 076758f99..b56108ec2 100755 --- a/build.gradle +++ b/build.gradle @@ -53,11 +53,10 @@ dependencies { implementation group: 'com.google.code.gson', name: 'gson', version: "${project.gson_version}" - include(implementation(annotationProcessor("com.github.llamalad7.mixinextras:mixinextras-fabric:${project.mixin_extras_version}"))) - modImplementation("carpet:fabric-carpet:${project.carpet_core_version}") modImplementation include("me.lucko:fabric-permissions-api:${project.fabric_permissions_version}") + modImplementation include("net.kyori:adventure-platform-fabric:${project.adventure_platform_fabric_version}") include(implementation "net.kyori:adventure-text-minimessage:${project.adventure_api_version}") @@ -65,6 +64,7 @@ dependencies { implementation "me.lucko:spark-api:${project.spark_version}" + include(implementation(annotationProcessor("com.github.llamalad7.mixinextras:mixinextras-fabric:${project.mixin_extras_version}"))) include(implementation "org.apache.commons:commons-compress:${project.apache_commons_compression_version}") include(implementation "commons-io:commons-io:${project.apache_commons_io_version}") include(implementation "org.quartz-scheduler:quartz:${project.quartz_version}") @@ -118,7 +118,7 @@ publishing { } } -// build.gradle +// modrinth modrinth { token = "$System.env.modrinth_token" projectId = "1TowMm2v" @@ -134,15 +134,10 @@ modrinth { } syncBodyFrom = rootProject.file("README.md").text } - -// replace readme tasks.modrinth.dependsOn(tasks.modrinthSyncBody) -tasks.register('replaceReadme') { - // todo -} tasks.modrinthSyncBody.dependsOn(tasks.replaceReadme) - +// test framework test { useJUnitPlatform() } \ No newline at end of file diff --git a/src/main/java/io/github/sakurawald/Fuji.java b/src/main/java/io/github/sakurawald/Fuji.java index f9e286bbe..4609c3b0c 100644 --- a/src/main/java/io/github/sakurawald/Fuji.java +++ b/src/main/java/io/github/sakurawald/Fuji.java @@ -23,9 +23,6 @@ // TODO: playtime(every/for) rewards and rank like module // TODO: kit module -> spec-command // TODO: luckperms context calculate module - -// TODO: remove tick chunk cache module - public class Fuji implements ModInitializer { public static final String MOD_ID = "fuji"; public static final Logger LOGGER = LogUtil.createLogger("Fuji"); diff --git a/src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/Position.java b/src/main/java/io/github/sakurawald/common/Position.java similarity index 96% rename from src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/Position.java rename to src/main/java/io/github/sakurawald/common/Position.java index 37d8c7f3f..81025b15b 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/Position.java +++ b/src/main/java/io/github/sakurawald/common/Position.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.module.initializer.teleport_warmup; +package io.github.sakurawald.common; import io.github.sakurawald.Fuji; import io.github.sakurawald.util.MessageUtil; diff --git a/src/main/java/io/github/sakurawald/config/model/HomeModel.java b/src/main/java/io/github/sakurawald/config/model/HomeModel.java index f08f1544b..289988acf 100644 --- a/src/main/java/io/github/sakurawald/config/model/HomeModel.java +++ b/src/main/java/io/github/sakurawald/config/model/HomeModel.java @@ -1,6 +1,6 @@ package io.github.sakurawald.config.model; -import io.github.sakurawald.module.initializer.teleport_warmup.Position; +import io.github.sakurawald.common.Position; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/io/github/sakurawald/module/initializer/afk/AfkModule.java b/src/main/java/io/github/sakurawald/module/initializer/afk/AfkModule.java index 8bf10e8ac..d8c5c0a1e 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/afk/AfkModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/afk/AfkModule.java @@ -46,7 +46,7 @@ public void registerCommand(CommandDispatcher dispatcher, C private int $afk(CommandContext ctx) { return CommandUtil.playerOnlyCommand(ctx, (player -> { // note: issue command will update lastLastActionTime, so it's impossible to use /afk to disable afk - ((ServerPlayerAfkStateAccessor) player).fuji$setAfk(true); + ((AfkStateAccessor) player).fuji$setAfk(true); MessageUtil.sendMessage(player, "afk.on"); return Command.SINGLE_SUCCESS; })); @@ -57,7 +57,7 @@ public static class AfkCheckerJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { for (ServerPlayerEntity player : Fuji.SERVER.getPlayerManager().getPlayerList()) { - ServerPlayerAfkStateAccessor afk_player = (ServerPlayerAfkStateAccessor) player; + AfkStateAccessor afk_player = (AfkStateAccessor) player; // get last action time long lastActionTime = player.getLastActionTime(); diff --git a/src/main/java/io/github/sakurawald/module/initializer/afk/ServerPlayerAfkStateAccessor.java b/src/main/java/io/github/sakurawald/module/initializer/afk/AfkStateAccessor.java similarity index 82% rename from src/main/java/io/github/sakurawald/module/initializer/afk/ServerPlayerAfkStateAccessor.java rename to src/main/java/io/github/sakurawald/module/initializer/afk/AfkStateAccessor.java index 5bffa2ff5..8f735beeb 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/afk/ServerPlayerAfkStateAccessor.java +++ b/src/main/java/io/github/sakurawald/module/initializer/afk/AfkStateAccessor.java @@ -1,6 +1,6 @@ package io.github.sakurawald.module.initializer.afk; -public interface ServerPlayerAfkStateAccessor { +public interface AfkStateAccessor { void fuji$setAfk(boolean flag); diff --git a/src/main/java/io/github/sakurawald/module/initializer/back/BackModule.java b/src/main/java/io/github/sakurawald/module/initializer/back/BackModule.java index 78cd3a2a5..38e71a032 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/back/BackModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/back/BackModule.java @@ -5,7 +5,7 @@ import com.mojang.brigadier.context.CommandContext; import io.github.sakurawald.config.Configs; import io.github.sakurawald.module.initializer.ModuleInitializer; -import io.github.sakurawald.module.initializer.teleport_warmup.Position; +import io.github.sakurawald.common.Position; import io.github.sakurawald.util.CommandUtil; import io.github.sakurawald.util.MessageUtil; import lombok.Getter; diff --git a/src/main/java/io/github/sakurawald/module/initializer/home/HomeModule.java b/src/main/java/io/github/sakurawald/module/initializer/home/HomeModule.java index eec76a775..9509bc341 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/home/HomeModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/home/HomeModule.java @@ -10,7 +10,7 @@ import io.github.sakurawald.config.handler.ObjectConfigHandler; import io.github.sakurawald.config.model.HomeModel; import io.github.sakurawald.module.initializer.ModuleInitializer; -import io.github.sakurawald.module.initializer.teleport_warmup.Position; +import io.github.sakurawald.common.Position; import io.github.sakurawald.util.CommandUtil; import io.github.sakurawald.util.MessageUtil; import io.github.sakurawald.util.ScheduleUtil; diff --git a/src/main/java/io/github/sakurawald/module/initializer/motd/MotdModule.java b/src/main/java/io/github/sakurawald/module/initializer/motd/MotdModule.java index 589c4a2c1..0d4e47568 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/motd/MotdModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/motd/MotdModule.java @@ -64,5 +64,4 @@ public Text getRandomDescription() { return MessageUtil.ofVomponent(descriptions.get(new Random().nextInt(descriptions.size()))); } - } diff --git a/src/main/java/io/github/sakurawald/module/initializer/multi_obsidian_platform/MultiObsidianPlatformModule.java b/src/main/java/io/github/sakurawald/module/initializer/multi_obsidian_platform/MultiObsidianPlatformModule.java index b05ea4193..d10823669 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/multi_obsidian_platform/MultiObsidianPlatformModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/multi_obsidian_platform/MultiObsidianPlatformModule.java @@ -83,13 +83,4 @@ public BlockPos transform(BlockPos bp) { return TRANSFORM_CACHE.get(bp); } - public void makeObsidianPlatform(ServerWorld serverLevel, BlockPos centerBlockPos) { - int i = centerBlockPos.getX(); - int j = centerBlockPos.getY() - 2; - int k = centerBlockPos.getZ(); - BlockPos.iterate(i - 2, j + 1, k - 2, i + 2, j + 3, k + 2).forEach(blockPos -> serverLevel.setBlockState(blockPos, Blocks.AIR.getDefaultState())); - BlockPos.iterate(i - 2, j, k - 2, i + 2, j, k + 2).forEach(blockPos -> serverLevel.setBlockState(blockPos, Blocks.OBSIDIAN.getDefaultState())); - } - - } diff --git a/src/main/java/io/github/sakurawald/module/initializer/repair/RepairModule.java b/src/main/java/io/github/sakurawald/module/initializer/repair/RepairModule.java index 46a5f8930..5bb2784cc 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/repair/RepairModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/repair/RepairModule.java @@ -13,7 +13,6 @@ public class RepairModule extends ModuleInitializer { - @Override public void registerCommand(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess, CommandManager.RegistrationEnvironment environment) { dispatcher.register(CommandManager.literal("repair").executes(this::$repair)); diff --git a/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldManager.java b/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldManager.java index 11a9b189b..14403605f 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldManager.java +++ b/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldManager.java @@ -2,7 +2,7 @@ import io.github.sakurawald.module.ModuleManager; import io.github.sakurawald.module.initializer.resource_world.interfaces.SimpleRegistryMixinInterface; -import io.github.sakurawald.module.initializer.teleport_warmup.Position; +import io.github.sakurawald.common.Position; import io.github.sakurawald.module.initializer.teleport_warmup.TeleportTicket; import io.github.sakurawald.module.initializer.teleport_warmup.TeleportWarmupModule; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; diff --git a/src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/TeleportTicket.java b/src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/TeleportTicket.java index a35859a98..5331fa508 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/TeleportTicket.java +++ b/src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/TeleportTicket.java @@ -1,5 +1,6 @@ package io.github.sakurawald.module.initializer.teleport_warmup; +import io.github.sakurawald.common.Position; import io.github.sakurawald.util.MessageUtil; import net.kyori.adventure.bossbar.BossBar; import net.minecraft.server.network.ServerPlayerEntity; diff --git a/src/main/java/io/github/sakurawald/module/initializer/test/TestModule.java b/src/main/java/io/github/sakurawald/module/initializer/test/TestModule.java index 6fb8ab2f8..ffccd5353 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/test/TestModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/test/TestModule.java @@ -17,31 +17,6 @@ public class TestModule extends ModuleInitializer { - @SneakyThrows - private static int simulateLag(CommandContext ctx) { - Fuji.SERVER.getCommandManager().getDispatcher().execute("execute in minecraft:overworld run test fake-players", ctx.getSource()); - Fuji.SERVER.getCommandManager().getDispatcher().execute("execute in minecraft:overworld run time set midnight", ctx.getSource()); - Fuji.SERVER.getCommandManager().getDispatcher().execute("execute in minecraft:the_nether run test fake-players", ctx.getSource()); - Fuji.SERVER.getCommandManager().getDispatcher().execute("execute in minecraft:the_end run test fake-players", ctx.getSource()); - - return Command.SINGLE_SUCCESS; - } - - @SuppressWarnings({"ConstantValue", "ReassignedVariable", "PointlessArithmeticExpression", "DataFlowIssue"}) - @SneakyThrows - private static int fakePlayers(CommandContext ctx) { - int amount = 25; - int startIndex = 0; - if (ctx.getSource().getWorld().getRegistryKey() == World.OVERWORLD) startIndex = amount * 0; - if (ctx.getSource().getWorld().getRegistryKey() == World.NETHER) startIndex = amount * 1; - if (ctx.getSource().getWorld().getRegistryKey() == World.END) startIndex = amount * 2; - for (int i = 0; i < amount; i++) { - int distance = i * 100; - Fuji.SERVER.getCommandManager().getDispatcher().execute("player %d spawn at %d 96 %d".formatted(startIndex++, distance, distance), ctx.getSource()); - } - return Command.SINGLE_SUCCESS; - } - private static int clearChat(CommandContext ctx) { for (int i = 0; i < 50; i++) { ctx.getSource().sendMessage(Component.empty()); @@ -52,17 +27,13 @@ private static int clearChat(CommandContext ctx) { private static int magic(CommandContext ctx) { ServerPlayerEntity player = ctx.getSource().getPlayer(); player.sendMessage(Text.literal(String.valueOf(player.getMainHandStack().getComponents()))); - return 1; } - @Override public void registerCommand(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess, CommandManager.RegistrationEnvironment environment) { dispatcher.register( CommandManager.literal("test").requires(s -> s.hasPermissionLevel(4)) - .then(CommandManager.literal("fake-players").executes(TestModule::fakePlayers)) - .then(CommandManager.literal("simulate-lag").executes(TestModule::simulateLag)) .then(CommandManager.literal("clear-chat").executes(TestModule::clearChat)) .then(CommandManager.literal("magic").executes(TestModule::magic)) ); diff --git a/src/main/java/io/github/sakurawald/module/initializer/tpa/TpaModule.java b/src/main/java/io/github/sakurawald/module/initializer/tpa/TpaModule.java index 39f740d93..d2fbe3665 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/tpa/TpaModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/tpa/TpaModule.java @@ -27,7 +27,6 @@ public class TpaModule extends ModuleInitializer { @Getter private final ArrayList requests = new ArrayList<>(); - @SuppressWarnings("unused") @Override public void registerCommand(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess, CommandManager.RegistrationEnvironment environment) { diff --git a/src/main/java/io/github/sakurawald/module/mixin/ModuleMixinConfigPlugin.java b/src/main/java/io/github/sakurawald/module/mixin/ModuleMixinConfigPlugin.java index 981dc703c..cb79e6077 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/ModuleMixinConfigPlugin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/ModuleMixinConfigPlugin.java @@ -33,7 +33,10 @@ public String getRefMapperConfig() { @Override public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { String basePackageName = ModuleManager.calculateBasePackageName(this.getClass(), mixinClassName); + + // bypass if (basePackageName.startsWith("_")) return true; + return ModuleManager.enableModule(mixinConfigs, basePackageName); } diff --git a/src/main/java/io/github/sakurawald/module/mixin/afk/PlayerListMixin.java b/src/main/java/io/github/sakurawald/module/mixin/afk/PlayerListMixin.java index ee693cd71..6da23e9c3 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/afk/PlayerListMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/afk/PlayerListMixin.java @@ -1,6 +1,6 @@ package io.github.sakurawald.module.mixin.afk; -import io.github.sakurawald.module.initializer.afk.ServerPlayerAfkStateAccessor; +import io.github.sakurawald.module.initializer.afk.AfkStateAccessor; import net.minecraft.network.ClientConnection; import net.minecraft.server.PlayerManager; import net.minecraft.server.network.ConnectedClientData; @@ -15,7 +15,7 @@ public abstract class PlayerListMixin { @Inject(at = @At(value = "TAIL"), method = "onPlayerConnect") private void $onPlayerConnect(ClientConnection connection, ServerPlayerEntity serverPlayer, ConnectedClientData commonListenerCookie, CallbackInfo ci) { - ServerPlayerAfkStateAccessor afk_player = (ServerPlayerAfkStateAccessor) serverPlayer; + AfkStateAccessor afk_player = (AfkStateAccessor) serverPlayer; afk_player.fuji$setLastLastActionTime(serverPlayer.getLastActionTime()); } } \ No newline at end of file diff --git a/src/main/java/io/github/sakurawald/module/mixin/afk/ServerPlayerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/afk/ServerPlayerMixin.java index 4d6fcfb04..105ff8355 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/afk/ServerPlayerMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/afk/ServerPlayerMixin.java @@ -1,7 +1,7 @@ package io.github.sakurawald.module.mixin.afk; import io.github.sakurawald.config.Configs; -import io.github.sakurawald.module.initializer.afk.ServerPlayerAfkStateAccessor; +import io.github.sakurawald.module.initializer.afk.AfkStateAccessor; import io.github.sakurawald.util.MessageUtil; import net.kyori.adventure.text.TextReplacementConfig; import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; @@ -22,11 +22,11 @@ import static io.github.sakurawald.util.MessageUtil.toVomponent; @Mixin(ServerPlayerEntity.class) - -public abstract class ServerPlayerMixin implements ServerPlayerAfkStateAccessor { +public abstract class ServerPlayerMixin implements AfkStateAccessor { @Unique private final ServerPlayerEntity player = (ServerPlayerEntity) (Object) this; + @Shadow @Final public MinecraftServer server; @@ -39,7 +39,7 @@ public abstract class ServerPlayerMixin implements ServerPlayerAfkStateAccessor @Inject(method = "getPlayerListName", at = @At("HEAD"), cancellable = true) public void $getPlayerListName(CallbackInfoReturnable cir) { - ServerPlayerAfkStateAccessor accessor = (ServerPlayerAfkStateAccessor) player; + AfkStateAccessor accessor = (AfkStateAccessor) player; if (accessor.fuji$isAfk()) { cir.setReturnValue(Text.literal("afk " + player.getGameProfile().getName())); diff --git a/src/main/java/io/github/sakurawald/module/mixin/motd/ServerStatusPacketListenerImplMixin.java b/src/main/java/io/github/sakurawald/module/mixin/motd/ServerStatusPacketListenerImplMixin.java index 9b9c2b5b4..46e4613b4 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/motd/ServerStatusPacketListenerImplMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/motd/ServerStatusPacketListenerImplMixin.java @@ -41,7 +41,6 @@ abstract class ServerStatusPacketListenerImplMixin { @Unique private static final MotdModule module = ModuleManager.getInitializer(MotdModule.class); - @Redirect(method = "onRequest", at = @At(value = "FIELD", target = "Lnet/minecraft/server/network/ServerQueryNetworkHandler;metadata:Lnet/minecraft/server/ServerMetadata;")) public ServerMetadata $handleStatusRequest(final ServerQueryNetworkHandler instance) { ServerMetadata vanillaStatus = Fuji.SERVER.getServerMetadata(); diff --git a/src/main/java/io/github/sakurawald/module/mixin/op_protect/ServerPlayNetworkHandlerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/op_protect/ServerPlayNetworkHandlerMixin.java index 5f845b42b..ce659863d 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/op_protect/ServerPlayNetworkHandlerMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/op_protect/ServerPlayNetworkHandlerMixin.java @@ -2,6 +2,7 @@ import io.github.sakurawald.Fuji; +import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents; import net.minecraft.network.DisconnectionInfo; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; @@ -22,7 +23,7 @@ public class ServerPlayNetworkHandlerMixin { @Inject(at = @At(value = "HEAD"), method = "onDisconnected") private void $onDisconnected(DisconnectionInfo disconnectionInfo, CallbackInfo ci) { if (Fuji.SERVER.getPlayerManager().isOperator(player.getGameProfile())) { - Fuji.LOGGER.info("op protect -> deop " + player.getGameProfile().getName()); + Fuji.LOGGER.info("op protect -> deop {}", player.getGameProfile().getName()); Fuji.SERVER.getPlayerManager().removeFromOperators(player.getGameProfile()); } } diff --git a/src/main/java/io/github/sakurawald/module/mixin/teleport_warmup/ServerPlayerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/teleport_warmup/ServerPlayerMixin.java index 5d097441e..ef29b9cda 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/teleport_warmup/ServerPlayerMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/teleport_warmup/ServerPlayerMixin.java @@ -2,7 +2,7 @@ import io.github.sakurawald.module.ModuleManager; import io.github.sakurawald.module.initializer.back.BackModule; -import io.github.sakurawald.module.initializer.teleport_warmup.Position; +import io.github.sakurawald.common.Position; import io.github.sakurawald.module.initializer.teleport_warmup.ServerPlayerCombatStateAccessor; import io.github.sakurawald.module.initializer.teleport_warmup.TeleportTicket; import io.github.sakurawald.module.initializer.teleport_warmup.TeleportWarmupModule; diff --git a/src/main/java/io/github/sakurawald/util/MessageUtil.java b/src/main/java/io/github/sakurawald/util/MessageUtil.java index 0c4dda1c5..7a09347f6 100644 --- a/src/main/java/io/github/sakurawald/util/MessageUtil.java +++ b/src/main/java/io/github/sakurawald/util/MessageUtil.java @@ -24,7 +24,6 @@ import java.util.Map; @UtilityClass - public class MessageUtil { private static final FabricServerAudiences adventure = FabricServerAudiences.of(Fuji.SERVER); @Getter diff --git a/src/main/java/io/github/sakurawald/util/RegistryUtil.java b/src/main/java/io/github/sakurawald/util/RegistryUtil.java index 694c52841..177232df0 100644 --- a/src/main/java/io/github/sakurawald/util/RegistryUtil.java +++ b/src/main/java/io/github/sakurawald/util/RegistryUtil.java @@ -1,8 +1,10 @@ package io.github.sakurawald.util; import io.github.sakurawald.Fuji; +import lombok.experimental.UtilityClass; import net.minecraft.registry.RegistryWrapper; +@UtilityClass public class RegistryUtil { public static RegistryWrapper.WrapperLookup getDefaultWrapperLookup(){ return Fuji.SERVER.getRegistryManager(); diff --git a/src/main/java/io/github/sakurawald/util/ScheduleUtil.java b/src/main/java/io/github/sakurawald/util/ScheduleUtil.java index 17a919472..766e48ca0 100644 --- a/src/main/java/io/github/sakurawald/util/ScheduleUtil.java +++ b/src/main/java/io/github/sakurawald/util/ScheduleUtil.java @@ -3,6 +3,7 @@ import io.github.sakurawald.config.Configs; import lombok.Getter; +import lombok.experimental.UtilityClass; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.config.Configurator; import org.quartz.*; @@ -16,6 +17,7 @@ import static io.github.sakurawald.Fuji.LOGGER; +@UtilityClass public class ScheduleUtil { public static final String CRON_EVERY_MINUTE = "0 * * ? * * *"; From 90db1a37c3688d40882c5796330b8a05a6a5d921 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Wed, 19 Jun 2024 13:17:46 +0800 Subject: [PATCH 13/50] refactor: use custom events --- .../event/PrePlayerDisconnectEvent.java | 27 +++++++++++++++++++ .../op_protect/OpProtectModule.java | 20 ++++++++++++++ .../event}/ServerPlayNetworkHandlerMixin.java | 19 ++++++------- src/main/resources/fuji.mixins.json | 17 ++++++------ 4 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 src/main/java/io/github/sakurawald/common/event/PrePlayerDisconnectEvent.java create mode 100644 src/main/java/io/github/sakurawald/module/initializer/op_protect/OpProtectModule.java rename src/main/java/io/github/sakurawald/module/mixin/{op_protect => _internal/event}/ServerPlayNetworkHandlerMixin.java (56%) diff --git a/src/main/java/io/github/sakurawald/common/event/PrePlayerDisconnectEvent.java b/src/main/java/io/github/sakurawald/common/event/PrePlayerDisconnectEvent.java new file mode 100644 index 000000000..f7934c710 --- /dev/null +++ b/src/main/java/io/github/sakurawald/common/event/PrePlayerDisconnectEvent.java @@ -0,0 +1,27 @@ +package io.github.sakurawald.common.event; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.entity.passive.SheepEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.DisconnectionInfo; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; + +public interface PrePlayerDisconnectEvent { + + Event EVENT = EventFactory.createArrayBacked(PrePlayerDisconnectEvent.class, + (listeners) -> (player, disconnectionInfo) -> { + for (PrePlayerDisconnectEvent listener : listeners) { + ActionResult result = listener.interact(player, disconnectionInfo); + + if(result != ActionResult.PASS) { + return result; + } + } + + return ActionResult.PASS; + }); + + ActionResult interact(ServerPlayerEntity player, DisconnectionInfo disconnectionInfo); +} \ No newline at end of file diff --git a/src/main/java/io/github/sakurawald/module/initializer/op_protect/OpProtectModule.java b/src/main/java/io/github/sakurawald/module/initializer/op_protect/OpProtectModule.java new file mode 100644 index 000000000..1afec9ae6 --- /dev/null +++ b/src/main/java/io/github/sakurawald/module/initializer/op_protect/OpProtectModule.java @@ -0,0 +1,20 @@ +package io.github.sakurawald.module.initializer.op_protect; + +import io.github.sakurawald.Fuji; +import io.github.sakurawald.common.event.PrePlayerDisconnectEvent; +import io.github.sakurawald.module.initializer.ModuleInitializer; +import net.minecraft.util.ActionResult; + +public class OpProtectModule extends ModuleInitializer { + + @Override + public void onInitialize() { + PrePlayerDisconnectEvent.EVENT.register(((player, disconnectionInfo) -> { + if (Fuji.SERVER.getPlayerManager().isOperator(player.getGameProfile())) { + Fuji.LOGGER.info("op protect -> deop {}", player.getGameProfile().getName()); + Fuji.SERVER.getPlayerManager().removeFromOperators(player.getGameProfile()); + } + return ActionResult.PASS; + })); + } +} diff --git a/src/main/java/io/github/sakurawald/module/mixin/op_protect/ServerPlayNetworkHandlerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/_internal/event/ServerPlayNetworkHandlerMixin.java similarity index 56% rename from src/main/java/io/github/sakurawald/module/mixin/op_protect/ServerPlayNetworkHandlerMixin.java rename to src/main/java/io/github/sakurawald/module/mixin/_internal/event/ServerPlayNetworkHandlerMixin.java index ce659863d..4ea2b0bc7 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/op_protect/ServerPlayNetworkHandlerMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/_internal/event/ServerPlayNetworkHandlerMixin.java @@ -1,30 +1,31 @@ -package io.github.sakurawald.module.mixin.op_protect; +package io.github.sakurawald.module.mixin._internal.event; -import io.github.sakurawald.Fuji; -import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents; +import io.github.sakurawald.common.event.PrePlayerDisconnectEvent; +import net.minecraft.entity.passive.SheepEntity; import net.minecraft.network.DisconnectionInfo; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.Text; +import net.minecraft.util.ActionResult; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - @Mixin(ServerPlayNetworkHandler.class) public class ServerPlayNetworkHandlerMixin { @Shadow public ServerPlayerEntity player; - @Inject(at = @At(value = "HEAD"), method = "onDisconnected") + @Inject(at = @At(value = "HEAD"), method = "onDisconnected", cancellable = true) private void $onDisconnected(DisconnectionInfo disconnectionInfo, CallbackInfo ci) { - if (Fuji.SERVER.getPlayerManager().isOperator(player.getGameProfile())) { - Fuji.LOGGER.info("op protect -> deop {}", player.getGameProfile().getName()); - Fuji.SERVER.getPlayerManager().removeFromOperators(player.getGameProfile()); + ActionResult result = PrePlayerDisconnectEvent.EVENT.invoker().interact(player, disconnectionInfo); + if (result == ActionResult.FAIL) { + ci.cancel(); } } } + + diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index dc6b10c8a..30bbeb1e8 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -4,13 +4,11 @@ "compatibilityLevel": "JAVA_17", "plugin": "io.github.sakurawald.module.mixin.ModuleMixinConfigPlugin", "mixins": [ + "_internal.event.ServerPlayNetworkHandlerMixin", "_internal.server_instance.MinecraftServerMixin", "afk.PlayerListMixin", "afk.ServerPlayerMixin", "back.ServerPlayerMixin", - "fake_player_manager.PlayerCommandMixin", - "fake_player_manager.PlayerListMixin", - "fake_player_manager.PlayerMixin", "better_info.InfoCommandMixin", "biome_lookup_cache.NaturalSpawnerMixin", "bypass_chat_speed.ServerGamePacketListenerImplMixin", @@ -20,8 +18,15 @@ "chat.ServerGamePacketListenerImplMixin", "command_cooldown.CommandsMixin", "command_interactive.SignBlockMixin", + "command_permission.CommandNodeAccessor", "command_spy.CommandsMixin", "deathlog.ServerPlayerMixin", + "fake_player_manager.PlayerCommandMixin", + "fake_player_manager.PlayerListMixin", + "fake_player_manager.PlayerMixin", + "fix_player_list_cme.PlayerListMixin", + "fix_player_list_cme.ServerLevelMixin", + "fix_whitelist.UserWhiteListMixin", "language.ServerPlayerMixin", "main_stats.BlockMixin", "main_stats.PlayerListMixin", @@ -43,14 +48,10 @@ "sit.InteractModifierMixin", "skin.PlayerListMixin", "skin.ServerLoginNetworkHandlerMixin", - "fix_player_list_cme.PlayerListMixin", - "fix_player_list_cme.ServerLevelMixin", "system_message.ComponentMixin", "teleport_warmup.ServerPlayerMixin", "top_chunks.ThreadedAnvilChunkStorageMixin", - "fix_whitelist.UserWhiteListMixin", - "works.HopperBlockEntityMixin", - "command_permission.CommandNodeAccessor" + "works.HopperBlockEntityMixin" ], "injectors": { "defaultRequire": 1 From 10cfbb305831219879c1e3118ca54f7138aaedde Mon Sep 17 00:00:00 2001 From: sakurawald Date: Wed, 19 Jun 2024 13:20:07 +0800 Subject: [PATCH 14/50] refactor: main stats module --- .../main_stats/MainStatsModule.java | 8 ++++++ .../ServerPlayNetworkHandlerMixin.java | 26 ------------------- 2 files changed, 8 insertions(+), 26 deletions(-) delete mode 100644 src/main/java/io/github/sakurawald/module/mixin/main_stats/ServerPlayNetworkHandlerMixin.java diff --git a/src/main/java/io/github/sakurawald/module/initializer/main_stats/MainStatsModule.java b/src/main/java/io/github/sakurawald/module/initializer/main_stats/MainStatsModule.java index 86dba7caf..108fd1e40 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/main_stats/MainStatsModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/main_stats/MainStatsModule.java @@ -1,5 +1,6 @@ package io.github.sakurawald.module.initializer.main_stats; +import io.github.sakurawald.common.event.PrePlayerDisconnectEvent; import io.github.sakurawald.config.Configs; import io.github.sakurawald.config.model.ConfigModel; import io.github.sakurawald.module.ModuleManager; @@ -8,6 +9,7 @@ import io.github.sakurawald.util.ScheduleUtil; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.minecraft.server.MinecraftServer; +import net.minecraft.util.ActionResult; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; @@ -28,6 +30,12 @@ public void onInitialize() { this.updateMainStats(server); this.registerScheduleTask(server); }); + + PrePlayerDisconnectEvent.EVENT.register(((player, disconnectionInfo) -> { + String uuid = player.getUuid().toString(); + MainStats.uuid2stats.remove(uuid); + return ActionResult.PASS; + })); } public void updateMainStats(MinecraftServer server) { diff --git a/src/main/java/io/github/sakurawald/module/mixin/main_stats/ServerPlayNetworkHandlerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/main_stats/ServerPlayNetworkHandlerMixin.java deleted file mode 100644 index 1359198de..000000000 --- a/src/main/java/io/github/sakurawald/module/mixin/main_stats/ServerPlayNetworkHandlerMixin.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.github.sakurawald.module.mixin.main_stats; - - -import io.github.sakurawald.module.initializer.main_stats.MainStats; -import net.minecraft.network.DisconnectionInfo; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.Text; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin { - - @Shadow - public ServerPlayerEntity player; - - @Inject(at = @At("HEAD"), method = "onDisconnected") - private void $disconnect(DisconnectionInfo disconnectionInfo, CallbackInfo ci) { - String uuid = player.getUuid().toString(); - MainStats.uuid2stats.remove(uuid); - } -} From cbf932b6a0059bc689b44f0a1809244e475d791a Mon Sep 17 00:00:00 2001 From: sakurawald Date: Wed, 19 Jun 2024 13:40:48 +0800 Subject: [PATCH 15/50] refactor: add custom event PostPlayerConnectEvent --- build.gradle | 1 - .../common/event/PostPlayerConnectEvent.java | 27 +++++++++++++++++ .../module/initializer/afk/AfkModule.java | 7 +++++ .../module/initializer/chat/ChatModule.java | 9 ++++++ .../FakePlayerManagerModule.java | 16 +++++++--- .../main_stats/MainStatsModule.java | 8 +++++ .../newbie_welcome/NewbieWelcomeModule.java | 14 +++++++++ .../event/PlayerManagerMixin.java} | 18 +++++++----- .../module/mixin/afk/PlayerListMixin.java | 21 -------------- .../fake_player_manager/PlayerListMixin.java | 28 ------------------ .../mixin/newbie_welcome/PlayerListMixin.java | 29 ------------------- src/main/resources/fuji.mixins.json | 7 +---- 12 files changed, 89 insertions(+), 96 deletions(-) create mode 100644 src/main/java/io/github/sakurawald/common/event/PostPlayerConnectEvent.java rename src/main/java/io/github/sakurawald/module/mixin/{main_stats/PlayerListMixin.java => _internal/event/PlayerManagerMixin.java} (58%) delete mode 100644 src/main/java/io/github/sakurawald/module/mixin/afk/PlayerListMixin.java delete mode 100644 src/main/java/io/github/sakurawald/module/mixin/fake_player_manager/PlayerListMixin.java delete mode 100644 src/main/java/io/github/sakurawald/module/mixin/newbie_welcome/PlayerListMixin.java diff --git a/build.gradle b/build.gradle index b56108ec2..ad52f4f36 100755 --- a/build.gradle +++ b/build.gradle @@ -135,7 +135,6 @@ modrinth { syncBodyFrom = rootProject.file("README.md").text } tasks.modrinth.dependsOn(tasks.modrinthSyncBody) -tasks.modrinthSyncBody.dependsOn(tasks.replaceReadme) // test framework test { diff --git a/src/main/java/io/github/sakurawald/common/event/PostPlayerConnectEvent.java b/src/main/java/io/github/sakurawald/common/event/PostPlayerConnectEvent.java new file mode 100644 index 000000000..ecdc28c06 --- /dev/null +++ b/src/main/java/io/github/sakurawald/common/event/PostPlayerConnectEvent.java @@ -0,0 +1,27 @@ +package io.github.sakurawald.common.event; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.DisconnectionInfo; +import net.minecraft.server.network.ConnectedClientData; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +public interface PostPlayerConnectEvent { + Event EVENT = EventFactory.createArrayBacked(PostPlayerConnectEvent.class, + (listeners) -> (connection, player, commonListenerCookie) -> { + for (PostPlayerConnectEvent listener : listeners) { + ActionResult result = listener.interact(connection, player, commonListenerCookie); + + if (result != ActionResult.PASS) { + return result; + } + } + + return ActionResult.PASS; + }); + + ActionResult interact(ClientConnection connection, ServerPlayerEntity player, ConnectedClientData commonListenerCookie); +} diff --git a/src/main/java/io/github/sakurawald/module/initializer/afk/AfkModule.java b/src/main/java/io/github/sakurawald/module/initializer/afk/AfkModule.java index d8c5c0a1e..25246e193 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/afk/AfkModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/afk/AfkModule.java @@ -4,6 +4,7 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; import io.github.sakurawald.Fuji; +import io.github.sakurawald.common.event.PostPlayerConnectEvent; import io.github.sakurawald.config.Configs; import io.github.sakurawald.module.initializer.ModuleInitializer; import io.github.sakurawald.util.CommandUtil; @@ -14,6 +15,7 @@ import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; @@ -25,6 +27,11 @@ public class AfkModule extends ModuleInitializer { @Override public void onInitialize() { ServerLifecycleEvents.SERVER_STARTED.register(server -> updateJobs()); + PostPlayerConnectEvent.EVENT.register((connection, player, commonListenerCookie) -> { + AfkStateAccessor afk_player = (AfkStateAccessor) player; + afk_player.fuji$setLastLastActionTime(player.getLastActionTime()); + return ActionResult.PASS; + }); } @Override diff --git a/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java b/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java index 7e8b3c249..d0016590b 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java @@ -6,6 +6,7 @@ import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import io.github.sakurawald.Fuji; +import io.github.sakurawald.common.event.PostPlayerConnectEvent; import io.github.sakurawald.config.Configs; import io.github.sakurawald.config.handler.ConfigHandler; import io.github.sakurawald.config.handler.ObjectConfigHandler; @@ -16,6 +17,7 @@ import io.github.sakurawald.module.initializer.chat.mention.MentionPlayersJob; import io.github.sakurawald.module.initializer.main_stats.MainStats; import io.github.sakurawald.module.initializer.main_stats.MainStatsModule; +import io.github.sakurawald.util.CarpetUtil; import io.github.sakurawald.util.CommandUtil; import io.github.sakurawald.util.MessageUtil; import lombok.Getter; @@ -32,6 +34,7 @@ import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; import org.jetbrains.annotations.NotNull; import java.time.Duration; @@ -62,6 +65,12 @@ public class ChatModule extends ModuleInitializer { public void onInitialize() { chatHandler.loadFromDisk(); chatHistory = EvictingQueue.create(Configs.configHandler.model().modules.chat.history.cache_size); + +// PostPlayerConnectEvent.EVENT.register(((connection, player, commonListenerCookie) -> { +// if (CarpetUtil.isFakePlayer(player)) return ActionResult.PASS; +// this.getChatHistory().forEach(player::sendMessage); +// return ActionResult.PASS; +// })); } diff --git a/src/main/java/io/github/sakurawald/module/initializer/fake_player_manager/FakePlayerManagerModule.java b/src/main/java/io/github/sakurawald/module/initializer/fake_player_manager/FakePlayerManagerModule.java index 1ce3861ee..615785edb 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/fake_player_manager/FakePlayerManagerModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/fake_player_manager/FakePlayerManagerModule.java @@ -5,19 +5,19 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; import io.github.sakurawald.Fuji; +import io.github.sakurawald.common.event.PostPlayerConnectEvent; import io.github.sakurawald.config.Configs; import io.github.sakurawald.module.initializer.ModuleInitializer; -import io.github.sakurawald.util.CommandUtil; -import io.github.sakurawald.util.DateUtil; -import io.github.sakurawald.util.MessageUtil; -import io.github.sakurawald.util.ScheduleUtil; +import io.github.sakurawald.util.*; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.kyori.adventure.text.Component; +import net.minecraft.client.realms.Request; import net.minecraft.command.CommandRegistryAccess; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; import net.minecraft.util.Uuids; import org.quartz.Job; import org.quartz.JobDataMap; @@ -35,6 +35,14 @@ public class FakePlayerManagerModule extends ModuleInitializer { @Override public void onInitialize() { ServerLifecycleEvents.SERVER_STARTED.register(this::registerScheduleTask); + + PostPlayerConnectEvent.EVENT.register((connection, player, commonListenerCookie) -> { + if (CarpetUtil.isFakePlayer(player)) return ActionResult.PASS; + if (this.hasFakePlayers(player)) { + this.renewFakePlayers(player); + } + return ActionResult.PASS; + }); } @SuppressWarnings("unused") diff --git a/src/main/java/io/github/sakurawald/module/initializer/main_stats/MainStatsModule.java b/src/main/java/io/github/sakurawald/module/initializer/main_stats/MainStatsModule.java index 108fd1e40..7bf5e36af 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/main_stats/MainStatsModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/main_stats/MainStatsModule.java @@ -1,5 +1,6 @@ package io.github.sakurawald.module.initializer.main_stats; +import io.github.sakurawald.common.event.PostPlayerConnectEvent; import io.github.sakurawald.common.event.PrePlayerDisconnectEvent; import io.github.sakurawald.config.Configs; import io.github.sakurawald.config.model.ConfigModel; @@ -36,6 +37,13 @@ public void onInitialize() { MainStats.uuid2stats.remove(uuid); return ActionResult.PASS; })); + + PostPlayerConnectEvent.EVENT.register((connection, player, commonListenerCookie) -> { + String uuid = player.getUuid().toString(); + MainStats stats = MainStats.calculatePlayerMainStats(uuid); + MainStats.uuid2stats.put(uuid, stats); + return ActionResult.PASS; + }); } public void updateMainStats(MinecraftServer server) { diff --git a/src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/NewbieWelcomeModule.java b/src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/NewbieWelcomeModule.java index be29786d3..2c80336e1 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/NewbieWelcomeModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/newbie_welcome/NewbieWelcomeModule.java @@ -1,12 +1,26 @@ package io.github.sakurawald.module.initializer.newbie_welcome; +import io.github.sakurawald.common.event.PostPlayerConnectEvent; import io.github.sakurawald.module.initializer.ModuleInitializer; import io.github.sakurawald.module.initializer.newbie_welcome.random_teleport.RandomTeleport; +import io.github.sakurawald.util.CarpetUtil; import io.github.sakurawald.util.MessageUtil; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.stat.Stats; +import net.minecraft.util.ActionResult; public class NewbieWelcomeModule extends ModuleInitializer { + @Override + public void onInitialize() { + PostPlayerConnectEvent.EVENT.register((connection, player, commonListenerCookie) -> { + if (CarpetUtil.isFakePlayer(player)) return ActionResult.PASS; + if (player.getStatHandler().getStat(Stats.CUSTOM.getOrCreateStat(Stats.LEAVE_GAME)) < 1) { + this.welcomeNewbiePlayer(player); + } + return ActionResult.PASS; + }); + } public void welcomeNewbiePlayer(ServerPlayerEntity player) { /* welcome message */ diff --git a/src/main/java/io/github/sakurawald/module/mixin/main_stats/PlayerListMixin.java b/src/main/java/io/github/sakurawald/module/mixin/_internal/event/PlayerManagerMixin.java similarity index 58% rename from src/main/java/io/github/sakurawald/module/mixin/main_stats/PlayerListMixin.java rename to src/main/java/io/github/sakurawald/module/mixin/_internal/event/PlayerManagerMixin.java index d9c11cc34..332c06d4f 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/main_stats/PlayerListMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/_internal/event/PlayerManagerMixin.java @@ -1,22 +1,26 @@ -package io.github.sakurawald.module.mixin.main_stats; +package io.github.sakurawald.module.mixin._internal.event; -import io.github.sakurawald.module.initializer.main_stats.MainStats; +import io.github.sakurawald.common.event.PostPlayerConnectEvent; +import net.minecraft.entity.passive.SheepEntity; import net.minecraft.network.ClientConnection; import net.minecraft.server.PlayerManager; import net.minecraft.server.network.ConnectedClientData; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(PlayerManager.class) -public abstract class PlayerListMixin { +public class PlayerManagerMixin { - @Inject(at = @At(value = "TAIL"), method = "onPlayerConnect") + @Inject(at = @At(value = "TAIL"), method = "onPlayerConnect", cancellable = true) private void $onPlayerConnect(ClientConnection connection, ServerPlayerEntity serverPlayer, ConnectedClientData commonListenerCookie, CallbackInfo ci) { - String uuid = serverPlayer.getUuid().toString(); - MainStats stats = MainStats.calculatePlayerMainStats(uuid); - MainStats.uuid2stats.put(uuid, stats); + ActionResult result = PostPlayerConnectEvent.EVENT.invoker().interact(connection, serverPlayer, commonListenerCookie); + + if (result == ActionResult.FAIL) { + ci.cancel(); + } } } diff --git a/src/main/java/io/github/sakurawald/module/mixin/afk/PlayerListMixin.java b/src/main/java/io/github/sakurawald/module/mixin/afk/PlayerListMixin.java deleted file mode 100644 index 6da23e9c3..000000000 --- a/src/main/java/io/github/sakurawald/module/mixin/afk/PlayerListMixin.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.github.sakurawald.module.mixin.afk; - -import io.github.sakurawald.module.initializer.afk.AfkStateAccessor; -import net.minecraft.network.ClientConnection; -import net.minecraft.server.PlayerManager; -import net.minecraft.server.network.ConnectedClientData; -import net.minecraft.server.network.ServerPlayerEntity; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(PlayerManager.class) - -public abstract class PlayerListMixin { - @Inject(at = @At(value = "TAIL"), method = "onPlayerConnect") - private void $onPlayerConnect(ClientConnection connection, ServerPlayerEntity serverPlayer, ConnectedClientData commonListenerCookie, CallbackInfo ci) { - AfkStateAccessor afk_player = (AfkStateAccessor) serverPlayer; - afk_player.fuji$setLastLastActionTime(serverPlayer.getLastActionTime()); - } -} \ No newline at end of file diff --git a/src/main/java/io/github/sakurawald/module/mixin/fake_player_manager/PlayerListMixin.java b/src/main/java/io/github/sakurawald/module/mixin/fake_player_manager/PlayerListMixin.java deleted file mode 100644 index 5ff6c893e..000000000 --- a/src/main/java/io/github/sakurawald/module/mixin/fake_player_manager/PlayerListMixin.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.github.sakurawald.module.mixin.fake_player_manager; - -import io.github.sakurawald.module.ModuleManager; -import io.github.sakurawald.module.initializer.fake_player_manager.FakePlayerManagerModule; -import io.github.sakurawald.util.CarpetUtil; -import net.minecraft.network.ClientConnection; -import net.minecraft.server.PlayerManager; -import net.minecraft.server.network.ConnectedClientData; -import net.minecraft.server.network.ServerPlayerEntity; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(PlayerManager.class) -public abstract class PlayerListMixin { - @Unique - private static final FakePlayerManagerModule module = ModuleManager.getInitializer(FakePlayerManagerModule.class); - - @Inject(at = @At(value = "TAIL"), method = "onPlayerConnect") - private void $onPlayerConnect(ClientConnection connection, ServerPlayerEntity serverPlayer, ConnectedClientData commonListenerCookie, CallbackInfo ci) { - if (CarpetUtil.isFakePlayer(serverPlayer)) return; - if (module.hasFakePlayers(serverPlayer)) { - module.renewFakePlayers(serverPlayer); - } - } -} diff --git a/src/main/java/io/github/sakurawald/module/mixin/newbie_welcome/PlayerListMixin.java b/src/main/java/io/github/sakurawald/module/mixin/newbie_welcome/PlayerListMixin.java deleted file mode 100644 index 571af8d9a..000000000 --- a/src/main/java/io/github/sakurawald/module/mixin/newbie_welcome/PlayerListMixin.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.github.sakurawald.module.mixin.newbie_welcome; - -import io.github.sakurawald.module.ModuleManager; -import io.github.sakurawald.module.initializer.newbie_welcome.NewbieWelcomeModule; -import io.github.sakurawald.util.CarpetUtil; -import net.minecraft.network.ClientConnection; -import net.minecraft.server.PlayerManager; -import net.minecraft.server.network.ConnectedClientData; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.stat.Stats; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(PlayerManager.class) -public abstract class PlayerListMixin { - @Unique - private static final NewbieWelcomeModule module = ModuleManager.getInitializer(NewbieWelcomeModule.class); - - @Inject(at = @At(value = "TAIL"), method = "onPlayerConnect") - private void $onPlayerConnect(ClientConnection connection, ServerPlayerEntity serverPlayer, ConnectedClientData commonListenerCookie, CallbackInfo ci) { - if (CarpetUtil.isFakePlayer(serverPlayer)) return; - if (serverPlayer.getStatHandler().getStat(Stats.CUSTOM.getOrCreateStat(Stats.LEAVE_GAME)) < 1) { - module.welcomeNewbiePlayer(serverPlayer); - } - } -} diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index 30bbeb1e8..38ee2346a 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -4,9 +4,9 @@ "compatibilityLevel": "JAVA_17", "plugin": "io.github.sakurawald.module.mixin.ModuleMixinConfigPlugin", "mixins": [ + "_internal.event.PlayerManagerMixin", "_internal.event.ServerPlayNetworkHandlerMixin", "_internal.server_instance.MinecraftServerMixin", - "afk.PlayerListMixin", "afk.ServerPlayerMixin", "back.ServerPlayerMixin", "better_info.InfoCommandMixin", @@ -22,19 +22,14 @@ "command_spy.CommandsMixin", "deathlog.ServerPlayerMixin", "fake_player_manager.PlayerCommandMixin", - "fake_player_manager.PlayerListMixin", "fake_player_manager.PlayerMixin", "fix_player_list_cme.PlayerListMixin", "fix_player_list_cme.ServerLevelMixin", "fix_whitelist.UserWhiteListMixin", "language.ServerPlayerMixin", "main_stats.BlockMixin", - "main_stats.PlayerListMixin", - "main_stats.ServerPlayNetworkHandlerMixin", "motd.ServerStatusPacketListenerImplMixin", "multi_obsidian_platform.EndPortalBlockMixin", - "newbie_welcome.PlayerListMixin", - "op_protect.ServerPlayNetworkHandlerMixin", "pvp.PvpToggleMixin", "reply.MsgCommandMixin", "resource_world.EndGatewayBlockEntityMixin", From fa9bb8ce8e3679293f2435e1fb9499beb34f194f Mon Sep 17 00:00:00 2001 From: sakurawald Date: Wed, 19 Jun 2024 13:43:35 +0800 Subject: [PATCH 16/50] remove: biome lookup cache module --- .../sakurawald/config/model/ConfigModel.java | 5 -- .../biome_lookup_cache/ChunkManager.java | 74 ------------------- .../NaturalSpawnerMixin.java | 29 -------- 3 files changed, 108 deletions(-) delete mode 100644 src/main/java/io/github/sakurawald/module/initializer/biome_lookup_cache/ChunkManager.java delete mode 100644 src/main/java/io/github/sakurawald/module/mixin/biome_lookup_cache/NaturalSpawnerMixin.java diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index 1148a32e9..e31ab7c9a 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -60,7 +60,6 @@ public class Modules { public BypassChatSpeed bypass_chat_speed = new BypassChatSpeed(); public BypassMoveSpeed bypass_move_speed = new BypassMoveSpeed(); public BypassMaxPlayerLimit bypass_max_player_limit = new BypassMaxPlayerLimit(); - public BiomeLookupCache biome_lookup_cache = new BiomeLookupCache(); public Config config = new Config(); public Test test = new Test(); public Hat hat = new Hat(); @@ -400,10 +399,6 @@ public class Scheduler { public boolean enable = false; } - public class BiomeLookupCache { - public boolean enable = false; - } - public class Config { public boolean enable = false; } diff --git a/src/main/java/io/github/sakurawald/module/initializer/biome_lookup_cache/ChunkManager.java b/src/main/java/io/github/sakurawald/module/initializer/biome_lookup_cache/ChunkManager.java deleted file mode 100644 index 36f3a5e95..000000000 --- a/src/main/java/io/github/sakurawald/module/initializer/biome_lookup_cache/ChunkManager.java +++ /dev/null @@ -1,74 +0,0 @@ -package io.github.sakurawald.module.initializer.biome_lookup_cache; - -import com.mojang.datafixers.util.Either; -import net.minecraft.server.world.OptionalChunk; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.concurrent.CompletableFuture; -import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.server.world.ChunkHolder; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.world.World; -import net.minecraft.world.WorldView; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.ChunkStatus; -import net.minecraft.world.chunk.WorldChunk; - -/** - * Utility methods for getting chunks. - * - * @author Wesley1808 - */ -public class ChunkManager { - - @NotNull - public static RegistryEntry getRoughBiome(World level, BlockPos pos) { - Chunk chunk = getChunkNow(level, pos); - int x = pos.getX() >> 2; - int y = pos.getY() >> 2; - int z = pos.getZ() >> 2; - - return chunk != null ? chunk.getBiomeForNoiseGen(x, y, z) : level.getGeneratorStoredBiome(x, y, z); - } - - @Nullable - public static Chunk getChunkNow(WorldView levelReader, BlockPos pos) { - return getChunkNow(levelReader, pos.getX() >> 4, pos.getZ() >> 4); - } - - @Nullable - public static Chunk getChunkNow(WorldView levelReader, int chunkX, int chunkZ) { - if (levelReader instanceof ServerWorld level) { - return getChunkFromHolder(getChunkHolder(level, chunkX, chunkZ)); - } else { - return levelReader.getChunk(chunkX, chunkZ, ChunkStatus.FULL, false); - } - } - - @SuppressWarnings("ObjectEquality") - @Nullable - public static WorldChunk getChunkFromFuture(CompletableFuture> future) { - - WorldChunk now = future.getNow(null).orElse(null); - - if (now == ChunkHolder.UNLOADED_WORLD_CHUNK || now == null) { - return null; - } - - return now; - } - - @Nullable - public static WorldChunk getChunkFromHolder(ChunkHolder holder) { - return holder != null ? getChunkFromFuture(holder.getAccessibleFuture()) : null; - } - - @Nullable - private static ChunkHolder getChunkHolder(ServerWorld level, int chunkX, int chunkZ) { - return level.getChunkManager().getChunkHolder(ChunkPos.toLong(chunkX, chunkZ)); - } -} \ No newline at end of file diff --git a/src/main/java/io/github/sakurawald/module/mixin/biome_lookup_cache/NaturalSpawnerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/biome_lookup_cache/NaturalSpawnerMixin.java deleted file mode 100644 index 32c070104..000000000 --- a/src/main/java/io/github/sakurawald/module/mixin/biome_lookup_cache/NaturalSpawnerMixin.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.github.sakurawald.module.mixin.biome_lookup_cache; - -import io.github.sakurawald.module.initializer.biome_lookup_cache.ChunkManager; -import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.SpawnHelper; -import net.minecraft.world.biome.Biome; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -/* - * Carpet Mod also includes some optimization for entity-spawn, please enable lagFreeSpawn in carpet - * */ -@Mixin(SpawnHelper.class) -public abstract class NaturalSpawnerMixin { - @Redirect( - method = {"mobsAt", "getRandomSpawnMobAt"}, - require = 0, - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/server/level/ServerLevel;getBiome(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/core/Holder;" - ) - ) - private static RegistryEntry $getRandomSpawnMobAt(ServerWorld level, BlockPos pos) { - return ChunkManager.getRoughBiome(level, pos); - } -} \ No newline at end of file From 8848fa5ae58d38742fb200138008e8b55bdc2ce6 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Wed, 19 Jun 2024 14:00:13 +0800 Subject: [PATCH 17/50] add: custom event PrePlayerDeathEvent --- .../common/event/PrePlayerDeathEvent.java | 23 ++++++++++++++++ .../module/initializer/back/BackModule.java | 11 ++++++++ .../initializer/deathlog/DeathLogModule.java | 9 +++++++ .../event/ServerPlayerEntityMixin.java | 25 ++++++++++++++++++ .../module/mixin/back/ServerPlayerMixin.java | 8 ------ .../mixin/command_spy/CommandsMixin.java | 1 - .../mixin/deathlog/ServerPlayerMixin.java | 26 ------------------- src/main/resources/fuji.mixins.json | 3 +-- 8 files changed, 69 insertions(+), 37 deletions(-) create mode 100644 src/main/java/io/github/sakurawald/common/event/PrePlayerDeathEvent.java create mode 100644 src/main/java/io/github/sakurawald/module/mixin/_internal/event/ServerPlayerEntityMixin.java delete mode 100644 src/main/java/io/github/sakurawald/module/mixin/deathlog/ServerPlayerMixin.java diff --git a/src/main/java/io/github/sakurawald/common/event/PrePlayerDeathEvent.java b/src/main/java/io/github/sakurawald/common/event/PrePlayerDeathEvent.java new file mode 100644 index 000000000..00402ab2d --- /dev/null +++ b/src/main/java/io/github/sakurawald/common/event/PrePlayerDeathEvent.java @@ -0,0 +1,23 @@ +package io.github.sakurawald.common.event; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; + +public interface PrePlayerDeathEvent { + Event EVENT = EventFactory.createArrayBacked(PrePlayerDeathEvent.class, + (listeners) -> (player, damageSource) -> { + for (PrePlayerDeathEvent listener : listeners) { + ActionResult result = listener.interact(player, damageSource); + if (result != ActionResult.PASS) { + return result; + } + } + + return ActionResult.PASS; + }); + + ActionResult interact(ServerPlayerEntity player, DamageSource damageSource); +} diff --git a/src/main/java/io/github/sakurawald/module/initializer/back/BackModule.java b/src/main/java/io/github/sakurawald/module/initializer/back/BackModule.java index 38e71a032..550534dd0 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/back/BackModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/back/BackModule.java @@ -3,6 +3,7 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; +import io.github.sakurawald.common.event.PrePlayerDeathEvent; import io.github.sakurawald.config.Configs; import io.github.sakurawald.module.initializer.ModuleInitializer; import io.github.sakurawald.common.Position; @@ -13,6 +14,8 @@ import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; + import java.util.HashMap; @SuppressWarnings("LombokGetterMayBeUsed") @@ -21,6 +24,14 @@ public class BackModule extends ModuleInitializer { @Getter private final HashMap player2lastPos = new HashMap<>(); + @Override + public void onInitialize() { + PrePlayerDeathEvent.EVENT.register((player, damageSource) -> { + this.updatePlayer(player); + return ActionResult.PASS; + }); + } + @Override public void registerCommand(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess, CommandManager.RegistrationEnvironment environment) { dispatcher.register(CommandManager.literal("back").executes(this::$back)); diff --git a/src/main/java/io/github/sakurawald/module/initializer/deathlog/DeathLogModule.java b/src/main/java/io/github/sakurawald/module/initializer/deathlog/DeathLogModule.java index db51ba72f..3525c8188 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/deathlog/DeathLogModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/deathlog/DeathLogModule.java @@ -6,6 +6,7 @@ import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import io.github.sakurawald.Fuji; +import io.github.sakurawald.common.event.PrePlayerDeathEvent; import io.github.sakurawald.module.initializer.ModuleInitializer; import io.github.sakurawald.util.CommandUtil; import io.github.sakurawald.util.RegistryUtil; @@ -25,6 +26,7 @@ import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; import net.minecraft.util.Uuids; import net.minecraft.util.collection.DefaultedList; import net.minecraft.util.math.Vec3d; @@ -63,6 +65,13 @@ public class DeathLogModule extends ModuleInitializer { @Override public void onInitialize() { STORAGE_PATH.toFile().mkdirs(); + + PrePlayerDeathEvent.EVENT.register((player, damageSource) -> { + // don't store empty inventory + if (player.getInventory().isEmpty()) return ActionResult.PASS; + this.store(player); + return ActionResult.PASS; + }); } @SuppressWarnings({"UnusedReturnValue", "unused"}) diff --git a/src/main/java/io/github/sakurawald/module/mixin/_internal/event/ServerPlayerEntityMixin.java b/src/main/java/io/github/sakurawald/module/mixin/_internal/event/ServerPlayerEntityMixin.java new file mode 100644 index 000000000..b0383c106 --- /dev/null +++ b/src/main/java/io/github/sakurawald/module/mixin/_internal/event/ServerPlayerEntityMixin.java @@ -0,0 +1,25 @@ +package io.github.sakurawald.module.mixin._internal.event; + +import io.github.sakurawald.common.event.PrePlayerDeathEvent; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ServerPlayerEntity.class) +public abstract class ServerPlayerEntityMixin { + + @Inject(method = "onDeath", at = @At("HEAD"), cancellable = true) + public void $onDeath(DamageSource damageSource, CallbackInfo ci) { + ServerPlayerEntity player = (ServerPlayerEntity) (Object) this; + + ActionResult result = PrePlayerDeathEvent.EVENT.invoker().interact(player, damageSource); + if (result == ActionResult.FAIL) { + ci.cancel(); + } + } +} diff --git a/src/main/java/io/github/sakurawald/module/mixin/back/ServerPlayerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/back/ServerPlayerMixin.java index 8b830a0bb..b9f69f425 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/back/ServerPlayerMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/back/ServerPlayerMixin.java @@ -13,21 +13,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ServerPlayerEntity.class) - public abstract class ServerPlayerMixin { - @Unique private static final BackModule module = ModuleManager.getInitializer(BackModule.class); @Unique private static final TeleportWarmupModule teleportWarmupModule = ModuleManager.getInitializer(TeleportWarmupModule.class); - @Inject(method = "onDeath", at = @At("HEAD")) - public void $onDeath(DamageSource damageSource, CallbackInfo ci) { - ServerPlayerEntity player = (ServerPlayerEntity) (Object) this; - module.updatePlayer(player); - } - @Inject(method = "teleport(Lnet/minecraft/server/world/ServerWorld;DDDFF)V", at = @At("HEAD")) public void $teleport(ServerWorld targetWorld, double x, double y, double z, float yaw, float pitch, CallbackInfo ci) { ServerPlayerEntity player = (ServerPlayerEntity) (Object) this; diff --git a/src/main/java/io/github/sakurawald/module/mixin/command_spy/CommandsMixin.java b/src/main/java/io/github/sakurawald/module/mixin/command_spy/CommandsMixin.java index ebf26634e..81536628e 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/command_spy/CommandsMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/command_spy/CommandsMixin.java @@ -12,7 +12,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(CommandManager.class) - public class CommandsMixin { // If you issue "///abcdefg", then commandLine = "//abcdefg" diff --git a/src/main/java/io/github/sakurawald/module/mixin/deathlog/ServerPlayerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/deathlog/ServerPlayerMixin.java deleted file mode 100644 index c43ba26d3..000000000 --- a/src/main/java/io/github/sakurawald/module/mixin/deathlog/ServerPlayerMixin.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.github.sakurawald.module.mixin.deathlog; - -import io.github.sakurawald.module.ModuleManager; -import io.github.sakurawald.module.initializer.deathlog.DeathLogModule; -import net.minecraft.entity.damage.DamageSource; -import net.minecraft.server.network.ServerPlayerEntity; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(ServerPlayerEntity.class) -public abstract class ServerPlayerMixin { - @Unique - private static final DeathLogModule module = ModuleManager.getInitializer(DeathLogModule.class); - - @Inject(method = "onDeath", at = @At("HEAD")) - public void $onDeath(DamageSource damageSource, CallbackInfo ci) { - ServerPlayerEntity player = (ServerPlayerEntity) (Object) this; - // don't store empty inventory - if (player.getInventory().isEmpty()) return; - module.store(player); - } - -} diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index 38ee2346a..680779a77 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -5,12 +5,12 @@ "plugin": "io.github.sakurawald.module.mixin.ModuleMixinConfigPlugin", "mixins": [ "_internal.event.PlayerManagerMixin", + "_internal.event.ServerPlayerEntityMixin", "_internal.event.ServerPlayNetworkHandlerMixin", "_internal.server_instance.MinecraftServerMixin", "afk.ServerPlayerMixin", "back.ServerPlayerMixin", "better_info.InfoCommandMixin", - "biome_lookup_cache.NaturalSpawnerMixin", "bypass_chat_speed.ServerGamePacketListenerImplMixin", "bypass_max_player_limit.DedicatedPlayerManagerMixin", "bypass_move_speed.ServerGamePacketListenerImplMixin", @@ -20,7 +20,6 @@ "command_interactive.SignBlockMixin", "command_permission.CommandNodeAccessor", "command_spy.CommandsMixin", - "deathlog.ServerPlayerMixin", "fake_player_manager.PlayerCommandMixin", "fake_player_manager.PlayerMixin", "fix_player_list_cme.PlayerListMixin", From 12eacc8699e8c81d4de57b472d1bfa6dfd0cd3c3 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Wed, 19 Jun 2024 14:23:46 +0800 Subject: [PATCH 18/50] add: custom event PreCommandExecuteEvent --- .../common/event/PreCommandExecuteEvent.java | 24 +++++++++++++ .../common/{ => structure}/Position.java | 2 +- .../sakurawald/config/model/HomeModel.java | 2 +- .../module/initializer/back/BackModule.java | 2 +- .../CommandCooldownModule.java | 19 ++++++++++ .../command_spy/CommandSpyModule.java | 22 ++++++++++++ .../module/initializer/home/HomeModule.java | 2 +- .../module/initializer/reply/ReplyModule.java | 2 ++ .../resource_world/ResourceWorldManager.java | 2 +- .../teleport_warmup/TeleportTicket.java | 2 +- .../_internal/event/CommandManagerMixin.java | 25 +++++++++++++ .../mixin/command_cooldown/CommandsMixin.java | 36 ------------------- .../mixin/command_spy/CommandsMixin.java | 26 -------------- .../teleport_warmup/ServerPlayerMixin.java | 2 +- src/main/resources/fuji.mixins.json | 3 +- 15 files changed, 100 insertions(+), 71 deletions(-) create mode 100644 src/main/java/io/github/sakurawald/common/event/PreCommandExecuteEvent.java rename src/main/java/io/github/sakurawald/common/{ => structure}/Position.java (97%) create mode 100644 src/main/java/io/github/sakurawald/module/initializer/command_spy/CommandSpyModule.java create mode 100644 src/main/java/io/github/sakurawald/module/mixin/_internal/event/CommandManagerMixin.java delete mode 100644 src/main/java/io/github/sakurawald/module/mixin/command_cooldown/CommandsMixin.java delete mode 100644 src/main/java/io/github/sakurawald/module/mixin/command_spy/CommandsMixin.java diff --git a/src/main/java/io/github/sakurawald/common/event/PreCommandExecuteEvent.java b/src/main/java/io/github/sakurawald/common/event/PreCommandExecuteEvent.java new file mode 100644 index 000000000..07bf04276 --- /dev/null +++ b/src/main/java/io/github/sakurawald/common/event/PreCommandExecuteEvent.java @@ -0,0 +1,24 @@ +package io.github.sakurawald.common.event; + +import com.mojang.brigadier.ParseResults; +import com.mojang.brigadier.context.CommandContext; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.util.ActionResult; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +public interface PreCommandExecuteEvent { + Event EVENT = EventFactory.createArrayBacked(PreCommandExecuteEvent.class, + (listeners) -> (parseResults, string) -> { + for (PreCommandExecuteEvent listener : listeners) { + ActionResult result = listener.interact(parseResults, string); + if (result != ActionResult.PASS) { + return result; + } + } + return ActionResult.PASS; + }); + + ActionResult interact(ParseResults parseResults, String string); +} diff --git a/src/main/java/io/github/sakurawald/common/Position.java b/src/main/java/io/github/sakurawald/common/structure/Position.java similarity index 97% rename from src/main/java/io/github/sakurawald/common/Position.java rename to src/main/java/io/github/sakurawald/common/structure/Position.java index 81025b15b..469001e40 100644 --- a/src/main/java/io/github/sakurawald/common/Position.java +++ b/src/main/java/io/github/sakurawald/common/structure/Position.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.common; +package io.github.sakurawald.common.structure; import io.github.sakurawald.Fuji; import io.github.sakurawald.util.MessageUtil; diff --git a/src/main/java/io/github/sakurawald/config/model/HomeModel.java b/src/main/java/io/github/sakurawald/config/model/HomeModel.java index 289988acf..a981791a9 100644 --- a/src/main/java/io/github/sakurawald/config/model/HomeModel.java +++ b/src/main/java/io/github/sakurawald/config/model/HomeModel.java @@ -1,6 +1,6 @@ package io.github.sakurawald.config.model; -import io.github.sakurawald.common.Position; +import io.github.sakurawald.common.structure.Position; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/io/github/sakurawald/module/initializer/back/BackModule.java b/src/main/java/io/github/sakurawald/module/initializer/back/BackModule.java index 550534dd0..a936d1196 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/back/BackModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/back/BackModule.java @@ -6,7 +6,7 @@ import io.github.sakurawald.common.event.PrePlayerDeathEvent; import io.github.sakurawald.config.Configs; import io.github.sakurawald.module.initializer.ModuleInitializer; -import io.github.sakurawald.common.Position; +import io.github.sakurawald.common.structure.Position; import io.github.sakurawald.util.CommandUtil; import io.github.sakurawald.util.MessageUtil; import lombok.Getter; diff --git a/src/main/java/io/github/sakurawald/module/initializer/command_cooldown/CommandCooldownModule.java b/src/main/java/io/github/sakurawald/module/initializer/command_cooldown/CommandCooldownModule.java index 3c4516076..281d69b37 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/command_cooldown/CommandCooldownModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/command_cooldown/CommandCooldownModule.java @@ -1,15 +1,34 @@ package io.github.sakurawald.module.initializer.command_cooldown; +import io.github.sakurawald.common.event.PreCommandExecuteEvent; import io.github.sakurawald.config.Configs; import io.github.sakurawald.module.initializer.ModuleInitializer; import java.util.HashMap; import java.util.Map; + +import io.github.sakurawald.util.MessageUtil; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; public class CommandCooldownModule extends ModuleInitializer { private final HashMap> map = new HashMap<>(); + @Override + public void onInitialize() { + PreCommandExecuteEvent.EVENT.register((parseResults, string) -> { + ServerPlayerEntity player = parseResults.getContext().getSource().getPlayer(); + if (player == null) return ActionResult.PASS; + + long cooldown = this.calculateCommandCooldown(player, string); + if (cooldown > 0) { + MessageUtil.sendActionBar(player, "command_cooldown.cooldown", cooldown / 1000); + return ActionResult.FAIL; + } + + return ActionResult.PASS; + }); + } public long calculateCommandCooldown(ServerPlayerEntity player, String commandLine) { diff --git a/src/main/java/io/github/sakurawald/module/initializer/command_spy/CommandSpyModule.java b/src/main/java/io/github/sakurawald/module/initializer/command_spy/CommandSpyModule.java new file mode 100644 index 000000000..e1d81435f --- /dev/null +++ b/src/main/java/io/github/sakurawald/module/initializer/command_spy/CommandSpyModule.java @@ -0,0 +1,22 @@ +package io.github.sakurawald.module.initializer.command_spy; + +import io.github.sakurawald.Fuji; +import io.github.sakurawald.common.event.PreCommandExecuteEvent; +import io.github.sakurawald.module.initializer.ModuleInitializer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; + +public class CommandSpyModule extends ModuleInitializer { + @Override + public void onInitialize() { + PreCommandExecuteEvent.EVENT.register((parseResults, string) -> { + ServerPlayerEntity player = parseResults.getContext().getSource().getPlayer(); + if (player == null) return ActionResult.PASS; + + // fix: fabric console will not log the command issue + Fuji.LOGGER.info("{} issued server command: {}", player.getGameProfile().getName(), string); + + return ActionResult.PASS; + }); + } +} diff --git a/src/main/java/io/github/sakurawald/module/initializer/home/HomeModule.java b/src/main/java/io/github/sakurawald/module/initializer/home/HomeModule.java index 9509bc341..cedf64a5e 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/home/HomeModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/home/HomeModule.java @@ -10,7 +10,7 @@ import io.github.sakurawald.config.handler.ObjectConfigHandler; import io.github.sakurawald.config.model.HomeModel; import io.github.sakurawald.module.initializer.ModuleInitializer; -import io.github.sakurawald.common.Position; +import io.github.sakurawald.common.structure.Position; import io.github.sakurawald.util.CommandUtil; import io.github.sakurawald.util.MessageUtil; import io.github.sakurawald.util.ScheduleUtil; diff --git a/src/main/java/io/github/sakurawald/module/initializer/reply/ReplyModule.java b/src/main/java/io/github/sakurawald/module/initializer/reply/ReplyModule.java index d34a6bc3e..0bd1eb07b 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/reply/ReplyModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/reply/ReplyModule.java @@ -6,6 +6,7 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import io.github.sakurawald.Fuji; +import io.github.sakurawald.common.event.PreCommandExecuteEvent; import io.github.sakurawald.module.initializer.ModuleInitializer; import io.github.sakurawald.util.CommandUtil; import io.github.sakurawald.util.MessageUtil; @@ -13,6 +14,7 @@ import net.minecraft.command.CommandRegistryAccess; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; import static net.minecraft.server.command.CommandManager.argument; diff --git a/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldManager.java b/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldManager.java index 14403605f..1c29ae1ae 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldManager.java +++ b/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldManager.java @@ -2,7 +2,7 @@ import io.github.sakurawald.module.ModuleManager; import io.github.sakurawald.module.initializer.resource_world.interfaces.SimpleRegistryMixinInterface; -import io.github.sakurawald.common.Position; +import io.github.sakurawald.common.structure.Position; import io.github.sakurawald.module.initializer.teleport_warmup.TeleportTicket; import io.github.sakurawald.module.initializer.teleport_warmup.TeleportWarmupModule; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; diff --git a/src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/TeleportTicket.java b/src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/TeleportTicket.java index 5331fa508..fc09c43fd 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/TeleportTicket.java +++ b/src/main/java/io/github/sakurawald/module/initializer/teleport_warmup/TeleportTicket.java @@ -1,6 +1,6 @@ package io.github.sakurawald.module.initializer.teleport_warmup; -import io.github.sakurawald.common.Position; +import io.github.sakurawald.common.structure.Position; import io.github.sakurawald.util.MessageUtil; import net.kyori.adventure.bossbar.BossBar; import net.minecraft.server.network.ServerPlayerEntity; diff --git a/src/main/java/io/github/sakurawald/module/mixin/_internal/event/CommandManagerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/_internal/event/CommandManagerMixin.java new file mode 100644 index 000000000..fcfd00a79 --- /dev/null +++ b/src/main/java/io/github/sakurawald/module/mixin/_internal/event/CommandManagerMixin.java @@ -0,0 +1,25 @@ +package io.github.sakurawald.module.mixin._internal.event; + +import com.mojang.brigadier.ParseResults; +import io.github.sakurawald.common.event.PreCommandExecuteEvent; +import net.minecraft.server.command.CommandManager; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.util.ActionResult; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(CommandManager.class) +public class CommandManagerMixin { + + // If you issue "///abcdefg", then commandLine = "//abcdefg" + @Inject(method = "execute", at = @At("HEAD"), cancellable = true) + public void $execute(ParseResults parseResults, String string, CallbackInfo ci) { + ActionResult result = PreCommandExecuteEvent.EVENT.invoker().interact(parseResults, string); + if (result == ActionResult.FAIL) { + ci.cancel(); + } + } + +} diff --git a/src/main/java/io/github/sakurawald/module/mixin/command_cooldown/CommandsMixin.java b/src/main/java/io/github/sakurawald/module/mixin/command_cooldown/CommandsMixin.java deleted file mode 100644 index 5baa240ee..000000000 --- a/src/main/java/io/github/sakurawald/module/mixin/command_cooldown/CommandsMixin.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.github.sakurawald.module.mixin.command_cooldown; - -import com.mojang.brigadier.ParseResults; -import io.github.sakurawald.module.ModuleManager; -import io.github.sakurawald.module.initializer.command_cooldown.CommandCooldownModule; -import io.github.sakurawald.util.MessageUtil; -import net.minecraft.server.command.CommandManager; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(CommandManager.class) - -public class CommandsMixin { - - @Unique - private static final CommandCooldownModule module = ModuleManager.getInitializer(CommandCooldownModule.class); - - // If you issue "///abcdefg", then commandLine = "//abcdefg" - @Inject(method = "execute", at = @At("HEAD"), cancellable = true) - public void $execute(ParseResults parseResults, String string, CallbackInfo ci) { - ServerPlayerEntity player = parseResults.getContext().getSource().getPlayer(); - if (player == null) return; - - long cooldown = module.calculateCommandCooldown(player, string); - if (cooldown > 0) { - MessageUtil.sendActionBar(player, "command_cooldown.cooldown", cooldown / 1000); - ci.cancel(); - } - } -} diff --git a/src/main/java/io/github/sakurawald/module/mixin/command_spy/CommandsMixin.java b/src/main/java/io/github/sakurawald/module/mixin/command_spy/CommandsMixin.java deleted file mode 100644 index 81536628e..000000000 --- a/src/main/java/io/github/sakurawald/module/mixin/command_spy/CommandsMixin.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.github.sakurawald.module.mixin.command_spy; - -import com.mojang.brigadier.ParseResults; -import io.github.sakurawald.Fuji; -import net.minecraft.server.command.CommandManager; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(CommandManager.class) -public class CommandsMixin { - - // If you issue "///abcdefg", then commandLine = "//abcdefg" - @Inject(method = "execute", at = @At("HEAD")) - public void $execute(ParseResults parseResults, String string, CallbackInfo ci) { - ServerPlayerEntity player = parseResults.getContext().getSource().getPlayer(); - if (player == null) return; - - // fix: fabric console will not log the command issue - Fuji.LOGGER.info("{} issued server command: {}", player.getGameProfile().getName(), string); - } -} diff --git a/src/main/java/io/github/sakurawald/module/mixin/teleport_warmup/ServerPlayerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/teleport_warmup/ServerPlayerMixin.java index ef29b9cda..3d58e7183 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/teleport_warmup/ServerPlayerMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/teleport_warmup/ServerPlayerMixin.java @@ -2,7 +2,7 @@ import io.github.sakurawald.module.ModuleManager; import io.github.sakurawald.module.initializer.back.BackModule; -import io.github.sakurawald.common.Position; +import io.github.sakurawald.common.structure.Position; import io.github.sakurawald.module.initializer.teleport_warmup.ServerPlayerCombatStateAccessor; import io.github.sakurawald.module.initializer.teleport_warmup.TeleportTicket; import io.github.sakurawald.module.initializer.teleport_warmup.TeleportWarmupModule; diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index 680779a77..b7b22b9b7 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -4,6 +4,7 @@ "compatibilityLevel": "JAVA_17", "plugin": "io.github.sakurawald.module.mixin.ModuleMixinConfigPlugin", "mixins": [ + "_internal.event.CommandManagerMixin", "_internal.event.PlayerManagerMixin", "_internal.event.ServerPlayerEntityMixin", "_internal.event.ServerPlayNetworkHandlerMixin", @@ -16,10 +17,8 @@ "bypass_move_speed.ServerGamePacketListenerImplMixin", "chat.PlayerListMixin", "chat.ServerGamePacketListenerImplMixin", - "command_cooldown.CommandsMixin", "command_interactive.SignBlockMixin", "command_permission.CommandNodeAccessor", - "command_spy.CommandsMixin", "fake_player_manager.PlayerCommandMixin", "fake_player_manager.PlayerMixin", "fix_player_list_cme.PlayerListMixin", From 001dc156e9d66f18c2c11ecae2ab840f0bb02590 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Wed, 19 Jun 2024 14:37:47 +0800 Subject: [PATCH 19/50] add: todo list --- .../github/sakurawald/module/initializer/chat/ChatModule.java | 1 + .../module/initializer/resource_world/ResourceWorldModule.java | 1 - .../mixin/_internal/server_instance/MinecraftServerMixin.java | 2 +- .../registry/DimensionOptionsRegistryHolderMixin.java | 3 +++ 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java b/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java index d0016590b..802e8162c 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java @@ -169,6 +169,7 @@ private Component resolvePositionTag(ServerPlayerEntity player, Component compon } String dim_display_name; + // TODO: insert `pos` in resource world will throw error if (MessageUtil.ofString(player, dim_name) != null) { dim_display_name = MessageUtil.ofString(player, dim_name); } else { diff --git a/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldModule.java b/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldModule.java index 2a75f7063..2c6d68698 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/resource_world/ResourceWorldModule.java @@ -51,7 +51,6 @@ import static net.minecraft.server.command.CommandManager.literal; - public class ResourceWorldModule extends ModuleInitializer { private final String DEFAULT_RESOURCE_WORLD_NAMESPACE = "resource_world"; diff --git a/src/main/java/io/github/sakurawald/module/mixin/_internal/server_instance/MinecraftServerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/_internal/server_instance/MinecraftServerMixin.java index 80dbdc85b..cc3c662c1 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/_internal/server_instance/MinecraftServerMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/_internal/server_instance/MinecraftServerMixin.java @@ -15,7 +15,7 @@ public class MinecraftServerMixin { @Inject(method = "", at = @At("RETURN")) private void $init(CallbackInfo ci) { MinecraftServer server = (MinecraftServer) (Object) this; - LOGGER.debug("MinecraftServerMixin: $init: " + server); + LOGGER.debug("MinecraftServerMixin: $init: {}", server); Fuji.SERVER = server; } } diff --git a/src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/DimensionOptionsRegistryHolderMixin.java b/src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/DimensionOptionsRegistryHolderMixin.java index c0c1916fd..b48fea1d8 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/DimensionOptionsRegistryHolderMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/DimensionOptionsRegistryHolderMixin.java @@ -13,6 +13,9 @@ @Mixin(DimensionOptionsRegistryHolder.class) public class DimensionOptionsRegistryHolderMixin { + + // TODO: fix a bug + /* Prevent resource worlds to write in level.dat */ @ModifyArg(method = "method_45516", at = @At(value = "INVOKE", target = "Lcom/mojang/serialization/MapCodec;forGetter(Ljava/util/function/Function;)Lcom/mojang/serialization/codecs/RecordCodecBuilder;")) private static Function> fuji$swapRegistryGetter(Function> getter) { From a9779591b68694cad7c5f9bb43d8b62f99280c0d Mon Sep 17 00:00:00 2001 From: sakurawald Date: Thu, 20 Jun 2024 09:06:40 +0800 Subject: [PATCH 20/50] fix: possible NPE in DimensionOptionsRegistryHolder in resource world module --- .../DimensionOptionsMixinInterface.java | 2 +- .../DimensionOptionsRegistryHolderMixin.java | 24 ---------- .../registry/SimpleRegistryMixin.java | 48 ++++++++++++------- .../registry/WorldGenSettingsMixin.java | 27 +++++++++++ src/main/resources/fuji.mixins.json | 2 +- 5 files changed, 60 insertions(+), 43 deletions(-) delete mode 100644 src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/DimensionOptionsRegistryHolderMixin.java create mode 100644 src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/WorldGenSettingsMixin.java diff --git a/src/main/java/io/github/sakurawald/module/initializer/resource_world/interfaces/DimensionOptionsMixinInterface.java b/src/main/java/io/github/sakurawald/module/initializer/resource_world/interfaces/DimensionOptionsMixinInterface.java index 528a2a6a9..c891b669d 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/resource_world/interfaces/DimensionOptionsMixinInterface.java +++ b/src/main/java/io/github/sakurawald/module/initializer/resource_world/interfaces/DimensionOptionsMixinInterface.java @@ -1,9 +1,9 @@ package io.github.sakurawald.module.initializer.resource_world.interfaces; +import net.minecraft.world.dimension.DimensionOptions; import org.jetbrains.annotations.ApiStatus; import java.util.function.Predicate; -import net.minecraft.world.dimension.DimensionOptions; @ApiStatus.Internal public interface DimensionOptionsMixinInterface { diff --git a/src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/DimensionOptionsRegistryHolderMixin.java b/src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/DimensionOptionsRegistryHolderMixin.java deleted file mode 100644 index b48fea1d8..000000000 --- a/src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/DimensionOptionsRegistryHolderMixin.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.github.sakurawald.module.mixin.resource_world.registry; - -import io.github.sakurawald.module.initializer.resource_world.FilteredRegistry; -import io.github.sakurawald.module.initializer.resource_world.interfaces.DimensionOptionsMixinInterface; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyArg; - -import java.util.function.Function; -import net.minecraft.registry.Registry; -import net.minecraft.world.dimension.DimensionOptions; -import net.minecraft.world.dimension.DimensionOptionsRegistryHolder; - -@Mixin(DimensionOptionsRegistryHolder.class) -public class DimensionOptionsRegistryHolderMixin { - - // TODO: fix a bug - - /* Prevent resource worlds to write in level.dat */ - @ModifyArg(method = "method_45516", at = @At(value = "INVOKE", target = "Lcom/mojang/serialization/MapCodec;forGetter(Ljava/util/function/Function;)Lcom/mojang/serialization/codecs/RecordCodecBuilder;")) - private static Function> fuji$swapRegistryGetter(Function> getter) { - return (x) -> new FilteredRegistry<>(getter.apply(x), DimensionOptionsMixinInterface.SAVE_PROPERTIES_PREDICATE); - } -} diff --git a/src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/SimpleRegistryMixin.java b/src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/SimpleRegistryMixin.java index 9bbd229dd..bc9e452c4 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/SimpleRegistryMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/SimpleRegistryMixin.java @@ -1,29 +1,31 @@ package io.github.sakurawald.module.mixin.resource_world.registry; -import com.mojang.serialization.Lifecycle; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; import io.github.sakurawald.Fuji; import io.github.sakurawald.module.initializer.resource_world.interfaces.SimpleRegistryMixinInterface; -import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.ObjectList; import it.unimi.dsi.fastutil.objects.Reference2IntMap; -import org.jetbrains.annotations.Nullable; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.List; -import java.util.Map; -import java.util.Optional; +import net.minecraft.registry.MutableRegistry; +import net.minecraft.registry.Registry; import net.minecraft.registry.RegistryKey; import net.minecraft.registry.SimpleRegistry; import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.registry.entry.RegistryEntry.Reference; +import net.minecraft.registry.entry.RegistryEntryInfo; import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; + +import java.util.Map; +import java.util.Objects; +import java.util.stream.Stream; @SuppressWarnings("unused") @Mixin(SimpleRegistry.class) -public abstract class SimpleRegistryMixin implements SimpleRegistryMixinInterface { +public abstract class SimpleRegistryMixin implements SimpleRegistryMixinInterface, MutableRegistry { @Shadow @Final @@ -37,6 +39,10 @@ public abstract class SimpleRegistryMixin implements SimpleRegistryMixinInter @Final private Map, RegistryEntry.Reference> keyToEntry; + @Shadow + @Final + private Map, RegistryEntryInfo> keyToEntryInfo; + @Shadow @Final private ObjectList> rawIdToEntry; @@ -46,10 +52,12 @@ public abstract class SimpleRegistryMixin implements SimpleRegistryMixinInter private Reference2IntMap entryToRawId; @Shadow - private boolean frozen; + @Final + RegistryKey> key; @Shadow - public abstract Optional> getEntry(int rawId); + private boolean frozen; + @Override public boolean fuji$remove(T entry) { @@ -60,14 +68,14 @@ public abstract class SimpleRegistryMixin implements SimpleRegistryMixinInter } try { - this.rawIdToEntry.set(rawId, null); - this.idToEntry.remove(registryEntry.registryKey().getValue()); this.keyToEntry.remove(registryEntry.registryKey()); + this.idToEntry.remove(registryEntry.registryKey().getValue()); this.valueToEntry.remove(entry); - + this.rawIdToEntry.set(rawId, null); + this.keyToEntryInfo.remove(this.key); return true; } catch (Throwable e) { - Fuji.LOGGER.error("Failed to remove entry: " + entry.toString()); + Fuji.LOGGER.error("Failed to remove entry: {}", entry.toString()); return false; } } @@ -87,4 +95,10 @@ public abstract class SimpleRegistryMixin implements SimpleRegistryMixinInter public boolean fuji$isFrozen() { return this.frozen; } + + @ModifyReturnValue(method = "streamEntries", at = @At("RETURN")) + public Stream> fixEntryStream(Stream> original) { + return original.filter(Objects::nonNull); + } } + diff --git a/src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/WorldGenSettingsMixin.java b/src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/WorldGenSettingsMixin.java new file mode 100644 index 000000000..4c6e751a7 --- /dev/null +++ b/src/main/java/io/github/sakurawald/module/mixin/resource_world/registry/WorldGenSettingsMixin.java @@ -0,0 +1,27 @@ +package io.github.sakurawald.module.mixin.resource_world.registry; + +import com.google.common.collect.Maps; +import io.github.sakurawald.module.initializer.resource_world.interfaces.DimensionOptionsMixinInterface; +import net.minecraft.registry.RegistryKey; +import net.minecraft.world.dimension.DimensionOptions; +import net.minecraft.world.dimension.DimensionOptionsRegistryHolder; +import net.minecraft.world.gen.GeneratorOptions; +import net.minecraft.world.level.WorldGenSettings; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +import java.util.Map; + +@Mixin(WorldGenSettings.class) +public class WorldGenSettingsMixin { + + @ModifyArg(method = "encode(Lcom/mojang/serialization/DynamicOps;Lnet/minecraft/world/gen/GeneratorOptions;Lnet/minecraft/world/dimension/DimensionOptionsRegistryHolder;)Lcom/mojang/serialization/DataResult;", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/WorldGenSettings;(Lnet/minecraft/world/gen/GeneratorOptions;Lnet/minecraft/world/dimension/DimensionOptionsRegistryHolder;)V"), index = 1) + private static DimensionOptionsRegistryHolder $wrapWorldGenSettings(DimensionOptionsRegistryHolder original) { + Map, DimensionOptions> dimensions = original.comp_1014(); + var saveDimensions = Maps.filterEntries(dimensions, entry -> DimensionOptionsMixinInterface.SAVE_PROPERTIES_PREDICATE.test(entry.getValue())); + return new DimensionOptionsRegistryHolder(saveDimensions); + } +} diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index b7b22b9b7..29ead23be 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -34,8 +34,8 @@ "resource_world.MinecraftServerMixin", "resource_world.ServerWorldMixin", "resource_world.registry.DimensionOptionsMixin", - "resource_world.registry.DimensionOptionsRegistryHolderMixin", "resource_world.registry.SimpleRegistryMixin", + "resource_world.registry.WorldGenSettingsMixin", "seen.GameProfileCacheMixin", "seen.PlayerListMixin", "sit.InteractModifierMixin", From d079ae8632e8046c727ec98e4dc8d711252f55af Mon Sep 17 00:00:00 2001 From: sakurawald Date: Thu, 20 Jun 2024 13:38:35 +0800 Subject: [PATCH 21/50] refactor: module manager --- gradle.properties | 2 +- src/main/java/io/github/sakurawald/Fuji.java | 1 + .../java/io/github/sakurawald/module/ModuleManager.java | 7 +++++-- .../sakurawald/module/initializer/ModuleInitializer.java | 6 ++++-- .../module/initializer/main_stats/MainStatsModule.java | 4 ++++ .../sakurawald/module/mixin/ModuleMixinConfigPlugin.java | 2 +- 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/gradle.properties b/gradle.properties index ce4328faa..f12d3ce3b 100755 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx8G org.gradle.parallel=true # mod properties -mod_version=1.2.0 +mod_version=1.2.1 maven_group=io.github.sakurawald archives_base_name=fuji diff --git a/src/main/java/io/github/sakurawald/Fuji.java b/src/main/java/io/github/sakurawald/Fuji.java index 4609c3b0c..77e8ecaa1 100644 --- a/src/main/java/io/github/sakurawald/Fuji.java +++ b/src/main/java/io/github/sakurawald/Fuji.java @@ -23,6 +23,7 @@ // TODO: playtime(every/for) rewards and rank like module // TODO: kit module -> spec-command // TODO: luckperms context calculate module + public class Fuji implements ModInitializer { public static final String MOD_ID = "fuji"; public static final Logger LOGGER = LogUtil.createLogger("Fuji"); diff --git a/src/main/java/io/github/sakurawald/module/ModuleManager.java b/src/main/java/io/github/sakurawald/module/ModuleManager.java index d83764735..f95d41ac7 100644 --- a/src/main/java/io/github/sakurawald/module/ModuleManager.java +++ b/src/main/java/io/github/sakurawald/module/ModuleManager.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.ApiStatus; import org.reflections.Reflections; +import javax.naming.OperationNotSupportedException; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -31,6 +32,8 @@ public static void reloadModules() { initializers.values().forEach(initializer -> { try { initializer.onReload(); + } catch (OperationNotSupportedException e) { + // no-op } catch (Exception e) { LOGGER.error("Failed to reload module -> {}", e.getMessage()); } @@ -62,7 +65,7 @@ public static T getInitializer(Class clazz) { JsonElement config = Configs.configHandler.toJsonElement(); if (!initializers.containsKey(clazz)) { String basePackageName = calculateBasePackageName(ModuleInitializer.class, clazz.getName()); - if (enableModule(config, basePackageName)) { + if (shouldEnableModule(config, basePackageName)) { try { ModuleInitializer moduleInitializer = clazz.getDeclaredConstructor().newInstance(); moduleInitializer.initialize(); @@ -75,7 +78,7 @@ public static T getInitializer(Class clazz) { return clazz.cast(initializers.get(clazz)); } - public static boolean enableModule(JsonElement config, String basePackageName) { + public static boolean shouldEnableModule(JsonElement config, String basePackageName) { boolean enable; try { enable = config.getAsJsonObject().get("modules").getAsJsonObject().get(basePackageName).getAsJsonObject().get("enable").getAsBoolean(); diff --git a/src/main/java/io/github/sakurawald/module/initializer/ModuleInitializer.java b/src/main/java/io/github/sakurawald/module/initializer/ModuleInitializer.java index 6bacc474c..a078ee6dc 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/ModuleInitializer.java +++ b/src/main/java/io/github/sakurawald/module/initializer/ModuleInitializer.java @@ -7,6 +7,8 @@ import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; +import javax.naming.OperationNotSupportedException; + public abstract class ModuleInitializer { public final void initialize() { @@ -18,8 +20,8 @@ public void onInitialize() { // no-op } - public void onReload() { - // no-op + public void onReload() throws OperationNotSupportedException { + throw new OperationNotSupportedException("This module don't support reload"); } public void registerCommand(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess, CommandManager.RegistrationEnvironment environment) { diff --git a/src/main/java/io/github/sakurawald/module/initializer/main_stats/MainStatsModule.java b/src/main/java/io/github/sakurawald/module/initializer/main_stats/MainStatsModule.java index 7bf5e36af..16c6eb85c 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/main_stats/MainStatsModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/main_stats/MainStatsModule.java @@ -9,8 +9,11 @@ import io.github.sakurawald.module.initializer.motd.MotdModule; import io.github.sakurawald.util.ScheduleUtil; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; import net.minecraft.server.MinecraftServer; import net.minecraft.util.ActionResult; +import net.minecraft.util.Identifier; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; @@ -27,6 +30,7 @@ public class MainStatsModule extends ModuleInitializer { @Override public void onInitialize() { + ServerLifecycleEvents.SERVER_STARTED.register(server -> { this.updateMainStats(server); this.registerScheduleTask(server); diff --git a/src/main/java/io/github/sakurawald/module/mixin/ModuleMixinConfigPlugin.java b/src/main/java/io/github/sakurawald/module/mixin/ModuleMixinConfigPlugin.java index cb79e6077..1086d016a 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/ModuleMixinConfigPlugin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/ModuleMixinConfigPlugin.java @@ -37,7 +37,7 @@ public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { // bypass if (basePackageName.startsWith("_")) return true; - return ModuleManager.enableModule(mixinConfigs, basePackageName); + return ModuleManager.shouldEnableModule(mixinConfigs, basePackageName); } @Override From 7a23db431a3c00e70b47d21ef2ad7a1a91f1aa6a Mon Sep 17 00:00:00 2001 From: sakurawald Date: Thu, 4 Jul 2024 01:00:13 +0800 Subject: [PATCH 22/50] fix: can't get command completion for offline players if `seen module` is disabled. --- gradle.properties | 2 +- src/main/java/io/github/sakurawald/Fuji.java | 15 +++++++++------ .../structure}/GameProfileCacheEx.java | 2 +- .../low_level}/GameProfileCacheMixin.java | 4 ++-- .../MinecraftServerMixin.java | 2 +- .../io/github/sakurawald/util/CommandUtil.java | 2 +- src/main/resources/fuji.mixins.json | 4 ++-- 7 files changed, 17 insertions(+), 14 deletions(-) rename src/main/java/io/github/sakurawald/{module/initializer/seen => common/structure}/GameProfileCacheEx.java (67%) rename src/main/java/io/github/sakurawald/module/mixin/{seen => _internal/low_level}/GameProfileCacheMixin.java (83%) rename src/main/java/io/github/sakurawald/module/mixin/_internal/{server_instance => low_level}/MinecraftServerMixin.java (90%) diff --git a/gradle.properties b/gradle.properties index f12d3ce3b..f9dbb70f3 100755 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx8G org.gradle.parallel=true # mod properties -mod_version=1.2.1 +mod_version=1.2.2 maven_group=io.github.sakurawald archives_base_name=fuji diff --git a/src/main/java/io/github/sakurawald/Fuji.java b/src/main/java/io/github/sakurawald/Fuji.java index 77e8ecaa1..352801cc6 100644 --- a/src/main/java/io/github/sakurawald/Fuji.java +++ b/src/main/java/io/github/sakurawald/Fuji.java @@ -13,16 +13,19 @@ import java.nio.file.Path; -// TODO: /spawn module +// TODO: placeholder module (placeholder api) + +// TODO: specific command module +// TODO: add native shell support specific command +// TODO: kit module -> spec-command + // TODO: custom tab list // TODO: player nickname / prefix / suffix -// TODO: backup module -// TODO: warmup module -// TODO: placeholder module + +// TODO: command warmup module +// TODO: /spawn module // TODO: /tppos module // TODO: playtime(every/for) rewards and rank like module -// TODO: kit module -> spec-command -// TODO: luckperms context calculate module public class Fuji implements ModInitializer { public static final String MOD_ID = "fuji"; diff --git a/src/main/java/io/github/sakurawald/module/initializer/seen/GameProfileCacheEx.java b/src/main/java/io/github/sakurawald/common/structure/GameProfileCacheEx.java similarity index 67% rename from src/main/java/io/github/sakurawald/module/initializer/seen/GameProfileCacheEx.java rename to src/main/java/io/github/sakurawald/common/structure/GameProfileCacheEx.java index b44b4127e..3152a068a 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/seen/GameProfileCacheEx.java +++ b/src/main/java/io/github/sakurawald/common/structure/GameProfileCacheEx.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.module.initializer.seen; +package io.github.sakurawald.common.structure; import java.util.Collection; diff --git a/src/main/java/io/github/sakurawald/module/mixin/seen/GameProfileCacheMixin.java b/src/main/java/io/github/sakurawald/module/mixin/_internal/low_level/GameProfileCacheMixin.java similarity index 83% rename from src/main/java/io/github/sakurawald/module/mixin/seen/GameProfileCacheMixin.java rename to src/main/java/io/github/sakurawald/module/mixin/_internal/low_level/GameProfileCacheMixin.java index aa966d783..63064927e 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/seen/GameProfileCacheMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/_internal/low_level/GameProfileCacheMixin.java @@ -1,6 +1,6 @@ -package io.github.sakurawald.module.mixin.seen; +package io.github.sakurawald.module.mixin._internal.low_level; -import io.github.sakurawald.module.initializer.seen.GameProfileCacheEx; +import io.github.sakurawald.common.structure.GameProfileCacheEx; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/src/main/java/io/github/sakurawald/module/mixin/_internal/server_instance/MinecraftServerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/_internal/low_level/MinecraftServerMixin.java similarity index 90% rename from src/main/java/io/github/sakurawald/module/mixin/_internal/server_instance/MinecraftServerMixin.java rename to src/main/java/io/github/sakurawald/module/mixin/_internal/low_level/MinecraftServerMixin.java index cc3c662c1..e4d95e8b1 100644 --- a/src/main/java/io/github/sakurawald/module/mixin/_internal/server_instance/MinecraftServerMixin.java +++ b/src/main/java/io/github/sakurawald/module/mixin/_internal/low_level/MinecraftServerMixin.java @@ -1,4 +1,4 @@ -package io.github.sakurawald.module.mixin._internal.server_instance; +package io.github.sakurawald.module.mixin._internal.low_level; import io.github.sakurawald.Fuji; import net.minecraft.server.MinecraftServer; diff --git a/src/main/java/io/github/sakurawald/util/CommandUtil.java b/src/main/java/io/github/sakurawald/util/CommandUtil.java index c635950d0..b5f80dd1f 100644 --- a/src/main/java/io/github/sakurawald/util/CommandUtil.java +++ b/src/main/java/io/github/sakurawald/util/CommandUtil.java @@ -5,7 +5,7 @@ import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import io.github.sakurawald.Fuji; -import io.github.sakurawald.module.initializer.seen.GameProfileCacheEx; +import io.github.sakurawald.common.structure.GameProfileCacheEx; import lombok.experimental.UtilityClass; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index 29ead23be..be346de9b 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -8,7 +8,7 @@ "_internal.event.PlayerManagerMixin", "_internal.event.ServerPlayerEntityMixin", "_internal.event.ServerPlayNetworkHandlerMixin", - "_internal.server_instance.MinecraftServerMixin", + "_internal.low_level.MinecraftServerMixin", "afk.ServerPlayerMixin", "back.ServerPlayerMixin", "better_info.InfoCommandMixin", @@ -36,7 +36,7 @@ "resource_world.registry.DimensionOptionsMixin", "resource_world.registry.SimpleRegistryMixin", "resource_world.registry.WorldGenSettingsMixin", - "seen.GameProfileCacheMixin", + "_internal.low_level.GameProfileCacheMixin", "seen.PlayerListMixin", "sit.InteractModifierMixin", "skin.PlayerListMixin", From 40b64b2b4c1cf7c6b5af43a691ec7b40c329c0bc Mon Sep 17 00:00:00 2001 From: sakurawald Date: Thu, 4 Jul 2024 03:02:42 +0800 Subject: [PATCH 23/50] feature: add power provider option for `enchantment module` --- README.md | 14 ---------- .../sakurawald/config/model/ConfigModel.java | 9 +++++++ .../enchantment/EnchantmentModule.java | 19 +++++++++---- .../MyEnchantmentScreenHandler.java | 18 +++++++++++++ .../module/initializer/test/TestModule.java | 7 +++-- .../EnchantmentScreenHandlerMixin.java | 27 +++++++++++++++++++ src/main/resources/fuji.mixins.json | 3 ++- 7 files changed, 75 insertions(+), 22 deletions(-) create mode 100644 src/main/java/io/github/sakurawald/module/initializer/enchantment/MyEnchantmentScreenHandler.java create mode 100644 src/main/java/io/github/sakurawald/module/mixin/enchantment/EnchantmentScreenHandlerMixin.java diff --git a/README.md b/README.md index ef0ea8a6b..f47283f49 100755 --- a/README.md +++ b/README.md @@ -149,20 +149,6 @@ for offline whitelist, this makes whitelist ONLY compare the username and ignore #### CommandSpyModule log command issue into the console. -#### BiomeLookupCacheModule -an optimization for mob-spawn, this will cause the mob spawns a few blocks away from the biome-border (This will not influence structure-based mob spawn). - -> After many rounds of test (about 46000 chunks and 6000 entities), we found that this optimization can boost about 5~6 mspt, which is very considerable. - -#### TickChunkCacheModule -an optimization for iterating chunks, use event-based chunk-list constructor to avoid chunk-iteration lag. - -> Disable `mixin.experimental.chunk_tickets=false -` in Lithium to avoid in-compatibility with this module. -> Lithium does some other optimization in the same mixin. However, this mod provides a better performance at this point. -> -> About 3~4 mspt boost - #### SchedulerModule where you can add schedule jobs by cron expression, set the random command-list to be executed. diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index e31ab7c9a..b3ad64a50 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -518,6 +518,15 @@ public class Enchantment { public boolean enable = false; + @Comment("Should we override the power of proviers for the opened enchant table?") + public OverridePower override_power = new OverridePower(); + public class OverridePower { + + public boolean enable = false; + @Comment("How many power providers for the opened enchant table. For a max level of enchant table, it requires 15 power providers.") + public int power_provider_amount = 15; + } + } public class Anvil { diff --git a/src/main/java/io/github/sakurawald/module/initializer/enchantment/EnchantmentModule.java b/src/main/java/io/github/sakurawald/module/initializer/enchantment/EnchantmentModule.java index 4cb6a6cbb..db5e4540b 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/enchantment/EnchantmentModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/enchantment/EnchantmentModule.java @@ -5,14 +5,27 @@ import com.mojang.brigadier.context.CommandContext; import io.github.sakurawald.module.initializer.ModuleInitializer; import io.github.sakurawald.util.CommandUtil; +import net.minecraft.block.EnchantingTableBlock; import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.enchantment.EnchantmentLevelEntry; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.screen.EnchantmentScreenHandler; import net.minecraft.screen.ScreenHandlerContext; import net.minecraft.screen.SimpleNamedScreenHandlerFactory; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; +import net.minecraft.util.collection.IndexedIterable; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import java.util.List; public class EnchantmentModule extends ModuleInitializer { @Override @@ -22,11 +35,7 @@ public void registerCommand(CommandDispatcher dispatcher, C private int $enchantment(CommandContext ctx) { return CommandUtil.playerOnlyCommand(ctx, player -> { - player.openHandledScreen(new SimpleNamedScreenHandlerFactory((i, inventory, p) -> new EnchantmentScreenHandler(i, inventory, ScreenHandlerContext.create(p.getWorld(), p.getBlockPos())) { - @Override - public boolean canUse(PlayerEntity player) { - return true; - } + player.openHandledScreen(new SimpleNamedScreenHandlerFactory((i, inventory, p) -> new MyEnchantmentScreenHandler(i, inventory, ScreenHandlerContext.create(p.getWorld(), p.getBlockPos())) { }, Text.translatable("container.enchant"))); return Command.SINGLE_SUCCESS; }); diff --git a/src/main/java/io/github/sakurawald/module/initializer/enchantment/MyEnchantmentScreenHandler.java b/src/main/java/io/github/sakurawald/module/initializer/enchantment/MyEnchantmentScreenHandler.java new file mode 100644 index 000000000..824bf74da --- /dev/null +++ b/src/main/java/io/github/sakurawald/module/initializer/enchantment/MyEnchantmentScreenHandler.java @@ -0,0 +1,18 @@ +package io.github.sakurawald.module.initializer.enchantment; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.screen.EnchantmentScreenHandler; +import net.minecraft.screen.ScreenHandlerContext; + +public class MyEnchantmentScreenHandler extends EnchantmentScreenHandler { + + public MyEnchantmentScreenHandler(int i, PlayerInventory playerInventory, ScreenHandlerContext screenHandlerContext) { + super(i, playerInventory, screenHandlerContext); + } + + @Override + public boolean canUse(PlayerEntity player) { + return true; + } +} diff --git a/src/main/java/io/github/sakurawald/module/initializer/test/TestModule.java b/src/main/java/io/github/sakurawald/module/initializer/test/TestModule.java index ffccd5353..df8f002df 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/test/TestModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/test/TestModule.java @@ -6,6 +6,8 @@ import io.github.sakurawald.Fuji; import io.github.sakurawald.module.initializer.ModuleInitializer; import lombok.SneakyThrows; +import me.lucko.fabric.api.permissions.v0.Permissions; +import net.fabricmc.fabric.api.util.TriState; import net.kyori.adventure.text.Component; import net.minecraft.command.CommandRegistryAccess; import net.minecraft.server.command.CommandManager; @@ -25,8 +27,9 @@ private static int clearChat(CommandContext ctx) { } private static int magic(CommandContext ctx) { - ServerPlayerEntity player = ctx.getSource().getPlayer(); - player.sendMessage(Text.literal(String.valueOf(player.getMainHandStack().getComponents()))); + var source = ctx.getSource(); + TriState test = Permissions.getPermissionValue(source, "fuji.seed"); + source.sendMessage(Text.literal("state is " + test.name())); return 1; } diff --git a/src/main/java/io/github/sakurawald/module/mixin/enchantment/EnchantmentScreenHandlerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/enchantment/EnchantmentScreenHandlerMixin.java new file mode 100644 index 000000000..4e7fb0dda --- /dev/null +++ b/src/main/java/io/github/sakurawald/module/mixin/enchantment/EnchantmentScreenHandlerMixin.java @@ -0,0 +1,27 @@ +package io.github.sakurawald.module.mixin.enchantment; + +import io.github.sakurawald.config.Configs; +import io.github.sakurawald.module.initializer.enchantment.MyEnchantmentScreenHandler; +import lombok.extern.slf4j.Slf4j; +import net.minecraft.screen.EnchantmentScreenHandler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Mixin(EnchantmentScreenHandler.class) +@Slf4j +public class EnchantmentScreenHandlerMixin { + + @ModifyArg(method = "method_17411(Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/enchantment/EnchantmentHelper;calculateRequiredExperienceLevel(Lnet/minecraft/util/math/random/Random;IILnet/minecraft/item/ItemStack;)I"), index = 2) + int injected(int i) { + var enchantment = Configs.configHandler.model().modules.enchantment; + if (enchantment.enable) { + EnchantmentScreenHandler instance = ((EnchantmentScreenHandler) (Object) this); + if (instance instanceof MyEnchantmentScreenHandler) { + return enchantment.override_power.power_provider_amount; + } + } + return i; + } + +} diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index be346de9b..5b3465bd7 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -8,6 +8,7 @@ "_internal.event.PlayerManagerMixin", "_internal.event.ServerPlayerEntityMixin", "_internal.event.ServerPlayNetworkHandlerMixin", + "_internal.low_level.GameProfileCacheMixin", "_internal.low_level.MinecraftServerMixin", "afk.ServerPlayerMixin", "back.ServerPlayerMixin", @@ -19,6 +20,7 @@ "chat.ServerGamePacketListenerImplMixin", "command_interactive.SignBlockMixin", "command_permission.CommandNodeAccessor", + "enchantment.EnchantmentScreenHandlerMixin", "fake_player_manager.PlayerCommandMixin", "fake_player_manager.PlayerMixin", "fix_player_list_cme.PlayerListMixin", @@ -36,7 +38,6 @@ "resource_world.registry.DimensionOptionsMixin", "resource_world.registry.SimpleRegistryMixin", "resource_world.registry.WorldGenSettingsMixin", - "_internal.low_level.GameProfileCacheMixin", "seen.PlayerListMixin", "sit.InteractModifierMixin", "skin.PlayerListMixin", From 396960c642680c0d7840480ed20a8ea58bf4a84b Mon Sep 17 00:00:00 2001 From: sakurawald Date: Thu, 4 Jul 2024 03:03:00 +0800 Subject: [PATCH 24/50] feature: add power provider option for `enchantment module` --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index f9dbb70f3..53e152908 100755 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx8G org.gradle.parallel=true # mod properties -mod_version=1.2.2 +mod_version=1.2.3 maven_group=io.github.sakurawald archives_base_name=fuji From a73eb623ba0412cce7217ae4a326e326750989ec Mon Sep 17 00:00:00 2001 From: sakurawald Date: Thu, 4 Jul 2024 13:01:45 +0800 Subject: [PATCH 25/50] add: command rewrite module --- .../sakurawald/config/model/ConfigModel.java | 16 +++++++++-- .../command_rewrite/CommandRewriteEntry.java | 13 +++++++++ .../ServerPlayNetworkHandlerMixin.java | 25 +++++++++++++++++ src/main/resources/fuji.mixins.json | 1 + src/test/java/RegexTest.java | 28 +++++++++++++++++++ 5 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 src/main/java/io/github/sakurawald/module/initializer/command_rewrite/CommandRewriteEntry.java create mode 100644 src/main/java/io/github/sakurawald/module/mixin/command_rewrite/ServerPlayNetworkHandlerMixin.java create mode 100644 src/test/java/RegexTest.java diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index b3ad64a50..217669ba4 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -4,6 +4,7 @@ import com.mojang.authlib.properties.Property; import io.github.sakurawald.config.annotation.Comment; import io.github.sakurawald.module.initializer.command_alias.CommandAliasEntry; +import io.github.sakurawald.module.initializer.command_rewrite.CommandRewriteEntry; import java.util.ArrayList; import java.util.HashMap; @@ -522,7 +523,7 @@ public class Enchantment { public OverridePower override_power = new OverridePower(); public class OverridePower { - public boolean enable = false; + public boolean enable = true; @Comment("How many power providers for the opened enchant table. For a max level of enchant table, it requires 15 power providers.") public int power_provider_amount = 15; } @@ -571,10 +572,21 @@ public class CommandAlias { public List alias = new ArrayList<>() { { this.add(new CommandAliasEntry(List.of("r"), List.of("reply"))); - this.add(new CommandAliasEntry(List.of("magic", "stick", "applied"), List.of("gamemode"))); this.add(new CommandAliasEntry(List.of("i", "want", "to","modify","chat"), List.of("chat","format"))); } }; } + + public CommandRewrite command_rewrite = new CommandRewrite(); + public class CommandRewrite { + public boolean enable = false; + public List rules = new ArrayList<>() { + { + this.add(new CommandRewriteEntry("home", "home tp default")); + } + }; + + } + } } diff --git a/src/main/java/io/github/sakurawald/module/initializer/command_rewrite/CommandRewriteEntry.java b/src/main/java/io/github/sakurawald/module/initializer/command_rewrite/CommandRewriteEntry.java new file mode 100644 index 000000000..e343c547f --- /dev/null +++ b/src/main/java/io/github/sakurawald/module/initializer/command_rewrite/CommandRewriteEntry.java @@ -0,0 +1,13 @@ +package io.github.sakurawald.module.initializer.command_rewrite; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.List; + +@Data +@AllArgsConstructor +public class CommandRewriteEntry { + public String from; + public String to; +} diff --git a/src/main/java/io/github/sakurawald/module/mixin/command_rewrite/ServerPlayNetworkHandlerMixin.java b/src/main/java/io/github/sakurawald/module/mixin/command_rewrite/ServerPlayNetworkHandlerMixin.java new file mode 100644 index 000000000..f106a1a06 --- /dev/null +++ b/src/main/java/io/github/sakurawald/module/mixin/command_rewrite/ServerPlayNetworkHandlerMixin.java @@ -0,0 +1,25 @@ +package io.github.sakurawald.module.mixin.command_rewrite; + +import io.github.sakurawald.config.Configs; +import io.github.sakurawald.module.initializer.command_rewrite.CommandRewriteEntry; +import lombok.extern.slf4j.Slf4j; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(value = ServerPlayNetworkHandler.class, priority = 999) +@Slf4j +public class ServerPlayNetworkHandlerMixin { + + @ModifyVariable(method = "executeCommand", at = @At(value = "HEAD"), ordinal = 0, argsOnly = true) + public String $execute(String string) { + for (CommandRewriteEntry rule : Configs.configHandler.model().modules.command_rewrite.rules) { + if (string.matches(rule.from)) { + return string.replaceAll(rule.from, rule.to); + } + } + + return string; + } +} diff --git a/src/main/resources/fuji.mixins.json b/src/main/resources/fuji.mixins.json index 5b3465bd7..954221f8b 100755 --- a/src/main/resources/fuji.mixins.json +++ b/src/main/resources/fuji.mixins.json @@ -20,6 +20,7 @@ "chat.ServerGamePacketListenerImplMixin", "command_interactive.SignBlockMixin", "command_permission.CommandNodeAccessor", + "command_rewrite.ServerPlayNetworkHandlerMixin", "enchantment.EnchantmentScreenHandlerMixin", "fake_player_manager.PlayerCommandMixin", "fake_player_manager.PlayerMixin", diff --git a/src/test/java/RegexTest.java b/src/test/java/RegexTest.java new file mode 100644 index 000000000..f324ce21a --- /dev/null +++ b/src/test/java/RegexTest.java @@ -0,0 +1,28 @@ +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class RegexTest { + + @Test + void testNormal() { + assertEquals("/home tp default" + , "/home".replaceAll("/home", "/home tp default") + ); + } + + @Test + void testRef() { + assertEquals("/aid alice" + , "/help alice".replaceAll("/help (.*)", "/aid $1") + ); + } + + @Test + void testNoEffect() { + assertEquals("/first alice" + , "/first alice".replaceAll("/help (.*)", "/aid $1") + ); + + } +} From 9b03b71d3a7fb7d94c51b9dc1b273fcdc674e782 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Thu, 4 Jul 2024 13:02:59 +0800 Subject: [PATCH 26/50] update: README.md --- README.md | 3 +++ gradle.properties | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f47283f49..6791720aa 100755 --- a/README.md +++ b/README.md @@ -251,6 +251,9 @@ provides `/sit` command and sit interact. #### CommandAliasModule provides command alias so that you can alias existed commands in a short name. +#### CommandRewriteModule +provides command rewrite so that you can use regex to rewrite the command players issued. + # Config diff --git a/gradle.properties b/gradle.properties index 53e152908..670dc66f7 100755 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx8G org.gradle.parallel=true # mod properties -mod_version=1.2.3 +mod_version=1.2.4 maven_group=io.github.sakurawald archives_base_name=fuji From 9ba49d6f698c598c78a11221fa67ff4cf6c362eb Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 14:05:43 +0800 Subject: [PATCH 27/50] add: github wiki as submodule --- .gitmodules | 3 +++ fuji-fabric.wiki | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 fuji-fabric.wiki diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..e0de389b9 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "fuji-fabric.wiki"] + path = fuji-fabric.wiki + url = https://github.com/sakurawald/fuji-fabric.wiki.git diff --git a/fuji-fabric.wiki b/fuji-fabric.wiki new file mode 160000 index 000000000..02b497932 --- /dev/null +++ b/fuji-fabric.wiki @@ -0,0 +1 @@ +Subproject commit 02b497932e7500e2f131cb7c8232cbc4d9ee7c32 From 4354844d4f8a441489f904f276a501284d36978e Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 14:12:08 +0800 Subject: [PATCH 28/50] update: github wiki --- fuji-fabric.wiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuji-fabric.wiki b/fuji-fabric.wiki index 02b497932..04d6c859f 160000 --- a/fuji-fabric.wiki +++ b/fuji-fabric.wiki @@ -1 +1 @@ -Subproject commit 02b497932e7500e2f131cb7c8232cbc4d9ee7c32 +Subproject commit 04d6c859f063846f6ac2b3f712773da06626ba14 From 76e419605dcaceb71d48642cb45736ee9e86d088 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 14:21:56 +0800 Subject: [PATCH 29/50] update: github wiki --- README.md | 67 +++---------------------------------------------------- 1 file changed, 3 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 6791720aa..13cd2741d 100755 --- a/README.md +++ b/README.md @@ -256,70 +256,9 @@ provides command rewrite so that you can use regex to rewrite the command player -# Config - -### What is the format of config files? -To make the config files more `readable` and `transparent`, we use `.json` as the config file format. -We try our best to avoid the usage of `.dat` format -(The vanilla minecraft data file format which needs an NBTExplorer to view and edit). - -### Where are the config files? -All the config files are inside `config/fuji/` directory so -that you don't need to find out where the config files are. - -### How to update to a newer version? -Normally, the newer version will generate missing configuration keys automatically, but if this doesn't work, you can delete the old config file and restart the server to let the newer version generate the default config file. - -# Permission -This mod uses a low-level permission system, which means that most of the admin commands are required level-permission to use. However, if you really want a command-permission-node for every command, you can use the `fuji-command-permission` module (This module adds a prefix command-permission for ALL commands, even the command is not provided by this mod!). - -> In other words, most of the commands doesn't require any permission to use, but if you want, you can use `CommandPermissionModule` to add a prefix-permission for every command! - -# Optimization -For a better server performance and without vanilla sacrifice, we recommend you to use `Lithium` and `Krypton` with this mod. - -For JVM, we recommended GraalVM, which performs better than OpenJDK. -> Here are the JVM arguments we optimized for GraalVM (Reference from papermc and graalvm manual): -> -> java -Xms16G -Xmx16G -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=40 -XX:G1MaxNewSizePercent=50 -XX:G1HeapRegionSize=16M -XX:G1ReservePercent=15 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1 -XX:+UseLargePages -XX:+UseTransparentHugePages -XX:+EnableDynamicAgentLoading -Djava.io.tmpdir=/tmp -jar server.jar --nogui - -# Diagnosis -By default, this mod will output its `debug messages` into `logs/debug.log` so that you can know what this mod is doing. -You can add `-Dfuji.level="INFO"` to change the logger level. - -# Build from source -This mod is written on linux environment, but there are no native-method calls, so you can compile it on any platform. - -Clone the source: -```shell -$ git clone https://github.com/SakuraWald/fuji-fabric.git -``` -Change the working-directory: -```shell -$ cd fuji-fabric -``` -Compile the source: -```shell -$ ./gradlew build -``` - -# FAQ -### What is `cron expression`? - -Cron expression is an easy and powerful language used to define when a job should be triggered. -You can learn more and generate a cron expression from the generator: https://www.freeformatter.com/cron-expression-generator-quartz.html - -### This mod failed to mixin the server at server-startup stage, what should I do? - -This mod need `fabric-api` mod to work, so make sure you have installed `fabric-api` mod. - -Before you enable `BetterFakePlayerModule` and `BetterInfoModule` , you need to install `carpet` mod. - -Before you enable `ProfilerMoudle`, you need to install `spark` mod. - -### How can I report bugs or suggest new features? - -You can create an issue at the project's `github` page. +# Links +See [configuration](https://github.com/sakurawald/fuji-fabric/wiki/Configuration) +See [permission](https://github.com/sakurawald/fuji-fabric/wiki/Permission) # Thanks At the early stage of this project, we reference some source and ideas from the following projects: From 78c1cbcb77dd2dcaa42df1f3a01de2df3e5e9b12 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 14:24:51 +0800 Subject: [PATCH 30/50] update: github wiki --- fuji-fabric.wiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuji-fabric.wiki b/fuji-fabric.wiki index 04d6c859f..6f2882215 160000 --- a/fuji-fabric.wiki +++ b/fuji-fabric.wiki @@ -1 +1 @@ -Subproject commit 04d6c859f063846f6ac2b3f712773da06626ba14 +Subproject commit 6f288221582f76078be9d584a47fc3e1d2646051 From 56bd5407b5d2f62b6ca791b08ff5fc56d629b674 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 14:29:34 +0800 Subject: [PATCH 31/50] update: github wiki --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 13cd2741d..f6f9284e1 100755 --- a/README.md +++ b/README.md @@ -256,11 +256,12 @@ provides command rewrite so that you can use regex to rewrite the command player -# Links +# Wiki See [configuration](https://github.com/sakurawald/fuji-fabric/wiki/Configuration) + See [permission](https://github.com/sakurawald/fuji-fabric/wiki/Permission) -# Thanks +# Reference At the early stage of this project, we reference some source and ideas from the following projects: 1. https://www.zrips.net/cmi/ 2. https://essentialsx.net/ From 896956dd7336f83bd0e028b414507c9488aa2b88 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 14:33:32 +0800 Subject: [PATCH 32/50] update: github wiki --- README.md | 243 +----------------------------------------------------- 1 file changed, 2 insertions(+), 241 deletions(-) diff --git a/README.md b/README.md index 13cd2741d..83843a79c 100755 --- a/README.md +++ b/README.md @@ -16,247 +16,8 @@ Fuji is a minecraft mod that provides many essential and useful modules for vani possible (From data-structure, algorithm, lazy-load and cache to improve performance greatly). 4. **Easy-to-Use**: all the modules are designed to be easy to use, and the commands are designed to be easy to remember, even the language file is designed to be easy to understand. -# Modules - -_**By default, all the modules are disabled, and this mod does nothing to the vanilla minecraft.**_ - -
-Click here to display all the modules - -#### PvpModule -provides a command to toggle the pvp status. (/pvp [on/off/status/list]) -module presentation gif - -#### ResourceWorldModule -create and manage auto-reset resource world for overworld, the_nether and the_end. (/rw [tp/delete/reset]) -module presentation gif - -#### ChatModule -A simple chat system. - -> - Support mini-message based parser -> - Support mention players -> - Support chat-history -> new joined player can see the chat-history -> - Support per-player message-format settings -> /chat format -> - Support quick-codes -> - Insert "pos" -> current position -> - Support display -> - Insert "item" -> item display (support shulker-box) -> - Insert "inv" -> inventory display -> - Insert "ender" -> enderchest display -> - Support MainStats placeholders - -module presentation gif -module presentation gif - -#### TopChunksModule -Provides a command /chunks to show the most laggy chunks in the server. -module presentation gif - -#### BetterFakePlayerModule -(Carpet required) provides some management for fake-player. - -> - FakePlayerNameSuffixAndPrefix -> - FakePlayerManipulateLimit -> - Type `/player who` to see the owner of fake-player -> - Only the owner of the fake-player can manipulate the fake-player -> - FakePlayerSpawnLimit -> caps can be set to change dynamically -> - FakePlayerRenewTime -> - Every fake-player only lives for 12 hrs until you renew it (This avoids the fake-player to be a long-term laggy entity) -> - Type `/player renew` to renew the fake-player - -module presentation gif - -#### BetterInfoModule -(Carpet required) provides /info entity and add nbt-query for /info block -module presentation gif - -#### TeleportWarmupModule -provides a teleport warmup for all player-teleport to avoid the abuse of teleport (Including damage-cancel, combat-cancel, distance-cancel). -module presentation gif - -#### SkinModule -provides /skin command, and even an option to use local random-skin for fake-player (This fixes a laggy operation when spawning new fake-player and fetching the skin from mojang server). - -#### DeathLogModule -provides /deathlog command, which can log and restore the death-log for all players. -module presentation gif - -#### BackModule -provides /back command (Support smart-ignore by distance). - -#### TpaModule -provides /tpa and /tpahere (Full gui support, and easy to understand messages). -module presentation gif - -#### WorksModule -provides /works command, some bit like /warp but this module provides a very powerful hopper and minecart-hopper counter for every technical player to sample their contraption. -module presentation gif - -#### WorldDownloaderModule -provides /download command for every player who wants to download the nearby chunks around him. (Including rate-limit and attack-protection. This command is safe to use, because everytime the command will copy the original-region-file into a temp-file, and only send the temp-file, which does nothing to the original-region-file) -module presentation gif - -#### MainStatsModule -This module sums up some basic stats, like: total_playtime, total_mined, total_placed, total_killed and total_moved (We call these 5 stats `MainStats`). You can use these placeholders in ChatStyleModule and MOTDModule - -module presentation gif - -#### NewbieWelcomeModule -This module broadcasts a welcome-message and random teleport the new player and sets its respawn location. - -#### CommandCooldownModule -Yeah, you know what this module does. (Use this module to avoid some heavy-command abuse) - -#### MotdModule -A simple MOTD that supports fancy and random motd, and supports some placeholders like MainStats -module presentation gif - -#### HeadModule -provides /head command to buy player heads. - -#### ProfilerModule -provides /profiler to sample the server health. (Including os, vm, cpu, ram, tps, mspt and gc) - -#### CommandPermissionModule -this module modifies ALL commands (even the command is registered from other mods) and adds a prefix-permission (we called it fuji-permission) for the command. If the player has fuji-permission, then we check fuji-permission for that command, otherwise check the command's original requires-permission. - -> Tips: if you don't know how to determine command-node name, you can just type `/lp group default permission fuji.` and let luckperms tell you what command-node names you can use. -> - Allow the default group to use a command by adding a fuji-permission (e.g. /seed) -> `/lp group default permission set fuji.seed true` -> - Disallow the default group to use a command by adding a fuji-permission (e.g. /help) -> `/lp group default permission set fuji.help false` -> - Disallow the default group to use a sub-command from a command by adding a fuji-permission (e.g. /player [player] mount) -> `/lp group default permission set fuji.player.player.mount false` - -#### BypassThingsModule -provides options to bypass some annoyed things. - -- bypass-chat-rate-limit -> avoid "Kicked for spamming" -- bypass-move-speed-limit -> avoid "Moved too quickly!" -- bypass-max-player-limit -> avoid server max-player limit - -#### OpProtectModule -auto deop an op-player when he leaves the server. - -#### MultiObsidianPlatformModule -makes every EnderPortal generate its own Obsidian Platform (Up to 128 in survival-mode, you can even use creative-mode to build more Ender Portal and more ObsidianPlatform. Please note that: all the obsidian-platform are vanilla-respect, which means they have the SAME chunk-layout and the SAME behaviour as vanilla obsidian-platform which locates in (100,50,0)) -module presentation gif - -#### StrongerPlayerListModule -a fix patch for ServerWorld#PlayerList, to avoid CME in player-list (e.g. sometimes tick-entity and tick-block-entity will randomly crash the server because of player-list CME) - -#### WhitelistFixModule -for offline whitelist, this makes whitelist ONLY compare the username and ignore UUID! - -#### CommandSpyModule -log command issue into the console. - -#### SchedulerModule -where you can add schedule jobs by cron expression, set the random command-list to be executed. - -> If `left_trigger_times` < 0, then it means infinity times. - -#### ConfigModule -provides `/fuji reload` to reload configs. - -#### TestModule -provides `/test` command only for test purpose. (Disable this by default, and you don't need to enable this unless you know what you are doing) - -#### HatModule -provides `/hat` command - -#### FlyModule -provides `/fly` command - -#### GodModule -provides `/god` command - -#### LanguageModule -provides multi-language support for your players. -(Disable this module will force all the players to use the default language) - -- The default language is en_us. -- Respect the player's client-side language-setting. -- If the player's client-side language-setting is not supported, then use the default language. -- Lazy-load support, which means if a language is not required, then it will not be loaded. -- Dynamic-reload support, you need to enable `ConfigModule` to use reload command. - -#### ReplyModule -provides `/reply` command to quickly reply messages to the player who recently `/msg` you! - -#### AfkModule -provides `/afk` command to set your afk status and auto-afk - -#### SuicideModule -provides `/suicide` command. - -#### CommandInteractiveModule -provides interactive sign command. You can insert `//` plus commands in any sign, and then right-click it to execute the command quickly. - -- If the sign contains `//`, then you must press `shift` to edit this sign -- You can add some comments before the first `//` -- You can use all the four lines to insert `//` (Every `//` means one command) -- Placeholder `@u` means the user of this sign - -#### SeenModule -provides `/seen` command. - -#### MoreModule -provides `/more` command. - -#### ExtinguishModule -provides `/extinguish` command. - -#### HomeModule -provides `/home` command. - -#### PingModule -provides `/ping` command. - -#### SystemMessageModule -This module hijacks the vanilla system-message so that you can modify any system-message you want. -(Actually, you can hijack almost all the language messages in the vanilla `en_us.json` language file) -The system messages including: -- Player join and leave server message -- Player advancement message -- Player death message -- Player command feedback -- Player white-list message -- ... - - module presentation gif - -#### EnderChestModule -provides `/enderchest` command. - -#### WorkbenchModule -provides `/workbench` command. - -#### EnchantmentModule -provides `/enchantment` command. - -#### GrindStoneModule -provides `/grindstone` command. - -#### StoneCutterModule -provides `/stonecutter` command. - -#### AnvilModule -provides `/anvil` command. - -#### BedModule -provides `/bed` command. - -#### SitModule -provides `/sit` command and sit interact. - -#### CommandAliasModule -provides command alias so that you can alias existed commands in a short name. - -#### CommandRewriteModule -provides command rewrite so that you can use regex to rewrite the command players issued. - -
- -# Links +# Wiki +See [module](https://github.com/sakurawald/fuji-fabric/wiki/Module) See [configuration](https://github.com/sakurawald/fuji-fabric/wiki/Configuration) See [permission](https://github.com/sakurawald/fuji-fabric/wiki/Permission) From 310d5d2ae5f459a6c4837008eaff91cfe22ae7c4 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 14:33:43 +0800 Subject: [PATCH 33/50] update: github wiki --- fuji-fabric.wiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuji-fabric.wiki b/fuji-fabric.wiki index 6f2882215..0b7c3bffd 160000 --- a/fuji-fabric.wiki +++ b/fuji-fabric.wiki @@ -1 +1 @@ -Subproject commit 6f288221582f76078be9d584a47fc3e1d2646051 +Subproject commit 0b7c3bffd5fa9b67d4af71a5c494a7efe41a35cc From 3569f508202de1908eb7439a40cb3f5472cc92a3 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 14:36:18 +0800 Subject: [PATCH 34/50] update: github wiki --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 83843a79c..d64d418ca 100755 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -# Fuji -mod icon - +# Introduction Fuji is a minecraft mod that provides many essential and useful modules for vanilla survival. > **_If minecraft gets updated, you can mail sakurawald@gmail.com for fuji update reminder._** @@ -18,9 +16,13 @@ Fuji is a minecraft mod that provides many essential and useful modules for vani # Wiki See [module](https://github.com/sakurawald/fuji-fabric/wiki/Module) + See [configuration](https://github.com/sakurawald/fuji-fabric/wiki/Configuration) + See [permission](https://github.com/sakurawald/fuji-fabric/wiki/Permission) +See [faq](https://github.com/sakurawald/fuji-fabric/wiki/FAQ) + # Thanks At the early stage of this project, we reference some source and ideas from the following projects: 1. https://www.zrips.net/cmi/ From a501efafb135599c710c8d42a652ee6f087e7eae Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 14:38:11 +0800 Subject: [PATCH 35/50] update: github wiki --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d64d418ca..a41a6a860 100755 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ See [permission](https://github.com/sakurawald/fuji-fabric/wiki/Permission) See [faq](https://github.com/sakurawald/fuji-fabric/wiki/FAQ) -# Thanks +# Credit At the early stage of this project, we reference some source and ideas from the following projects: 1. https://www.zrips.net/cmi/ 2. https://essentialsx.net/ From 15621584d5ec2e771556c0d2427895b722756299 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 14:40:38 +0800 Subject: [PATCH 36/50] update: github wiki --- fuji-fabric.wiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuji-fabric.wiki b/fuji-fabric.wiki index 0b7c3bffd..b2581f993 160000 --- a/fuji-fabric.wiki +++ b/fuji-fabric.wiki @@ -1 +1 @@ -Subproject commit 0b7c3bffd5fa9b67d4af71a5c494a7efe41a35cc +Subproject commit b2581f9933ff141409c9c0160e1e0ca7c8d15e6c From bac27bdf945f3da4e103cf03f40f05f8d798e7ee Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 16:14:18 +0800 Subject: [PATCH 37/50] update: project icon + readme --- fuji-fabric.wiki | 2 +- src/main/resources/assets/fuji/icon.png | Bin 99883 -> 76408 bytes 2 files changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 src/main/resources/assets/fuji/icon.png diff --git a/fuji-fabric.wiki b/fuji-fabric.wiki index b2581f993..9176c501f 160000 --- a/fuji-fabric.wiki +++ b/fuji-fabric.wiki @@ -1 +1 @@ -Subproject commit b2581f9933ff141409c9c0160e1e0ca7c8d15e6c +Subproject commit 9176c501f3704c90b22be152d18a60bc16edfb71 diff --git a/src/main/resources/assets/fuji/icon.png b/src/main/resources/assets/fuji/icon.png old mode 100755 new mode 100644 index dcbd0e7638315a8cb874f5ba56138bc105866e0c..75f311c3f90d6ecef336081fdaba8b346c7f8fc1 GIT binary patch literal 76408 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%0D>+K4bECxZCH^cw` z@XjiPg!a9?ZKqQmwNwLAL2LD>rLx6VO;79MNW{wgV6n{9iG5J}jCJ}n|Lxl^n2#ew ztwrz02Js_={lJ@czL?u+H!W<^Nfz|TKRaX%Rv>>IS@0Dgw~vFIan%PuWpQCDLe#K` zG<0NK>8HzN>E6I-*%O-v=>LZJud=$OpFvhVx&Am#N52tN)UqYK!f>`zDqWC_Piadj zND~S`D0;owQ%W;&?Abn)BM~)qPg-IXD__d>m_(%Qf*^)T&3zkL1Mur$b_o*bc7Pa9 zrm}zt#~SO>+ubOQ=pJMh&W6i?0D8L%C2O@P48@V}yg%p0RrkDP`Y)p^I&{aut8~GF z0Sz^|6Sxqeg<0j0ZT(C{gq9VL!51=8#v{DC01U4x8pRZVx3{95H>|+YHOBX7rCV{M zsdr0~Tp;uqgJcOUEBZeN?4g3eL~MVm=nJx#g|`8T?TBGwvtP2X|9Zp^oQ>`Ia_bN( P00000NkvXXu0mjf_hY$# literal 99883 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

Q} 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

1?G^$#5Jqb`mr|A|)#jbv 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

djkv{Lv>S<{YP{ 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 T^X|{h00000NkvXXu0mjf#Y3tw From 37434b17ca1b443a424e5f6e58d8a3d92913aa9b Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 17:40:13 +0800 Subject: [PATCH 38/50] update: github wiki --- .github/files/en_us.json | 6883 +++++++++++++++++ .../sakurawald/config/annotation/Comment.java | 2 +- .../sakurawald/config/model/ConfigModel.java | 328 +- 3 files changed, 7173 insertions(+), 40 deletions(-) create mode 100644 .github/files/en_us.json diff --git a/.github/files/en_us.json b/.github/files/en_us.json new file mode 100644 index 000000000..0ec346f8d --- /dev/null +++ b/.github/files/en_us.json @@ -0,0 +1,6883 @@ +{ + "accessibility.onboarding.accessibility.button": "Accessibility Settings...", + "accessibility.onboarding.screen.narrator": "Press enter to enable the narrator", + "accessibility.onboarding.screen.title": "Welcome to Minecraft!\n\nWould you like to enable the Narrator or visit the Accessibility Settings?", + "addServer.add": "Done", + "addServer.enterIp": "Server Address", + "addServer.enterName": "Server Name", + "addServer.hideAddress": "Hide Address", + "addServer.resourcePack": "Server Resource Packs", + "addServer.resourcePack.disabled": "Disabled", + "addServer.resourcePack.enabled": "Enabled", + "addServer.resourcePack.prompt": "Prompt", + "addServer.title": "Edit Server Info", + "advancement.advancementNotFound": "Unknown advancement: %s", + "advancements.adventure.adventuring_time.description": "Discover every biome", + "advancements.adventure.adventuring_time.title": "Adventuring Time", + "advancements.adventure.arbalistic.description": "Kill five unique mobs with one crossbow shot", + "advancements.adventure.arbalistic.title": "Arbalistic", + "advancements.adventure.avoid_vibration.description": "Sneak near a Sculk Sensor or Warden to prevent it from detecting you", + "advancements.adventure.avoid_vibration.title": "Sneak 100", + "advancements.adventure.blowback.description": "Kill a Breeze with a deflected Breeze-shot Wind Charge", + "advancements.adventure.blowback.title": "Blowback", + "advancements.adventure.brush_armadillo.description": "Get Armadillo Scutes from an Armadillo using a Brush", + "advancements.adventure.brush_armadillo.title": "Isn't It Scute?", + "advancements.adventure.bullseye.description": "Hit the bullseye of a Target block from at least 30 meters away", + "advancements.adventure.bullseye.title": "Bullseye", + "advancements.adventure.craft_decorated_pot_using_only_sherds.description": "Make a Decorated Pot out of 4 Pottery Sherds", + "advancements.adventure.craft_decorated_pot_using_only_sherds.title": "Careful Restoration", + "advancements.adventure.crafters_crafting_crafters.description": "Be near a Crafter when it crafts a Crafter", + "advancements.adventure.crafters_crafting_crafters.title": "Crafters Crafting Crafters", + "advancements.adventure.fall_from_world_height.description": "Free fall from the top of the world (build limit) to the bottom of the world and survive", + "advancements.adventure.fall_from_world_height.title": "Caves & Cliffs", + "advancements.adventure.hero_of_the_village.description": "Successfully defend a village from a raid", + "advancements.adventure.hero_of_the_village.title": "Hero of the Village", + "advancements.adventure.honey_block_slide.description": "Jump into a Honey Block to break your fall", + "advancements.adventure.honey_block_slide.title": "Sticky Situation", + "advancements.adventure.kill_a_mob.description": "Kill any hostile monster", + "advancements.adventure.kill_a_mob.title": "Monster Hunter", + "advancements.adventure.kill_all_mobs.description": "Kill one of every hostile monster", + "advancements.adventure.kill_all_mobs.title": "Monsters Hunted", + "advancements.adventure.kill_mob_near_sculk_catalyst.description": "Kill a mob near a Sculk Catalyst", + "advancements.adventure.kill_mob_near_sculk_catalyst.title": "It Spreads", + "advancements.adventure.lighten_up.description": "Scrape a Copper Bulb with an Axe to make it brighter", + "advancements.adventure.lighten_up.title": "Lighten Up", + "advancements.adventure.lightning_rod_with_villager_no_fire.description": "Protect a Villager from an undesired shock without starting a fire", + "advancements.adventure.lightning_rod_with_villager_no_fire.title": "Surge Protector", + "advancements.adventure.minecraft_trials_edition.description": "Step foot in a Trial Chamber", + "advancements.adventure.minecraft_trials_edition.title": "Minecraft: Trial(s) Edition", + "advancements.adventure.ol_betsy.description": "Shoot a Crossbow", + "advancements.adventure.ol_betsy.title": "Ol' Betsy", + "advancements.adventure.overoverkill.description": "Deal 50 hearts of damage in a single hit using the Mace", + "advancements.adventure.overoverkill.title": "Over-Overkill", + "advancements.adventure.play_jukebox_in_meadows.description": "Make the Meadows come alive with the sound of music from a Jukebox", + "advancements.adventure.play_jukebox_in_meadows.title": "Sound of Music", + "advancements.adventure.read_power_from_chiseled_bookshelf.description": "Read the power signal of a Chiseled Bookshelf using a Comparator", + "advancements.adventure.read_power_from_chiseled_bookshelf.title": "The Power of Books", + "advancements.adventure.revaulting.description": "Unlock an Ominous Vault with an Ominous Trial Key", + "advancements.adventure.revaulting.title": "Revaulting", + "advancements.adventure.root.description": "Adventure, exploration and combat", + "advancements.adventure.root.title": "Adventure", + "advancements.adventure.salvage_sherd.description": "Brush a Suspicious block to obtain a Pottery Sherd", + "advancements.adventure.salvage_sherd.title": "Respecting the Remnants", + "advancements.adventure.shoot_arrow.description": "Shoot something with an Arrow", + "advancements.adventure.shoot_arrow.title": "Take Aim", + "advancements.adventure.sleep_in_bed.description": "Sleep in a Bed to change your respawn point", + "advancements.adventure.sleep_in_bed.title": "Sweet Dreams", + "advancements.adventure.sniper_duel.description": "Kill a Skeleton from at least 50 meters away", + "advancements.adventure.sniper_duel.title": "Sniper Duel", + "advancements.adventure.spyglass_at_dragon.description": "Look at the Ender Dragon through a Spyglass", + "advancements.adventure.spyglass_at_dragon.title": "Is It a Plane?", + "advancements.adventure.spyglass_at_ghast.description": "Look at a Ghast through a Spyglass", + "advancements.adventure.spyglass_at_ghast.title": "Is It a Balloon?", + "advancements.adventure.spyglass_at_parrot.description": "Look at a Parrot through a Spyglass", + "advancements.adventure.spyglass_at_parrot.title": "Is It a Bird?", + "advancements.adventure.summon_iron_golem.description": "Summon an Iron Golem to help defend a village", + "advancements.adventure.summon_iron_golem.title": "Hired Help", + "advancements.adventure.throw_trident.description": "Throw a Trident at something.\nNote: Throwing away your only weapon is not a good idea.", + "advancements.adventure.throw_trident.title": "A Throwaway Joke", + "advancements.adventure.totem_of_undying.description": "Use a Totem of Undying to cheat death", + "advancements.adventure.totem_of_undying.title": "Postmortal", + "advancements.adventure.trade_at_world_height.description": "Trade with a Villager at the build height limit", + "advancements.adventure.trade_at_world_height.title": "Star Trader", + "advancements.adventure.trade.description": "Successfully trade with a Villager", + "advancements.adventure.trade.title": "What a Deal!", + "advancements.adventure.trim_with_all_exclusive_armor_patterns.description": "Apply these smithing templates at least once: Spire, Snout, Rib, Ward, Silence, Vex, Tide, Wayfinder", + "advancements.adventure.trim_with_all_exclusive_armor_patterns.title": "Smithing with Style", + "advancements.adventure.trim_with_any_armor_pattern.description": "Craft a trimmed armor at a Smithing Table", + "advancements.adventure.trim_with_any_armor_pattern.title": "Crafting a New Look", + "advancements.adventure.two_birds_one_arrow.description": "Kill two Phantoms with a piercing Arrow", + "advancements.adventure.two_birds_one_arrow.title": "Two Birds, One Arrow", + "advancements.adventure.under_lock_and_key.description": "Unlock a Vault with a Trial Key", + "advancements.adventure.under_lock_and_key.title": "Under Lock and Key", + "advancements.adventure.very_very_frightening.description": "Strike a Villager with lightning", + "advancements.adventure.very_very_frightening.title": "Very Very Frightening", + "advancements.adventure.voluntary_exile.description": "Kill a raid captain.\nMaybe consider staying away from villages for the time being...", + "advancements.adventure.voluntary_exile.title": "Voluntary Exile", + "advancements.adventure.walk_on_powder_snow_with_leather_boots.description": "Walk on Powder Snow... without sinking in it", + "advancements.adventure.walk_on_powder_snow_with_leather_boots.title": "Light as a Rabbit", + "advancements.adventure.who_needs_rockets.description": "Use a Wind Charge to launch yourself upward 8 blocks", + "advancements.adventure.who_needs_rockets.title": "Who Needs Rockets?", + "advancements.adventure.whos_the_pillager_now.description": "Give a Pillager a taste of their own medicine", + "advancements.adventure.whos_the_pillager_now.title": "Who's the Pillager Now?", + "advancements.empty": "There doesn't seem to be anything here...", + "advancements.end.dragon_breath.description": "Collect Dragon's Breath in a Glass Bottle", + "advancements.end.dragon_breath.title": "You Need a Mint", + "advancements.end.dragon_egg.description": "Hold the Dragon Egg", + "advancements.end.dragon_egg.title": "The Next Generation", + "advancements.end.elytra.description": "Find Elytra", + "advancements.end.elytra.title": "Sky's the Limit", + "advancements.end.enter_end_gateway.description": "Escape the island", + "advancements.end.enter_end_gateway.title": "Remote Getaway", + "advancements.end.find_end_city.description": "Go on in, what could happen?", + "advancements.end.find_end_city.title": "The City at the End of the Game", + "advancements.end.kill_dragon.description": "Good luck", + "advancements.end.kill_dragon.title": "Free the End", + "advancements.end.levitate.description": "Levitate up 50 blocks from the attacks of a Shulker", + "advancements.end.levitate.title": "Great View From Up Here", + "advancements.end.respawn_dragon.description": "Respawn the Ender Dragon", + "advancements.end.respawn_dragon.title": "The End... Again...", + "advancements.end.root.description": "Or the beginning?", + "advancements.end.root.title": "The End", + "advancements.husbandry.allay_deliver_cake_to_note_block.description": "Have an Allay drop a Cake at a Note Block", + "advancements.husbandry.allay_deliver_cake_to_note_block.title": "Birthday Song", + "advancements.husbandry.allay_deliver_item_to_player.description": "Have an Allay deliver items to you", + "advancements.husbandry.allay_deliver_item_to_player.title": "You've Got a Friend in Me", + "advancements.husbandry.axolotl_in_a_bucket.description": "Catch an Axolotl in a Bucket", + "advancements.husbandry.axolotl_in_a_bucket.title": "The Cutest Predator", + "advancements.husbandry.balanced_diet.description": "Eat everything that is edible, even if it's not good for you", + "advancements.husbandry.balanced_diet.title": "A Balanced Diet", + "advancements.husbandry.breed_all_animals.description": "Breed all the animals!", + "advancements.husbandry.breed_all_animals.title": "Two by Two", + "advancements.husbandry.breed_an_animal.description": "Breed two animals together", + "advancements.husbandry.breed_an_animal.title": "The Parrots and the Bats", + "advancements.husbandry.complete_catalogue.description": "Tame all Cat variants!", + "advancements.husbandry.complete_catalogue.title": "A Complete Catalogue", + "advancements.husbandry.feed_snifflet.description": "Feed a Snifflet", + "advancements.husbandry.feed_snifflet.title": "Little Sniffs", + "advancements.husbandry.fishy_business.description": "Catch a fish", + "advancements.husbandry.fishy_business.title": "Fishy Business", + "advancements.husbandry.froglights.description": "Have all Froglights in your inventory", + "advancements.husbandry.froglights.title": "With Our Powers Combined!", + "advancements.husbandry.kill_axolotl_target.description": "Team up with an Axolotl and win a fight", + "advancements.husbandry.kill_axolotl_target.title": "The Healing Power of Friendship!", + "advancements.husbandry.leash_all_frog_variants.description": "Get each Frog variant on a Lead", + "advancements.husbandry.leash_all_frog_variants.title": "When the Squad Hops into Town", + "advancements.husbandry.make_a_sign_glow.description": "Make the text of any kind of sign glow", + "advancements.husbandry.make_a_sign_glow.title": "Glow and Behold!", + "advancements.husbandry.netherite_hoe.description": "Use a Netherite Ingot to upgrade a Hoe, and then reevaluate your life choices", + "advancements.husbandry.netherite_hoe.title": "Serious Dedication", + "advancements.husbandry.obtain_sniffer_egg.description": "Obtain a Sniffer Egg", + "advancements.husbandry.obtain_sniffer_egg.title": "Smells Interesting", + "advancements.husbandry.plant_any_sniffer_seed.description": "Plant any Sniffer seed", + "advancements.husbandry.plant_any_sniffer_seed.title": "Planting the Past", + "advancements.husbandry.plant_seed.description": "Plant a seed and watch it grow", + "advancements.husbandry.plant_seed.title": "A Seedy Place", + "advancements.husbandry.remove_wolf_armor.description": "Remove Wolf Armor from a Wolf using Shears", + "advancements.husbandry.remove_wolf_armor.title": "Shear Brilliance", + "advancements.husbandry.repair_wolf_armor.description": "Repair a damaged Wolf Armor using Armadillo Scutes", + "advancements.husbandry.repair_wolf_armor.title": "Good as New", + "advancements.husbandry.ride_a_boat_with_a_goat.description": "Get in a Boat and float with a Goat", + "advancements.husbandry.ride_a_boat_with_a_goat.title": "Whatever Floats Your Goat!", + "advancements.husbandry.root.description": "The world is full of friends and food", + "advancements.husbandry.root.title": "Husbandry", + "advancements.husbandry.safely_harvest_honey.description": "Use a Campfire to collect Honey from a Beehive using a Glass Bottle without aggravating the Bees", + "advancements.husbandry.safely_harvest_honey.title": "Bee Our Guest", + "advancements.husbandry.silk_touch_nest.description": "Move a Bee Nest, with 3 Bees inside, using Silk Touch", + "advancements.husbandry.silk_touch_nest.title": "Total Beelocation", + "advancements.husbandry.tactical_fishing.description": "Catch a Fish... without a Fishing Rod!", + "advancements.husbandry.tactical_fishing.title": "Tactical Fishing", + "advancements.husbandry.tadpole_in_a_bucket.description": "Catch a Tadpole in a Bucket", + "advancements.husbandry.tadpole_in_a_bucket.title": "Bukkit Bukkit", + "advancements.husbandry.tame_an_animal.description": "Tame an animal", + "advancements.husbandry.tame_an_animal.title": "Best Friends Forever", + "advancements.husbandry.wax_off.description": "Scrape Wax off of a Copper block!", + "advancements.husbandry.wax_off.title": "Wax Off", + "advancements.husbandry.wax_on.description": "Apply Honeycomb to a Copper block!", + "advancements.husbandry.wax_on.title": "Wax On", + "advancements.husbandry.whole_pack.description": "Tame one of each Wolf variant", + "advancements.husbandry.whole_pack.title": "The Whole Pack", + "advancements.nether.all_effects.description": "Have every effect applied at the same time", + "advancements.nether.all_effects.title": "How Did We Get Here?", + "advancements.nether.all_potions.description": "Have every potion effect applied at the same time", + "advancements.nether.all_potions.title": "A Furious Cocktail", + "advancements.nether.brew_potion.description": "Brew a Potion", + "advancements.nether.brew_potion.title": "Local Brewery", + "advancements.nether.charge_respawn_anchor.description": "Charge a Respawn Anchor to the maximum", + "advancements.nether.charge_respawn_anchor.title": "Not Quite \"Nine\" Lives", + "advancements.nether.create_beacon.description": "Construct and place a Beacon", + "advancements.nether.create_beacon.title": "Bring Home the Beacon", + "advancements.nether.create_full_beacon.description": "Bring a Beacon to full power", + "advancements.nether.create_full_beacon.title": "Beaconator", + "advancements.nether.distract_piglin.description": "Distract Piglins with gold", + "advancements.nether.distract_piglin.title": "Oh Shiny", + "advancements.nether.explore_nether.description": "Explore all Nether biomes", + "advancements.nether.explore_nether.title": "Hot Tourist Destinations", + "advancements.nether.fast_travel.description": "Use the Nether to travel 7 km in the Overworld", + "advancements.nether.fast_travel.title": "Subspace Bubble", + "advancements.nether.find_bastion.description": "Enter a Bastion Remnant", + "advancements.nether.find_bastion.title": "Those Were the Days", + "advancements.nether.find_fortress.description": "Break your way into a Nether Fortress", + "advancements.nether.find_fortress.title": "A Terrible Fortress", + "advancements.nether.get_wither_skull.description": "Obtain a Wither Skeleton's skull", + "advancements.nether.get_wither_skull.title": "Spooky Scary Skeleton", + "advancements.nether.loot_bastion.description": "Loot a Chest in a Bastion Remnant", + "advancements.nether.loot_bastion.title": "War Pigs", + "advancements.nether.netherite_armor.description": "Get a full suit of Netherite armor", + "advancements.nether.netherite_armor.title": "Cover Me in Debris", + "advancements.nether.obtain_ancient_debris.description": "Obtain Ancient Debris", + "advancements.nether.obtain_ancient_debris.title": "Hidden in the Depths", + "advancements.nether.obtain_blaze_rod.description": "Relieve a Blaze of its rod", + "advancements.nether.obtain_blaze_rod.title": "Into Fire", + "advancements.nether.obtain_crying_obsidian.description": "Obtain Crying Obsidian", + "advancements.nether.obtain_crying_obsidian.title": "Who is Cutting Onions?", + "advancements.nether.return_to_sender.description": "Destroy a Ghast with a fireball", + "advancements.nether.return_to_sender.title": "Return to Sender", + "advancements.nether.ride_strider_in_overworld_lava.description": "Take a Strider for a loooong ride on a lava lake in the Overworld", + "advancements.nether.ride_strider_in_overworld_lava.title": "Feels Like Home", + "advancements.nether.ride_strider.description": "Ride a Strider with a Warped Fungus on a Stick", + "advancements.nether.ride_strider.title": "This Boat Has Legs", + "advancements.nether.root.description": "Bring summer clothes", + "advancements.nether.root.title": "Nether", + "advancements.nether.summon_wither.description": "Summon the Wither", + "advancements.nether.summon_wither.title": "Withering Heights", + "advancements.nether.uneasy_alliance.description": "Rescue a Ghast from the Nether, bring it safely home to the Overworld... and then kill it", + "advancements.nether.uneasy_alliance.title": "Uneasy Alliance", + "advancements.nether.use_lodestone.description": "Use a Compass on a Lodestone", + "advancements.nether.use_lodestone.title": "Country Lode, Take Me Home", + "advancements.progress": "%s/%s", + "advancements.sad_label": ":(", + "advancements.story.cure_zombie_villager.description": "Weaken and then cure a Zombie Villager", + "advancements.story.cure_zombie_villager.title": "Zombie Doctor", + "advancements.story.deflect_arrow.description": "Deflect a projectile with a Shield", + "advancements.story.deflect_arrow.title": "Not Today, Thank You", + "advancements.story.enchant_item.description": "Enchant an item at an Enchanting Table", + "advancements.story.enchant_item.title": "Enchanter", + "advancements.story.enter_the_end.description": "Enter the End Portal", + "advancements.story.enter_the_end.title": "The End?", + "advancements.story.enter_the_nether.description": "Build, light and enter a Nether Portal", + "advancements.story.enter_the_nether.title": "We Need to Go Deeper", + "advancements.story.follow_ender_eye.description": "Follow an Eye of Ender", + "advancements.story.follow_ender_eye.title": "Eye Spy", + "advancements.story.form_obsidian.description": "Obtain a block of Obsidian", + "advancements.story.form_obsidian.title": "Ice Bucket Challenge", + "advancements.story.iron_tools.description": "Upgrade your Pickaxe", + "advancements.story.iron_tools.title": "Isn't It Iron Pick", + "advancements.story.lava_bucket.description": "Fill a Bucket with lava", + "advancements.story.lava_bucket.title": "Hot Stuff", + "advancements.story.mine_diamond.description": "Acquire diamonds", + "advancements.story.mine_diamond.title": "Diamonds!", + "advancements.story.mine_stone.description": "Mine Stone with your new Pickaxe", + "advancements.story.mine_stone.title": "Stone Age", + "advancements.story.obtain_armor.description": "Protect yourself with a piece of iron armor", + "advancements.story.obtain_armor.title": "Suit Up", + "advancements.story.root.description": "The heart and story of the game", + "advancements.story.root.title": "Minecraft", + "advancements.story.shiny_gear.description": "Diamond armor saves lives", + "advancements.story.shiny_gear.title": "Cover Me with Diamonds", + "advancements.story.smelt_iron.description": "Smelt an Iron Ingot", + "advancements.story.smelt_iron.title": "Acquire Hardware", + "advancements.story.upgrade_tools.description": "Construct a better Pickaxe", + "advancements.story.upgrade_tools.title": "Getting an Upgrade", + "advancements.toast.challenge": "Challenge Complete!", + "advancements.toast.goal": "Goal Reached!", + "advancements.toast.task": "Advancement Made!", + "advMode.allEntities": "Use \"@e\" to target all entities", + "advMode.allPlayers": "Use \"@a\" to target all players", + "advMode.command": "Console Command", + "advMode.mode": "Mode", + "advMode.mode.auto": "Repeat", + "advMode.mode.autoexec.bat": "Always Active", + "advMode.mode.conditional": "Conditional", + "advMode.mode.redstone": "Impulse", + "advMode.mode.redstoneTriggered": "Needs Redstone", + "advMode.mode.sequence": "Chain", + "advMode.mode.unconditional": "Unconditional", + "advMode.nearestPlayer": "Use \"@p\" to target nearest player", + "advMode.notAllowed": "Must be an opped player in creative mode", + "advMode.notEnabled": "Command blocks are not enabled on this server", + "advMode.previousOutput": "Previous Output", + "advMode.randomPlayer": "Use \"@r\" to target random player", + "advMode.self": "Use \"@s\" to target the executing entity", + "advMode.setCommand": "Set Console Command for Block", + "advMode.setCommand.success": "Command set: %s", + "advMode.trackOutput": "Track output", + "advMode.triggering": "Triggering", + "advMode.type": "Type", + "argument.anchor.invalid": "Invalid entity anchor position %s", + "argument.angle.incomplete": "Incomplete (expected 1 angle)", + "argument.angle.invalid": "Invalid angle", + "argument.block.id.invalid": "Unknown block type '%s'", + "argument.block.property.duplicate": "Property '%s' can only be set once for block %s", + "argument.block.property.invalid": "Block %s does not accept '%s' for %s property", + "argument.block.property.novalue": "Expected value for property '%s' on block %s", + "argument.block.property.unclosed": "Expected closing ] for block state properties", + "argument.block.property.unknown": "Block %s does not have property '%s'", + "argument.block.tag.disallowed": "Tags aren't allowed here, only actual blocks", + "argument.color.invalid": "Unknown color '%s'", + "argument.component.invalid": "Invalid chat component: %s", + "argument.criteria.invalid": "Unknown criterion '%s'", + "argument.dimension.invalid": "Unknown dimension '%s'", + "argument.double.big": "Double must not be more than %s, found %s", + "argument.double.low": "Double must not be less than %s, found %s", + "argument.entity.invalid": "Invalid name or UUID", + "argument.entity.notfound.entity": "No entity was found", + "argument.entity.notfound.player": "No player was found", + "argument.entity.options.advancements.description": "Players with advancements", + "argument.entity.options.distance.description": "Distance to entity", + "argument.entity.options.distance.negative": "Distance cannot be negative", + "argument.entity.options.dx.description": "Entities between x and x + dx", + "argument.entity.options.dy.description": "Entities between y and y + dy", + "argument.entity.options.dz.description": "Entities between z and z + dz", + "argument.entity.options.gamemode.description": "Players with game mode", + "argument.entity.options.inapplicable": "Option '%s' isn't applicable here", + "argument.entity.options.level.description": "Experience level", + "argument.entity.options.level.negative": "Level shouldn't be negative", + "argument.entity.options.limit.description": "Maximum number of entities to return", + "argument.entity.options.limit.toosmall": "Limit must be at least 1", + "argument.entity.options.mode.invalid": "Invalid or unknown game mode '%s'", + "argument.entity.options.name.description": "Entity name", + "argument.entity.options.nbt.description": "Entities with NBT", + "argument.entity.options.predicate.description": "Custom predicate", + "argument.entity.options.scores.description": "Entities with scores", + "argument.entity.options.sort.description": "Sort the entities", + "argument.entity.options.sort.irreversible": "Invalid or unknown sort type '%s'", + "argument.entity.options.tag.description": "Entities with tag", + "argument.entity.options.team.description": "Entities on team", + "argument.entity.options.type.description": "Entities of type", + "argument.entity.options.type.invalid": "Invalid or unknown entity type '%s'", + "argument.entity.options.unknown": "Unknown option '%s'", + "argument.entity.options.unterminated": "Expected end of options", + "argument.entity.options.valueless": "Expected value for option '%s'", + "argument.entity.options.x_rotation.description": "Entity's x rotation", + "argument.entity.options.x.description": "x position", + "argument.entity.options.y_rotation.description": "Entity's y rotation", + "argument.entity.options.y.description": "y position", + "argument.entity.options.z.description": "z position", + "argument.entity.selector.allEntities": "All entities", + "argument.entity.selector.allPlayers": "All players", + "argument.entity.selector.missing": "Missing selector type", + "argument.entity.selector.nearestEntity": "Nearest entity", + "argument.entity.selector.nearestPlayer": "Nearest player", + "argument.entity.selector.not_allowed": "Selector not allowed", + "argument.entity.selector.randomPlayer": "Random player", + "argument.entity.selector.self": "Current entity", + "argument.entity.selector.unknown": "Unknown selector type '%s'", + "argument.entity.toomany": "Only one entity is allowed, but the provided selector allows more than one", + "argument.enum.invalid": "Invalid value \"%s\"", + "argument.float.big": "Float must not be more than %s, found %s", + "argument.float.low": "Float must not be less than %s, found %s", + "argument.gamemode.invalid": "Unknown game mode: %s", + "argument.id.invalid": "Invalid ID", + "argument.id.unknown": "Unknown ID: %s", + "argument.integer.big": "Integer must not be more than %s, found %s", + "argument.integer.low": "Integer must not be less than %s, found %s", + "argument.item.id.invalid": "Unknown item '%s'", + "argument.item.tag.disallowed": "Tags aren't allowed here, only actual items", + "argument.literal.incorrect": "Expected literal %s", + "argument.long.big": "Long must not be more than %s, found %s", + "argument.long.low": "Long must not be less than %s, found %s", + "argument.message.too_long": "Chat message was too long (%s > maximum %s characters)", + "argument.nbt.array.invalid": "Invalid array type '%s'", + "argument.nbt.array.mixed": "Can't insert %s into %s", + "argument.nbt.expected.key": "Expected key", + "argument.nbt.expected.value": "Expected value", + "argument.nbt.list.mixed": "Can't insert %s into list of %s", + "argument.nbt.trailing": "Unexpected trailing data", + "argument.player.entities": "Only players may be affected by this command, but the provided selector includes entities", + "argument.player.toomany": "Only one player is allowed, but the provided selector allows more than one", + "argument.player.unknown": "That player does not exist", + "argument.pos.missing.double": "Expected a coordinate", + "argument.pos.missing.int": "Expected a block position", + "argument.pos.mixed": "Cannot mix world & local coordinates (everything must either use ^ or not)", + "argument.pos.outofbounds": "That position is outside the allowed boundaries.", + "argument.pos.outofworld": "That position is out of this world!", + "argument.pos.unloaded": "That position is not loaded", + "argument.pos2d.incomplete": "Incomplete (expected 2 coordinates)", + "argument.pos3d.incomplete": "Incomplete (expected 3 coordinates)", + "argument.range.empty": "Expected value or range of values", + "argument.range.ints": "Only whole numbers allowed, not decimals", + "argument.range.swapped": "Min cannot be bigger than max", + "argument.resource_or_id.failed_to_parse": "Failed to parse structure: %s", + "argument.resource_or_id.invalid": "Invalid id or tag", + "argument.resource_tag.invalid_type": "Tag '%s' has wrong type '%s' (expected '%s')", + "argument.resource_tag.not_found": "Can't find tag '%s' of type '%s'", + "argument.resource.invalid_type": "Element '%s' has wrong type '%s' (expected '%s')", + "argument.resource.not_found": "Can't find element '%s' of type '%s'", + "argument.rotation.incomplete": "Incomplete (expected 2 coordinates)", + "argument.scoreboardDisplaySlot.invalid": "Unknown display slot '%s'", + "argument.scoreHolder.empty": "No relevant score holders could be found", + "argument.style.invalid": "Invalid style: %s", + "argument.time.invalid_tick_count": "The tick count must be non-negative", + "argument.time.invalid_unit": "Invalid unit", + "argument.time.tick_count_too_low": "The tick count must not be less than %s, found %s", + "argument.uuid.invalid": "Invalid UUID", + "arguments.block.tag.unknown": "Unknown block tag '%s'", + "arguments.function.tag.unknown": "Unknown function tag '%s'", + "arguments.function.unknown": "Unknown function %s", + "arguments.item.component.expected": "Expected item component", + "arguments.item.component.malformed": "Malformed '%s' component: '%s'", + "arguments.item.component.repeated": "Item component '%s' was repeated, but only one value can be specified", + "arguments.item.component.unknown": "Unknown item component '%s'", + "arguments.item.malformed": "Malformed item: '%s'", + "arguments.item.overstacked": "%s can only stack up to %s", + "arguments.item.predicate.malformed": "Malformed '%s' predicate: '%s'", + "arguments.item.predicate.unknown": "Unknown item predicate '%s'", + "arguments.item.tag.unknown": "Unknown item tag '%s'", + "arguments.nbtpath.node.invalid": "Invalid NBT path element", + "arguments.nbtpath.nothing_found": "Found no elements matching %s", + "arguments.nbtpath.too_deep": "Resulting NBT too deeply nested", + "arguments.nbtpath.too_large": "Resulting NBT too large", + "arguments.objective.notFound": "Unknown scoreboard objective '%s'", + "arguments.objective.readonly": "Scoreboard objective '%s' is read-only", + "arguments.operation.div0": "Cannot divide by zero", + "arguments.operation.invalid": "Invalid operation", + "arguments.swizzle.invalid": "Invalid swizzle, expected combination of 'x', 'y' and 'z'", + "attribute.modifier.equals.0": "%s %s", + "attribute.modifier.equals.1": "%s%% %s", + "attribute.modifier.equals.2": "%s%% %s", + "attribute.modifier.plus.0": "+%s %s", + "attribute.modifier.plus.1": "+%s%% %s", + "attribute.modifier.plus.2": "+%s%% %s", + "attribute.modifier.take.0": "-%s %s", + "attribute.modifier.take.1": "-%s%% %s", + "attribute.modifier.take.2": "-%s%% %s", + "attribute.name.generic.armor": "Armor", + "attribute.name.generic.armor_toughness": "Armor Toughness", + "attribute.name.generic.attack_damage": "Attack Damage", + "attribute.name.generic.attack_knockback": "Attack Knockback", + "attribute.name.generic.attack_speed": "Attack Speed", + "attribute.name.generic.block_interaction_range": "Block Interaction Range", + "attribute.name.generic.burning_time": "Burning Time", + "attribute.name.generic.entity_interaction_range": "Entity Interaction Range", + "attribute.name.generic.explosion_knockback_resistance": "Explosion Knockback Resistance", + "attribute.name.generic.fall_damage_multiplier": "Fall Damage Multiplier", + "attribute.name.generic.flying_speed": "Flying Speed", + "attribute.name.generic.follow_range": "Mob Follow Range", + "attribute.name.generic.gravity": "Gravity", + "attribute.name.generic.jump_strength": "Jump Strength", + "attribute.name.generic.knockback_resistance": "Knockback Resistance", + "attribute.name.generic.luck": "Luck", + "attribute.name.generic.max_absorption": "Max Absorption", + "attribute.name.generic.max_health": "Max Health", + "attribute.name.generic.movement_efficiency": "Movement Efficiency", + "attribute.name.generic.movement_speed": "Speed", + "attribute.name.generic.oxygen_bonus": "Oxygen Bonus", + "attribute.name.generic.safe_fall_distance": "Safe Fall Distance", + "attribute.name.generic.scale": "Scale", + "attribute.name.generic.step_height": "Step Height", + "attribute.name.generic.water_movement_efficiency": "Water Movement Efficiency", + "attribute.name.horse.jump_strength": "Horse Jump Strength", + "attribute.name.player.block_break_speed": "Block Break Speed", + "attribute.name.player.block_interaction_range": "Block Interaction Range", + "attribute.name.player.entity_interaction_range": "Entity Interaction Range", + "attribute.name.player.mining_efficiency": "Mining Efficiency", + "attribute.name.player.sneaking_speed": "Sneaking Speed", + "attribute.name.player.submerged_mining_speed": "Submerged Mining Speed", + "attribute.name.player.sweeping_damage_ratio": "Sweeping Damage Ratio", + "attribute.name.zombie.spawn_reinforcements": "Zombie Reinforcements", + "biome.minecraft.badlands": "Badlands", + "biome.minecraft.bamboo_jungle": "Bamboo Jungle", + "biome.minecraft.basalt_deltas": "Basalt Deltas", + "biome.minecraft.beach": "Beach", + "biome.minecraft.birch_forest": "Birch Forest", + "biome.minecraft.cherry_grove": "Cherry Grove", + "biome.minecraft.cold_ocean": "Cold Ocean", + "biome.minecraft.crimson_forest": "Crimson Forest", + "biome.minecraft.dark_forest": "Dark Forest", + "biome.minecraft.deep_cold_ocean": "Deep Cold Ocean", + "biome.minecraft.deep_dark": "Deep Dark", + "biome.minecraft.deep_frozen_ocean": "Deep Frozen Ocean", + "biome.minecraft.deep_lukewarm_ocean": "Deep Lukewarm Ocean", + "biome.minecraft.deep_ocean": "Deep Ocean", + "biome.minecraft.desert": "Desert", + "biome.minecraft.dripstone_caves": "Dripstone Caves", + "biome.minecraft.end_barrens": "End Barrens", + "biome.minecraft.end_highlands": "End Highlands", + "biome.minecraft.end_midlands": "End Midlands", + "biome.minecraft.eroded_badlands": "Eroded Badlands", + "biome.minecraft.flower_forest": "Flower Forest", + "biome.minecraft.forest": "Forest", + "biome.minecraft.frozen_ocean": "Frozen Ocean", + "biome.minecraft.frozen_peaks": "Frozen Peaks", + "biome.minecraft.frozen_river": "Frozen River", + "biome.minecraft.grove": "Grove", + "biome.minecraft.ice_spikes": "Ice Spikes", + "biome.minecraft.jagged_peaks": "Jagged Peaks", + "biome.minecraft.jungle": "Jungle", + "biome.minecraft.lukewarm_ocean": "Lukewarm Ocean", + "biome.minecraft.lush_caves": "Lush Caves", + "biome.minecraft.mangrove_swamp": "Mangrove Swamp", + "biome.minecraft.meadow": "Meadow", + "biome.minecraft.mushroom_fields": "Mushroom Fields", + "biome.minecraft.nether_wastes": "Nether Wastes", + "biome.minecraft.ocean": "Ocean", + "biome.minecraft.old_growth_birch_forest": "Old Growth Birch Forest", + "biome.minecraft.old_growth_pine_taiga": "Old Growth Pine Taiga", + "biome.minecraft.old_growth_spruce_taiga": "Old Growth Spruce Taiga", + "biome.minecraft.plains": "Plains", + "biome.minecraft.river": "River", + "biome.minecraft.savanna": "Savanna", + "biome.minecraft.savanna_plateau": "Savanna Plateau", + "biome.minecraft.small_end_islands": "Small End Islands", + "biome.minecraft.snowy_beach": "Snowy Beach", + "biome.minecraft.snowy_plains": "Snowy Plains", + "biome.minecraft.snowy_slopes": "Snowy Slopes", + "biome.minecraft.snowy_taiga": "Snowy Taiga", + "biome.minecraft.soul_sand_valley": "Soul Sand Valley", + "biome.minecraft.sparse_jungle": "Sparse Jungle", + "biome.minecraft.stony_peaks": "Stony Peaks", + "biome.minecraft.stony_shore": "Stony Shore", + "biome.minecraft.sunflower_plains": "Sunflower Plains", + "biome.minecraft.swamp": "Swamp", + "biome.minecraft.taiga": "Taiga", + "biome.minecraft.the_end": "The End", + "biome.minecraft.the_void": "The Void", + "biome.minecraft.warm_ocean": "Warm Ocean", + "biome.minecraft.warped_forest": "Warped Forest", + "biome.minecraft.windswept_forest": "Windswept Forest", + "biome.minecraft.windswept_gravelly_hills": "Windswept Gravelly Hills", + "biome.minecraft.windswept_hills": "Windswept Hills", + "biome.minecraft.windswept_savanna": "Windswept Savanna", + "biome.minecraft.wooded_badlands": "Wooded Badlands", + "block.minecraft.acacia_button": "Acacia Button", + "block.minecraft.acacia_door": "Acacia Door", + "block.minecraft.acacia_fence": "Acacia Fence", + "block.minecraft.acacia_fence_gate": "Acacia Fence Gate", + "block.minecraft.acacia_hanging_sign": "Acacia Hanging Sign", + "block.minecraft.acacia_leaves": "Acacia Leaves", + "block.minecraft.acacia_log": "Acacia Log", + "block.minecraft.acacia_planks": "Acacia Planks", + "block.minecraft.acacia_pressure_plate": "Acacia Pressure Plate", + "block.minecraft.acacia_sapling": "Acacia Sapling", + "block.minecraft.acacia_sign": "Acacia Sign", + "block.minecraft.acacia_slab": "Acacia Slab", + "block.minecraft.acacia_stairs": "Acacia Stairs", + "block.minecraft.acacia_trapdoor": "Acacia Trapdoor", + "block.minecraft.acacia_wall_hanging_sign": "Acacia Wall Hanging Sign", + "block.minecraft.acacia_wall_sign": "Acacia Wall Sign", + "block.minecraft.acacia_wood": "Acacia Wood", + "block.minecraft.activator_rail": "Activator Rail", + "block.minecraft.air": "Air", + "block.minecraft.allium": "Allium", + "block.minecraft.amethyst_block": "Block of Amethyst", + "block.minecraft.amethyst_cluster": "Amethyst Cluster", + "block.minecraft.ancient_debris": "Ancient Debris", + "block.minecraft.andesite": "Andesite", + "block.minecraft.andesite_slab": "Andesite Slab", + "block.minecraft.andesite_stairs": "Andesite Stairs", + "block.minecraft.andesite_wall": "Andesite Wall", + "block.minecraft.anvil": "Anvil", + "block.minecraft.attached_melon_stem": "Attached Melon Stem", + "block.minecraft.attached_pumpkin_stem": "Attached Pumpkin Stem", + "block.minecraft.azalea": "Azalea", + "block.minecraft.azalea_leaves": "Azalea Leaves", + "block.minecraft.azure_bluet": "Azure Bluet", + "block.minecraft.bamboo": "Bamboo", + "block.minecraft.bamboo_block": "Block of Bamboo", + "block.minecraft.bamboo_button": "Bamboo Button", + "block.minecraft.bamboo_door": "Bamboo Door", + "block.minecraft.bamboo_fence": "Bamboo Fence", + "block.minecraft.bamboo_fence_gate": "Bamboo Fence Gate", + "block.minecraft.bamboo_hanging_sign": "Bamboo Hanging Sign", + "block.minecraft.bamboo_mosaic": "Bamboo Mosaic", + "block.minecraft.bamboo_mosaic_slab": "Bamboo Mosaic Slab", + "block.minecraft.bamboo_mosaic_stairs": "Bamboo Mosaic Stairs", + "block.minecraft.bamboo_planks": "Bamboo Planks", + "block.minecraft.bamboo_pressure_plate": "Bamboo Pressure Plate", + "block.minecraft.bamboo_sapling": "Bamboo Shoot", + "block.minecraft.bamboo_sign": "Bamboo Sign", + "block.minecraft.bamboo_slab": "Bamboo Slab", + "block.minecraft.bamboo_stairs": "Bamboo Stairs", + "block.minecraft.bamboo_trapdoor": "Bamboo Trapdoor", + "block.minecraft.bamboo_wall_hanging_sign": "Bamboo Wall Hanging Sign", + "block.minecraft.bamboo_wall_sign": "Bamboo Wall Sign", + "block.minecraft.banner.base.black": "Fully Black Field", + "block.minecraft.banner.base.blue": "Fully Blue Field", + "block.minecraft.banner.base.brown": "Fully Brown Field", + "block.minecraft.banner.base.cyan": "Fully Cyan Field", + "block.minecraft.banner.base.gray": "Fully Gray Field", + "block.minecraft.banner.base.green": "Fully Green Field", + "block.minecraft.banner.base.light_blue": "Fully Light Blue Field", + "block.minecraft.banner.base.light_gray": "Fully Light Gray Field", + "block.minecraft.banner.base.lime": "Fully Lime Field", + "block.minecraft.banner.base.magenta": "Fully Magenta Field", + "block.minecraft.banner.base.orange": "Fully Orange Field", + "block.minecraft.banner.base.pink": "Fully Pink Field", + "block.minecraft.banner.base.purple": "Fully Purple Field", + "block.minecraft.banner.base.red": "Fully Red Field", + "block.minecraft.banner.base.white": "Fully White Field", + "block.minecraft.banner.base.yellow": "Fully Yellow Field", + "block.minecraft.banner.border.black": "Black Bordure", + "block.minecraft.banner.border.blue": "Blue Bordure", + "block.minecraft.banner.border.brown": "Brown Bordure", + "block.minecraft.banner.border.cyan": "Cyan Bordure", + "block.minecraft.banner.border.gray": "Gray Bordure", + "block.minecraft.banner.border.green": "Green Bordure", + "block.minecraft.banner.border.light_blue": "Light Blue Bordure", + "block.minecraft.banner.border.light_gray": "Light Gray Bordure", + "block.minecraft.banner.border.lime": "Lime Bordure", + "block.minecraft.banner.border.magenta": "Magenta Bordure", + "block.minecraft.banner.border.orange": "Orange Bordure", + "block.minecraft.banner.border.pink": "Pink Bordure", + "block.minecraft.banner.border.purple": "Purple Bordure", + "block.minecraft.banner.border.red": "Red Bordure", + "block.minecraft.banner.border.white": "White Bordure", + "block.minecraft.banner.border.yellow": "Yellow Bordure", + "block.minecraft.banner.bricks.black": "Black Field Masoned", + "block.minecraft.banner.bricks.blue": "Blue Field Masoned", + "block.minecraft.banner.bricks.brown": "Brown Field Masoned", + "block.minecraft.banner.bricks.cyan": "Cyan Field Masoned", + "block.minecraft.banner.bricks.gray": "Gray Field Masoned", + "block.minecraft.banner.bricks.green": "Green Field Masoned", + "block.minecraft.banner.bricks.light_blue": "Light Blue Field Masoned", + "block.minecraft.banner.bricks.light_gray": "Light Gray Field Masoned", + "block.minecraft.banner.bricks.lime": "Lime Field Masoned", + "block.minecraft.banner.bricks.magenta": "Magenta Field Masoned", + "block.minecraft.banner.bricks.orange": "Orange Field Masoned", + "block.minecraft.banner.bricks.pink": "Pink Field Masoned", + "block.minecraft.banner.bricks.purple": "Purple Field Masoned", + "block.minecraft.banner.bricks.red": "Red Field Masoned", + "block.minecraft.banner.bricks.white": "White Field Masoned", + "block.minecraft.banner.bricks.yellow": "Yellow Field Masoned", + "block.minecraft.banner.circle.black": "Black Roundel", + "block.minecraft.banner.circle.blue": "Blue Roundel", + "block.minecraft.banner.circle.brown": "Brown Roundel", + "block.minecraft.banner.circle.cyan": "Cyan Roundel", + "block.minecraft.banner.circle.gray": "Gray Roundel", + "block.minecraft.banner.circle.green": "Green Roundel", + "block.minecraft.banner.circle.light_blue": "Light Blue Roundel", + "block.minecraft.banner.circle.light_gray": "Light Gray Roundel", + "block.minecraft.banner.circle.lime": "Lime Roundel", + "block.minecraft.banner.circle.magenta": "Magenta Roundel", + "block.minecraft.banner.circle.orange": "Orange Roundel", + "block.minecraft.banner.circle.pink": "Pink Roundel", + "block.minecraft.banner.circle.purple": "Purple Roundel", + "block.minecraft.banner.circle.red": "Red Roundel", + "block.minecraft.banner.circle.white": "White Roundel", + "block.minecraft.banner.circle.yellow": "Yellow Roundel", + "block.minecraft.banner.creeper.black": "Black Creeper Charge", + "block.minecraft.banner.creeper.blue": "Blue Creeper Charge", + "block.minecraft.banner.creeper.brown": "Brown Creeper Charge", + "block.minecraft.banner.creeper.cyan": "Cyan Creeper Charge", + "block.minecraft.banner.creeper.gray": "Gray Creeper Charge", + "block.minecraft.banner.creeper.green": "Green Creeper Charge", + "block.minecraft.banner.creeper.light_blue": "Light Blue Creeper Charge", + "block.minecraft.banner.creeper.light_gray": "Light Gray Creeper Charge", + "block.minecraft.banner.creeper.lime": "Lime Creeper Charge", + "block.minecraft.banner.creeper.magenta": "Magenta Creeper Charge", + "block.minecraft.banner.creeper.orange": "Orange Creeper Charge", + "block.minecraft.banner.creeper.pink": "Pink Creeper Charge", + "block.minecraft.banner.creeper.purple": "Purple Creeper Charge", + "block.minecraft.banner.creeper.red": "Red Creeper Charge", + "block.minecraft.banner.creeper.white": "White Creeper Charge", + "block.minecraft.banner.creeper.yellow": "Yellow Creeper Charge", + "block.minecraft.banner.cross.black": "Black Saltire", + "block.minecraft.banner.cross.blue": "Blue Saltire", + "block.minecraft.banner.cross.brown": "Brown Saltire", + "block.minecraft.banner.cross.cyan": "Cyan Saltire", + "block.minecraft.banner.cross.gray": "Gray Saltire", + "block.minecraft.banner.cross.green": "Green Saltire", + "block.minecraft.banner.cross.light_blue": "Light Blue Saltire", + "block.minecraft.banner.cross.light_gray": "Light Gray Saltire", + "block.minecraft.banner.cross.lime": "Lime Saltire", + "block.minecraft.banner.cross.magenta": "Magenta Saltire", + "block.minecraft.banner.cross.orange": "Orange Saltire", + "block.minecraft.banner.cross.pink": "Pink Saltire", + "block.minecraft.banner.cross.purple": "Purple Saltire", + "block.minecraft.banner.cross.red": "Red Saltire", + "block.minecraft.banner.cross.white": "White Saltire", + "block.minecraft.banner.cross.yellow": "Yellow Saltire", + "block.minecraft.banner.curly_border.black": "Black Bordure Indented", + "block.minecraft.banner.curly_border.blue": "Blue Bordure Indented", + "block.minecraft.banner.curly_border.brown": "Brown Bordure Indented", + "block.minecraft.banner.curly_border.cyan": "Cyan Bordure Indented", + "block.minecraft.banner.curly_border.gray": "Gray Bordure Indented", + "block.minecraft.banner.curly_border.green": "Green Bordure Indented", + "block.minecraft.banner.curly_border.light_blue": "Light Blue Bordure Indented", + "block.minecraft.banner.curly_border.light_gray": "Light Gray Bordure Indented", + "block.minecraft.banner.curly_border.lime": "Lime Bordure Indented", + "block.minecraft.banner.curly_border.magenta": "Magenta Bordure Indented", + "block.minecraft.banner.curly_border.orange": "Orange Bordure Indented", + "block.minecraft.banner.curly_border.pink": "Pink Bordure Indented", + "block.minecraft.banner.curly_border.purple": "Purple Bordure Indented", + "block.minecraft.banner.curly_border.red": "Red Bordure Indented", + "block.minecraft.banner.curly_border.white": "White Bordure Indented", + "block.minecraft.banner.curly_border.yellow": "Yellow Bordure Indented", + "block.minecraft.banner.diagonal_left.black": "Black Per Bend Sinister", + "block.minecraft.banner.diagonal_left.blue": "Blue Per Bend Sinister", + "block.minecraft.banner.diagonal_left.brown": "Brown Per Bend Sinister", + "block.minecraft.banner.diagonal_left.cyan": "Cyan Per Bend Sinister", + "block.minecraft.banner.diagonal_left.gray": "Gray Per Bend Sinister", + "block.minecraft.banner.diagonal_left.green": "Green Per Bend Sinister", + "block.minecraft.banner.diagonal_left.light_blue": "Light Blue Per Bend Sinister", + "block.minecraft.banner.diagonal_left.light_gray": "Light Gray Per Bend Sinister", + "block.minecraft.banner.diagonal_left.lime": "Lime Per Bend Sinister", + "block.minecraft.banner.diagonal_left.magenta": "Magenta Per Bend Sinister", + "block.minecraft.banner.diagonal_left.orange": "Orange Per Bend Sinister", + "block.minecraft.banner.diagonal_left.pink": "Pink Per Bend Sinister", + "block.minecraft.banner.diagonal_left.purple": "Purple Per Bend Sinister", + "block.minecraft.banner.diagonal_left.red": "Red Per Bend Sinister", + "block.minecraft.banner.diagonal_left.white": "White Per Bend Sinister", + "block.minecraft.banner.diagonal_left.yellow": "Yellow Per Bend Sinister", + "block.minecraft.banner.diagonal_right.black": "Black Per Bend", + "block.minecraft.banner.diagonal_right.blue": "Blue Per Bend", + "block.minecraft.banner.diagonal_right.brown": "Brown Per Bend", + "block.minecraft.banner.diagonal_right.cyan": "Cyan Per Bend", + "block.minecraft.banner.diagonal_right.gray": "Gray Per Bend", + "block.minecraft.banner.diagonal_right.green": "Green Per Bend", + "block.minecraft.banner.diagonal_right.light_blue": "Light Blue Per Bend", + "block.minecraft.banner.diagonal_right.light_gray": "Light Gray Per Bend", + "block.minecraft.banner.diagonal_right.lime": "Lime Per Bend", + "block.minecraft.banner.diagonal_right.magenta": "Magenta Per Bend", + "block.minecraft.banner.diagonal_right.orange": "Orange Per Bend", + "block.minecraft.banner.diagonal_right.pink": "Pink Per Bend", + "block.minecraft.banner.diagonal_right.purple": "Purple Per Bend", + "block.minecraft.banner.diagonal_right.red": "Red Per Bend", + "block.minecraft.banner.diagonal_right.white": "White Per Bend", + "block.minecraft.banner.diagonal_right.yellow": "Yellow Per Bend", + "block.minecraft.banner.diagonal_up_left.black": "Black Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.blue": "Blue Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.brown": "Brown Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.cyan": "Cyan Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.gray": "Gray Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.green": "Green Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.light_blue": "Light Blue Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.light_gray": "Light Gray Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.lime": "Lime Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.magenta": "Magenta Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.orange": "Orange Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.pink": "Pink Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.purple": "Purple Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.red": "Red Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.white": "White Per Bend Inverted", + "block.minecraft.banner.diagonal_up_left.yellow": "Yellow Per Bend Inverted", + "block.minecraft.banner.diagonal_up_right.black": "Black Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.blue": "Blue Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.brown": "Brown Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.cyan": "Cyan Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.gray": "Gray Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.green": "Green Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.light_blue": "Light Blue Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.light_gray": "Light Gray Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.lime": "Lime Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.magenta": "Magenta Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.orange": "Orange Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.pink": "Pink Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.purple": "Purple Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.red": "Red Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.white": "White Per Bend Sinister Inverted", + "block.minecraft.banner.diagonal_up_right.yellow": "Yellow Per Bend Sinister Inverted", + "block.minecraft.banner.flow.black": "Black Flow", + "block.minecraft.banner.flow.blue": "Blue Flow", + "block.minecraft.banner.flow.brown": "Brown Flow", + "block.minecraft.banner.flow.cyan": "Cyan Flow", + "block.minecraft.banner.flow.gray": "Gray Flow", + "block.minecraft.banner.flow.green": "Green Flow", + "block.minecraft.banner.flow.light_blue": "Light Blue Flow", + "block.minecraft.banner.flow.light_gray": "Light Gray Flow", + "block.minecraft.banner.flow.lime": "Lime Flow", + "block.minecraft.banner.flow.magenta": "Magenta Flow", + "block.minecraft.banner.flow.orange": "Orange Flow", + "block.minecraft.banner.flow.pink": "Pink Flow", + "block.minecraft.banner.flow.purple": "Purple Flow", + "block.minecraft.banner.flow.red": "Red Flow", + "block.minecraft.banner.flow.white": "White Flow", + "block.minecraft.banner.flow.yellow": "Yellow Flow", + "block.minecraft.banner.flower.black": "Black Flower Charge", + "block.minecraft.banner.flower.blue": "Blue Flower Charge", + "block.minecraft.banner.flower.brown": "Brown Flower Charge", + "block.minecraft.banner.flower.cyan": "Cyan Flower Charge", + "block.minecraft.banner.flower.gray": "Gray Flower Charge", + "block.minecraft.banner.flower.green": "Green Flower Charge", + "block.minecraft.banner.flower.light_blue": "Light Blue Flower Charge", + "block.minecraft.banner.flower.light_gray": "Light Gray Flower Charge", + "block.minecraft.banner.flower.lime": "Lime Flower Charge", + "block.minecraft.banner.flower.magenta": "Magenta Flower Charge", + "block.minecraft.banner.flower.orange": "Orange Flower Charge", + "block.minecraft.banner.flower.pink": "Pink Flower Charge", + "block.minecraft.banner.flower.purple": "Purple Flower Charge", + "block.minecraft.banner.flower.red": "Red Flower Charge", + "block.minecraft.banner.flower.white": "White Flower Charge", + "block.minecraft.banner.flower.yellow": "Yellow Flower Charge", + "block.minecraft.banner.globe.black": "Black Globe", + "block.minecraft.banner.globe.blue": "Blue Globe", + "block.minecraft.banner.globe.brown": "Brown Globe", + "block.minecraft.banner.globe.cyan": "Cyan Globe", + "block.minecraft.banner.globe.gray": "Gray Globe", + "block.minecraft.banner.globe.green": "Green Globe", + "block.minecraft.banner.globe.light_blue": "Light Blue Globe", + "block.minecraft.banner.globe.light_gray": "Light Gray Globe", + "block.minecraft.banner.globe.lime": "Lime Globe", + "block.minecraft.banner.globe.magenta": "Magenta Globe", + "block.minecraft.banner.globe.orange": "Orange Globe", + "block.minecraft.banner.globe.pink": "Pink Globe", + "block.minecraft.banner.globe.purple": "Purple Globe", + "block.minecraft.banner.globe.red": "Red Globe", + "block.minecraft.banner.globe.white": "White Globe", + "block.minecraft.banner.globe.yellow": "Yellow Globe", + "block.minecraft.banner.gradient_up.black": "Black Base Gradient", + "block.minecraft.banner.gradient_up.blue": "Blue Base Gradient", + "block.minecraft.banner.gradient_up.brown": "Brown Base Gradient", + "block.minecraft.banner.gradient_up.cyan": "Cyan Base Gradient", + "block.minecraft.banner.gradient_up.gray": "Gray Base Gradient", + "block.minecraft.banner.gradient_up.green": "Green Base Gradient", + "block.minecraft.banner.gradient_up.light_blue": "Light Blue Base Gradient", + "block.minecraft.banner.gradient_up.light_gray": "Light Gray Base Gradient", + "block.minecraft.banner.gradient_up.lime": "Lime Base Gradient", + "block.minecraft.banner.gradient_up.magenta": "Magenta Base Gradient", + "block.minecraft.banner.gradient_up.orange": "Orange Base Gradient", + "block.minecraft.banner.gradient_up.pink": "Pink Base Gradient", + "block.minecraft.banner.gradient_up.purple": "Purple Base Gradient", + "block.minecraft.banner.gradient_up.red": "Red Base Gradient", + "block.minecraft.banner.gradient_up.white": "White Base Gradient", + "block.minecraft.banner.gradient_up.yellow": "Yellow Base Gradient", + "block.minecraft.banner.gradient.black": "Black Gradient", + "block.minecraft.banner.gradient.blue": "Blue Gradient", + "block.minecraft.banner.gradient.brown": "Brown Gradient", + "block.minecraft.banner.gradient.cyan": "Cyan Gradient", + "block.minecraft.banner.gradient.gray": "Gray Gradient", + "block.minecraft.banner.gradient.green": "Green Gradient", + "block.minecraft.banner.gradient.light_blue": "Light Blue Gradient", + "block.minecraft.banner.gradient.light_gray": "Light Gray Gradient", + "block.minecraft.banner.gradient.lime": "Lime Gradient", + "block.minecraft.banner.gradient.magenta": "Magenta Gradient", + "block.minecraft.banner.gradient.orange": "Orange Gradient", + "block.minecraft.banner.gradient.pink": "Pink Gradient", + "block.minecraft.banner.gradient.purple": "Purple Gradient", + "block.minecraft.banner.gradient.red": "Red Gradient", + "block.minecraft.banner.gradient.white": "White Gradient", + "block.minecraft.banner.gradient.yellow": "Yellow Gradient", + "block.minecraft.banner.guster.black": "Black Guster", + "block.minecraft.banner.guster.blue": "Blue Guster", + "block.minecraft.banner.guster.brown": "Brown Guster", + "block.minecraft.banner.guster.cyan": "Cyan Guster", + "block.minecraft.banner.guster.gray": "Gray Guster", + "block.minecraft.banner.guster.green": "Green Guster", + "block.minecraft.banner.guster.light_blue": "Light Blue Guster", + "block.minecraft.banner.guster.light_gray": "Light Gray Guster", + "block.minecraft.banner.guster.lime": "Lime Guster", + "block.minecraft.banner.guster.magenta": "Magenta Guster", + "block.minecraft.banner.guster.orange": "Orange Guster", + "block.minecraft.banner.guster.pink": "Pink Guster", + "block.minecraft.banner.guster.purple": "Purple Guster", + "block.minecraft.banner.guster.red": "Red Guster", + "block.minecraft.banner.guster.white": "White Guster", + "block.minecraft.banner.guster.yellow": "Yellow Guster", + "block.minecraft.banner.half_horizontal_bottom.black": "Black Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.blue": "Blue Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.brown": "Brown Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.cyan": "Cyan Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.gray": "Gray Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.green": "Green Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.light_blue": "Light Blue Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.light_gray": "Light Gray Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.lime": "Lime Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.magenta": "Magenta Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.orange": "Orange Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.pink": "Pink Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.purple": "Purple Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.red": "Red Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.white": "White Per Fess Inverted", + "block.minecraft.banner.half_horizontal_bottom.yellow": "Yellow Per Fess Inverted", + "block.minecraft.banner.half_horizontal.black": "Black Per Fess", + "block.minecraft.banner.half_horizontal.blue": "Blue Per Fess", + "block.minecraft.banner.half_horizontal.brown": "Brown Per Fess", + "block.minecraft.banner.half_horizontal.cyan": "Cyan Per Fess", + "block.minecraft.banner.half_horizontal.gray": "Gray Per Fess", + "block.minecraft.banner.half_horizontal.green": "Green Per Fess", + "block.minecraft.banner.half_horizontal.light_blue": "Light Blue Per Fess", + "block.minecraft.banner.half_horizontal.light_gray": "Light Gray Per Fess", + "block.minecraft.banner.half_horizontal.lime": "Lime Per Fess", + "block.minecraft.banner.half_horizontal.magenta": "Magenta Per Fess", + "block.minecraft.banner.half_horizontal.orange": "Orange Per Fess", + "block.minecraft.banner.half_horizontal.pink": "Pink Per Fess", + "block.minecraft.banner.half_horizontal.purple": "Purple Per Fess", + "block.minecraft.banner.half_horizontal.red": "Red Per Fess", + "block.minecraft.banner.half_horizontal.white": "White Per Fess", + "block.minecraft.banner.half_horizontal.yellow": "Yellow Per Fess", + "block.minecraft.banner.half_vertical_right.black": "Black Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.blue": "Blue Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.brown": "Brown Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.cyan": "Cyan Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.gray": "Gray Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.green": "Green Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.light_blue": "Light Blue Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.light_gray": "Light Gray Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.lime": "Lime Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.magenta": "Magenta Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.orange": "Orange Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.pink": "Pink Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.purple": "Purple Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.red": "Red Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.white": "White Per Pale Inverted", + "block.minecraft.banner.half_vertical_right.yellow": "Yellow Per Pale Inverted", + "block.minecraft.banner.half_vertical.black": "Black Per Pale", + "block.minecraft.banner.half_vertical.blue": "Blue Per Pale", + "block.minecraft.banner.half_vertical.brown": "Brown Per Pale", + "block.minecraft.banner.half_vertical.cyan": "Cyan Per Pale", + "block.minecraft.banner.half_vertical.gray": "Gray Per Pale", + "block.minecraft.banner.half_vertical.green": "Green Per Pale", + "block.minecraft.banner.half_vertical.light_blue": "Light Blue Per Pale", + "block.minecraft.banner.half_vertical.light_gray": "Light Gray Per Pale", + "block.minecraft.banner.half_vertical.lime": "Lime Per Pale", + "block.minecraft.banner.half_vertical.magenta": "Magenta Per Pale", + "block.minecraft.banner.half_vertical.orange": "Orange Per Pale", + "block.minecraft.banner.half_vertical.pink": "Pink Per Pale", + "block.minecraft.banner.half_vertical.purple": "Purple Per Pale", + "block.minecraft.banner.half_vertical.red": "Red Per Pale", + "block.minecraft.banner.half_vertical.white": "White Per Pale", + "block.minecraft.banner.half_vertical.yellow": "Yellow Per Pale", + "block.minecraft.banner.mojang.black": "Black Thing", + "block.minecraft.banner.mojang.blue": "Blue Thing", + "block.minecraft.banner.mojang.brown": "Brown Thing", + "block.minecraft.banner.mojang.cyan": "Cyan Thing", + "block.minecraft.banner.mojang.gray": "Gray Thing", + "block.minecraft.banner.mojang.green": "Green Thing", + "block.minecraft.banner.mojang.light_blue": "Light Blue Thing", + "block.minecraft.banner.mojang.light_gray": "Light Gray Thing", + "block.minecraft.banner.mojang.lime": "Lime Thing", + "block.minecraft.banner.mojang.magenta": "Magenta Thing", + "block.minecraft.banner.mojang.orange": "Orange Thing", + "block.minecraft.banner.mojang.pink": "Pink Thing", + "block.minecraft.banner.mojang.purple": "Purple Thing", + "block.minecraft.banner.mojang.red": "Red Thing", + "block.minecraft.banner.mojang.white": "White Thing", + "block.minecraft.banner.mojang.yellow": "Yellow Thing", + "block.minecraft.banner.piglin.black": "Black Snout", + "block.minecraft.banner.piglin.blue": "Blue Snout", + "block.minecraft.banner.piglin.brown": "Brown Snout", + "block.minecraft.banner.piglin.cyan": "Cyan Snout", + "block.minecraft.banner.piglin.gray": "Gray Snout", + "block.minecraft.banner.piglin.green": "Green Snout", + "block.minecraft.banner.piglin.light_blue": "Light Blue Snout", + "block.minecraft.banner.piglin.light_gray": "Light Gray Snout", + "block.minecraft.banner.piglin.lime": "Lime Snout", + "block.minecraft.banner.piglin.magenta": "Magenta Snout", + "block.minecraft.banner.piglin.orange": "Orange Snout", + "block.minecraft.banner.piglin.pink": "Pink Snout", + "block.minecraft.banner.piglin.purple": "Purple Snout", + "block.minecraft.banner.piglin.red": "Red Snout", + "block.minecraft.banner.piglin.white": "White Snout", + "block.minecraft.banner.piglin.yellow": "Yellow Snout", + "block.minecraft.banner.rhombus.black": "Black Lozenge", + "block.minecraft.banner.rhombus.blue": "Blue Lozenge", + "block.minecraft.banner.rhombus.brown": "Brown Lozenge", + "block.minecraft.banner.rhombus.cyan": "Cyan Lozenge", + "block.minecraft.banner.rhombus.gray": "Gray Lozenge", + "block.minecraft.banner.rhombus.green": "Green Lozenge", + "block.minecraft.banner.rhombus.light_blue": "Light Blue Lozenge", + "block.minecraft.banner.rhombus.light_gray": "Light Gray Lozenge", + "block.minecraft.banner.rhombus.lime": "Lime Lozenge", + "block.minecraft.banner.rhombus.magenta": "Magenta Lozenge", + "block.minecraft.banner.rhombus.orange": "Orange Lozenge", + "block.minecraft.banner.rhombus.pink": "Pink Lozenge", + "block.minecraft.banner.rhombus.purple": "Purple Lozenge", + "block.minecraft.banner.rhombus.red": "Red Lozenge", + "block.minecraft.banner.rhombus.white": "White Lozenge", + "block.minecraft.banner.rhombus.yellow": "Yellow Lozenge", + "block.minecraft.banner.skull.black": "Black Skull Charge", + "block.minecraft.banner.skull.blue": "Blue Skull Charge", + "block.minecraft.banner.skull.brown": "Brown Skull Charge", + "block.minecraft.banner.skull.cyan": "Cyan Skull Charge", + "block.minecraft.banner.skull.gray": "Gray Skull Charge", + "block.minecraft.banner.skull.green": "Green Skull Charge", + "block.minecraft.banner.skull.light_blue": "Light Blue Skull Charge", + "block.minecraft.banner.skull.light_gray": "Light Gray Skull Charge", + "block.minecraft.banner.skull.lime": "Lime Skull Charge", + "block.minecraft.banner.skull.magenta": "Magenta Skull Charge", + "block.minecraft.banner.skull.orange": "Orange Skull Charge", + "block.minecraft.banner.skull.pink": "Pink Skull Charge", + "block.minecraft.banner.skull.purple": "Purple Skull Charge", + "block.minecraft.banner.skull.red": "Red Skull Charge", + "block.minecraft.banner.skull.white": "White Skull Charge", + "block.minecraft.banner.skull.yellow": "Yellow Skull Charge", + "block.minecraft.banner.small_stripes.black": "Black Paly", + "block.minecraft.banner.small_stripes.blue": "Blue Paly", + "block.minecraft.banner.small_stripes.brown": "Brown Paly", + "block.minecraft.banner.small_stripes.cyan": "Cyan Paly", + "block.minecraft.banner.small_stripes.gray": "Gray Paly", + "block.minecraft.banner.small_stripes.green": "Green Paly", + "block.minecraft.banner.small_stripes.light_blue": "Light Blue Paly", + "block.minecraft.banner.small_stripes.light_gray": "Light Gray Paly", + "block.minecraft.banner.small_stripes.lime": "Lime Paly", + "block.minecraft.banner.small_stripes.magenta": "Magenta Paly", + "block.minecraft.banner.small_stripes.orange": "Orange Paly", + "block.minecraft.banner.small_stripes.pink": "Pink Paly", + "block.minecraft.banner.small_stripes.purple": "Purple Paly", + "block.minecraft.banner.small_stripes.red": "Red Paly", + "block.minecraft.banner.small_stripes.white": "White Paly", + "block.minecraft.banner.small_stripes.yellow": "Yellow Paly", + "block.minecraft.banner.square_bottom_left.black": "Black Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.blue": "Blue Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.brown": "Brown Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.cyan": "Cyan Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.gray": "Gray Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.green": "Green Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.light_blue": "Light Blue Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.light_gray": "Light Gray Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.lime": "Lime Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.magenta": "Magenta Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.orange": "Orange Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.pink": "Pink Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.purple": "Purple Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.red": "Red Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.white": "White Base Dexter Canton", + "block.minecraft.banner.square_bottom_left.yellow": "Yellow Base Dexter Canton", + "block.minecraft.banner.square_bottom_right.black": "Black Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.blue": "Blue Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.brown": "Brown Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.cyan": "Cyan Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.gray": "Gray Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.green": "Green Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.light_blue": "Light Blue Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.light_gray": "Light Gray Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.lime": "Lime Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.magenta": "Magenta Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.orange": "Orange Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.pink": "Pink Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.purple": "Purple Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.red": "Red Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.white": "White Base Sinister Canton", + "block.minecraft.banner.square_bottom_right.yellow": "Yellow Base Sinister Canton", + "block.minecraft.banner.square_top_left.black": "Black Chief Dexter Canton", + "block.minecraft.banner.square_top_left.blue": "Blue Chief Dexter Canton", + "block.minecraft.banner.square_top_left.brown": "Brown Chief Dexter Canton", + "block.minecraft.banner.square_top_left.cyan": "Cyan Chief Dexter Canton", + "block.minecraft.banner.square_top_left.gray": "Gray Chief Dexter Canton", + "block.minecraft.banner.square_top_left.green": "Green Chief Dexter Canton", + "block.minecraft.banner.square_top_left.light_blue": "Light Blue Chief Dexter Canton", + "block.minecraft.banner.square_top_left.light_gray": "Light Gray Chief Dexter Canton", + "block.minecraft.banner.square_top_left.lime": "Lime Chief Dexter Canton", + "block.minecraft.banner.square_top_left.magenta": "Magenta Chief Dexter Canton", + "block.minecraft.banner.square_top_left.orange": "Orange Chief Dexter Canton", + "block.minecraft.banner.square_top_left.pink": "Pink Chief Dexter Canton", + "block.minecraft.banner.square_top_left.purple": "Purple Chief Dexter Canton", + "block.minecraft.banner.square_top_left.red": "Red Chief Dexter Canton", + "block.minecraft.banner.square_top_left.white": "White Chief Dexter Canton", + "block.minecraft.banner.square_top_left.yellow": "Yellow Chief Dexter Canton", + "block.minecraft.banner.square_top_right.black": "Black Chief Sinister Canton", + "block.minecraft.banner.square_top_right.blue": "Blue Chief Sinister Canton", + "block.minecraft.banner.square_top_right.brown": "Brown Chief Sinister Canton", + "block.minecraft.banner.square_top_right.cyan": "Cyan Chief Sinister Canton", + "block.minecraft.banner.square_top_right.gray": "Gray Chief Sinister Canton", + "block.minecraft.banner.square_top_right.green": "Green Chief Sinister Canton", + "block.minecraft.banner.square_top_right.light_blue": "Light Blue Chief Sinister Canton", + "block.minecraft.banner.square_top_right.light_gray": "Light Gray Chief Sinister Canton", + "block.minecraft.banner.square_top_right.lime": "Lime Chief Sinister Canton", + "block.minecraft.banner.square_top_right.magenta": "Magenta Chief Sinister Canton", + "block.minecraft.banner.square_top_right.orange": "Orange Chief Sinister Canton", + "block.minecraft.banner.square_top_right.pink": "Pink Chief Sinister Canton", + "block.minecraft.banner.square_top_right.purple": "Purple Chief Sinister Canton", + "block.minecraft.banner.square_top_right.red": "Red Chief Sinister Canton", + "block.minecraft.banner.square_top_right.white": "White Chief Sinister Canton", + "block.minecraft.banner.square_top_right.yellow": "Yellow Chief Sinister Canton", + "block.minecraft.banner.straight_cross.black": "Black Cross", + "block.minecraft.banner.straight_cross.blue": "Blue Cross", + "block.minecraft.banner.straight_cross.brown": "Brown Cross", + "block.minecraft.banner.straight_cross.cyan": "Cyan Cross", + "block.minecraft.banner.straight_cross.gray": "Gray Cross", + "block.minecraft.banner.straight_cross.green": "Green Cross", + "block.minecraft.banner.straight_cross.light_blue": "Light Blue Cross", + "block.minecraft.banner.straight_cross.light_gray": "Light Gray Cross", + "block.minecraft.banner.straight_cross.lime": "Lime Cross", + "block.minecraft.banner.straight_cross.magenta": "Magenta Cross", + "block.minecraft.banner.straight_cross.orange": "Orange Cross", + "block.minecraft.banner.straight_cross.pink": "Pink Cross", + "block.minecraft.banner.straight_cross.purple": "Purple Cross", + "block.minecraft.banner.straight_cross.red": "Red Cross", + "block.minecraft.banner.straight_cross.white": "White Cross", + "block.minecraft.banner.straight_cross.yellow": "Yellow Cross", + "block.minecraft.banner.stripe_bottom.black": "Black Base", + "block.minecraft.banner.stripe_bottom.blue": "Blue Base", + "block.minecraft.banner.stripe_bottom.brown": "Brown Base", + "block.minecraft.banner.stripe_bottom.cyan": "Cyan Base", + "block.minecraft.banner.stripe_bottom.gray": "Gray Base", + "block.minecraft.banner.stripe_bottom.green": "Green Base", + "block.minecraft.banner.stripe_bottom.light_blue": "Light Blue Base", + "block.minecraft.banner.stripe_bottom.light_gray": "Light Gray Base", + "block.minecraft.banner.stripe_bottom.lime": "Lime Base", + "block.minecraft.banner.stripe_bottom.magenta": "Magenta Base", + "block.minecraft.banner.stripe_bottom.orange": "Orange Base", + "block.minecraft.banner.stripe_bottom.pink": "Pink Base", + "block.minecraft.banner.stripe_bottom.purple": "Purple Base", + "block.minecraft.banner.stripe_bottom.red": "Red Base", + "block.minecraft.banner.stripe_bottom.white": "White Base", + "block.minecraft.banner.stripe_bottom.yellow": "Yellow Base", + "block.minecraft.banner.stripe_center.black": "Black Pale", + "block.minecraft.banner.stripe_center.blue": "Blue Pale", + "block.minecraft.banner.stripe_center.brown": "Brown Pale", + "block.minecraft.banner.stripe_center.cyan": "Cyan Pale", + "block.minecraft.banner.stripe_center.gray": "Gray Pale", + "block.minecraft.banner.stripe_center.green": "Green Pale", + "block.minecraft.banner.stripe_center.light_blue": "Light Blue Pale", + "block.minecraft.banner.stripe_center.light_gray": "Light Gray Pale", + "block.minecraft.banner.stripe_center.lime": "Lime Pale", + "block.minecraft.banner.stripe_center.magenta": "Magenta Pale", + "block.minecraft.banner.stripe_center.orange": "Orange Pale", + "block.minecraft.banner.stripe_center.pink": "Pink Pale", + "block.minecraft.banner.stripe_center.purple": "Purple Pale", + "block.minecraft.banner.stripe_center.red": "Red Pale", + "block.minecraft.banner.stripe_center.white": "White Pale", + "block.minecraft.banner.stripe_center.yellow": "Yellow Pale", + "block.minecraft.banner.stripe_downleft.black": "Black Bend Sinister", + "block.minecraft.banner.stripe_downleft.blue": "Blue Bend Sinister", + "block.minecraft.banner.stripe_downleft.brown": "Brown Bend Sinister", + "block.minecraft.banner.stripe_downleft.cyan": "Cyan Bend Sinister", + "block.minecraft.banner.stripe_downleft.gray": "Gray Bend Sinister", + "block.minecraft.banner.stripe_downleft.green": "Green Bend Sinister", + "block.minecraft.banner.stripe_downleft.light_blue": "Light Blue Bend Sinister", + "block.minecraft.banner.stripe_downleft.light_gray": "Light Gray Bend Sinister", + "block.minecraft.banner.stripe_downleft.lime": "Lime Bend Sinister", + "block.minecraft.banner.stripe_downleft.magenta": "Magenta Bend Sinister", + "block.minecraft.banner.stripe_downleft.orange": "Orange Bend Sinister", + "block.minecraft.banner.stripe_downleft.pink": "Pink Bend Sinister", + "block.minecraft.banner.stripe_downleft.purple": "Purple Bend Sinister", + "block.minecraft.banner.stripe_downleft.red": "Red Bend Sinister", + "block.minecraft.banner.stripe_downleft.white": "White Bend Sinister", + "block.minecraft.banner.stripe_downleft.yellow": "Yellow Bend Sinister", + "block.minecraft.banner.stripe_downright.black": "Black Bend", + "block.minecraft.banner.stripe_downright.blue": "Blue Bend", + "block.minecraft.banner.stripe_downright.brown": "Brown Bend", + "block.minecraft.banner.stripe_downright.cyan": "Cyan Bend", + "block.minecraft.banner.stripe_downright.gray": "Gray Bend", + "block.minecraft.banner.stripe_downright.green": "Green Bend", + "block.minecraft.banner.stripe_downright.light_blue": "Light Blue Bend", + "block.minecraft.banner.stripe_downright.light_gray": "Light Gray Bend", + "block.minecraft.banner.stripe_downright.lime": "Lime Bend", + "block.minecraft.banner.stripe_downright.magenta": "Magenta Bend", + "block.minecraft.banner.stripe_downright.orange": "Orange Bend", + "block.minecraft.banner.stripe_downright.pink": "Pink Bend", + "block.minecraft.banner.stripe_downright.purple": "Purple Bend", + "block.minecraft.banner.stripe_downright.red": "Red Bend", + "block.minecraft.banner.stripe_downright.white": "White Bend", + "block.minecraft.banner.stripe_downright.yellow": "Yellow Bend", + "block.minecraft.banner.stripe_left.black": "Black Pale Dexter", + "block.minecraft.banner.stripe_left.blue": "Blue Pale Dexter", + "block.minecraft.banner.stripe_left.brown": "Brown Pale Dexter", + "block.minecraft.banner.stripe_left.cyan": "Cyan Pale Dexter", + "block.minecraft.banner.stripe_left.gray": "Gray Pale Dexter", + "block.minecraft.banner.stripe_left.green": "Green Pale Dexter", + "block.minecraft.banner.stripe_left.light_blue": "Light Blue Pale Dexter", + "block.minecraft.banner.stripe_left.light_gray": "Light Gray Pale Dexter", + "block.minecraft.banner.stripe_left.lime": "Lime Pale Dexter", + "block.minecraft.banner.stripe_left.magenta": "Magenta Pale Dexter", + "block.minecraft.banner.stripe_left.orange": "Orange Pale Dexter", + "block.minecraft.banner.stripe_left.pink": "Pink Pale Dexter", + "block.minecraft.banner.stripe_left.purple": "Purple Pale Dexter", + "block.minecraft.banner.stripe_left.red": "Red Pale Dexter", + "block.minecraft.banner.stripe_left.white": "White Pale Dexter", + "block.minecraft.banner.stripe_left.yellow": "Yellow Pale Dexter", + "block.minecraft.banner.stripe_middle.black": "Black Fess", + "block.minecraft.banner.stripe_middle.blue": "Blue Fess", + "block.minecraft.banner.stripe_middle.brown": "Brown Fess", + "block.minecraft.banner.stripe_middle.cyan": "Cyan Fess", + "block.minecraft.banner.stripe_middle.gray": "Gray Fess", + "block.minecraft.banner.stripe_middle.green": "Green Fess", + "block.minecraft.banner.stripe_middle.light_blue": "Light Blue Fess", + "block.minecraft.banner.stripe_middle.light_gray": "Light Gray Fess", + "block.minecraft.banner.stripe_middle.lime": "Lime Fess", + "block.minecraft.banner.stripe_middle.magenta": "Magenta Fess", + "block.minecraft.banner.stripe_middle.orange": "Orange Fess", + "block.minecraft.banner.stripe_middle.pink": "Pink Fess", + "block.minecraft.banner.stripe_middle.purple": "Purple Fess", + "block.minecraft.banner.stripe_middle.red": "Red Fess", + "block.minecraft.banner.stripe_middle.white": "White Fess", + "block.minecraft.banner.stripe_middle.yellow": "Yellow Fess", + "block.minecraft.banner.stripe_right.black": "Black Pale Sinister", + "block.minecraft.banner.stripe_right.blue": "Blue Pale Sinister", + "block.minecraft.banner.stripe_right.brown": "Brown Pale Sinister", + "block.minecraft.banner.stripe_right.cyan": "Cyan Pale Sinister", + "block.minecraft.banner.stripe_right.gray": "Gray Pale Sinister", + "block.minecraft.banner.stripe_right.green": "Green Pale Sinister", + "block.minecraft.banner.stripe_right.light_blue": "Light Blue Pale Sinister", + "block.minecraft.banner.stripe_right.light_gray": "Light Gray Pale Sinister", + "block.minecraft.banner.stripe_right.lime": "Lime Pale Sinister", + "block.minecraft.banner.stripe_right.magenta": "Magenta Pale Sinister", + "block.minecraft.banner.stripe_right.orange": "Orange Pale Sinister", + "block.minecraft.banner.stripe_right.pink": "Pink Pale Sinister", + "block.minecraft.banner.stripe_right.purple": "Purple Pale Sinister", + "block.minecraft.banner.stripe_right.red": "Red Pale Sinister", + "block.minecraft.banner.stripe_right.white": "White Pale Sinister", + "block.minecraft.banner.stripe_right.yellow": "Yellow Pale Sinister", + "block.minecraft.banner.stripe_top.black": "Black Chief", + "block.minecraft.banner.stripe_top.blue": "Blue Chief", + "block.minecraft.banner.stripe_top.brown": "Brown Chief", + "block.minecraft.banner.stripe_top.cyan": "Cyan Chief", + "block.minecraft.banner.stripe_top.gray": "Gray Chief", + "block.minecraft.banner.stripe_top.green": "Green Chief", + "block.minecraft.banner.stripe_top.light_blue": "Light Blue Chief", + "block.minecraft.banner.stripe_top.light_gray": "Light Gray Chief", + "block.minecraft.banner.stripe_top.lime": "Lime Chief", + "block.minecraft.banner.stripe_top.magenta": "Magenta Chief", + "block.minecraft.banner.stripe_top.orange": "Orange Chief", + "block.minecraft.banner.stripe_top.pink": "Pink Chief", + "block.minecraft.banner.stripe_top.purple": "Purple Chief", + "block.minecraft.banner.stripe_top.red": "Red Chief", + "block.minecraft.banner.stripe_top.white": "White Chief", + "block.minecraft.banner.stripe_top.yellow": "Yellow Chief", + "block.minecraft.banner.triangle_bottom.black": "Black Chevron", + "block.minecraft.banner.triangle_bottom.blue": "Blue Chevron", + "block.minecraft.banner.triangle_bottom.brown": "Brown Chevron", + "block.minecraft.banner.triangle_bottom.cyan": "Cyan Chevron", + "block.minecraft.banner.triangle_bottom.gray": "Gray Chevron", + "block.minecraft.banner.triangle_bottom.green": "Green Chevron", + "block.minecraft.banner.triangle_bottom.light_blue": "Light Blue Chevron", + "block.minecraft.banner.triangle_bottom.light_gray": "Light Gray Chevron", + "block.minecraft.banner.triangle_bottom.lime": "Lime Chevron", + "block.minecraft.banner.triangle_bottom.magenta": "Magenta Chevron", + "block.minecraft.banner.triangle_bottom.orange": "Orange Chevron", + "block.minecraft.banner.triangle_bottom.pink": "Pink Chevron", + "block.minecraft.banner.triangle_bottom.purple": "Purple Chevron", + "block.minecraft.banner.triangle_bottom.red": "Red Chevron", + "block.minecraft.banner.triangle_bottom.white": "White Chevron", + "block.minecraft.banner.triangle_bottom.yellow": "Yellow Chevron", + "block.minecraft.banner.triangle_top.black": "Black Inverted Chevron", + "block.minecraft.banner.triangle_top.blue": "Blue Inverted Chevron", + "block.minecraft.banner.triangle_top.brown": "Brown Inverted Chevron", + "block.minecraft.banner.triangle_top.cyan": "Cyan Inverted Chevron", + "block.minecraft.banner.triangle_top.gray": "Gray Inverted Chevron", + "block.minecraft.banner.triangle_top.green": "Green Inverted Chevron", + "block.minecraft.banner.triangle_top.light_blue": "Light Blue Inverted Chevron", + "block.minecraft.banner.triangle_top.light_gray": "Light Gray Inverted Chevron", + "block.minecraft.banner.triangle_top.lime": "Lime Inverted Chevron", + "block.minecraft.banner.triangle_top.magenta": "Magenta Inverted Chevron", + "block.minecraft.banner.triangle_top.orange": "Orange Inverted Chevron", + "block.minecraft.banner.triangle_top.pink": "Pink Inverted Chevron", + "block.minecraft.banner.triangle_top.purple": "Purple Inverted Chevron", + "block.minecraft.banner.triangle_top.red": "Red Inverted Chevron", + "block.minecraft.banner.triangle_top.white": "White Inverted Chevron", + "block.minecraft.banner.triangle_top.yellow": "Yellow Inverted Chevron", + "block.minecraft.banner.triangles_bottom.black": "Black Base Indented", + "block.minecraft.banner.triangles_bottom.blue": "Blue Base Indented", + "block.minecraft.banner.triangles_bottom.brown": "Brown Base Indented", + "block.minecraft.banner.triangles_bottom.cyan": "Cyan Base Indented", + "block.minecraft.banner.triangles_bottom.gray": "Gray Base Indented", + "block.minecraft.banner.triangles_bottom.green": "Green Base Indented", + "block.minecraft.banner.triangles_bottom.light_blue": "Light Blue Base Indented", + "block.minecraft.banner.triangles_bottom.light_gray": "Light Gray Base Indented", + "block.minecraft.banner.triangles_bottom.lime": "Lime Base Indented", + "block.minecraft.banner.triangles_bottom.magenta": "Magenta Base Indented", + "block.minecraft.banner.triangles_bottom.orange": "Orange Base Indented", + "block.minecraft.banner.triangles_bottom.pink": "Pink Base Indented", + "block.minecraft.banner.triangles_bottom.purple": "Purple Base Indented", + "block.minecraft.banner.triangles_bottom.red": "Red Base Indented", + "block.minecraft.banner.triangles_bottom.white": "White Base Indented", + "block.minecraft.banner.triangles_bottom.yellow": "Yellow Base Indented", + "block.minecraft.banner.triangles_top.black": "Black Chief Indented", + "block.minecraft.banner.triangles_top.blue": "Blue Chief Indented", + "block.minecraft.banner.triangles_top.brown": "Brown Chief Indented", + "block.minecraft.banner.triangles_top.cyan": "Cyan Chief Indented", + "block.minecraft.banner.triangles_top.gray": "Gray Chief Indented", + "block.minecraft.banner.triangles_top.green": "Green Chief Indented", + "block.minecraft.banner.triangles_top.light_blue": "Light Blue Chief Indented", + "block.minecraft.banner.triangles_top.light_gray": "Light Gray Chief Indented", + "block.minecraft.banner.triangles_top.lime": "Lime Chief Indented", + "block.minecraft.banner.triangles_top.magenta": "Magenta Chief Indented", + "block.minecraft.banner.triangles_top.orange": "Orange Chief Indented", + "block.minecraft.banner.triangles_top.pink": "Pink Chief Indented", + "block.minecraft.banner.triangles_top.purple": "Purple Chief Indented", + "block.minecraft.banner.triangles_top.red": "Red Chief Indented", + "block.minecraft.banner.triangles_top.white": "White Chief Indented", + "block.minecraft.banner.triangles_top.yellow": "Yellow Chief Indented", + "block.minecraft.barrel": "Barrel", + "block.minecraft.barrier": "Barrier", + "block.minecraft.basalt": "Basalt", + "block.minecraft.beacon": "Beacon", + "block.minecraft.beacon.primary": "Primary Power", + "block.minecraft.beacon.secondary": "Secondary Power", + "block.minecraft.bed.no_sleep": "You can sleep only at night or during thunderstorms", + "block.minecraft.bed.not_safe": "You may not rest now; there are monsters nearby", + "block.minecraft.bed.obstructed": "This bed is obstructed", + "block.minecraft.bed.occupied": "This bed is occupied", + "block.minecraft.bed.too_far_away": "You may not rest now; the bed is too far away", + "block.minecraft.bedrock": "Bedrock", + "block.minecraft.bee_nest": "Bee Nest", + "block.minecraft.beehive": "Beehive", + "block.minecraft.beetroots": "Beetroots", + "block.minecraft.bell": "Bell", + "block.minecraft.big_dripleaf": "Big Dripleaf", + "block.minecraft.big_dripleaf_stem": "Big Dripleaf Stem", + "block.minecraft.birch_button": "Birch Button", + "block.minecraft.birch_door": "Birch Door", + "block.minecraft.birch_fence": "Birch Fence", + "block.minecraft.birch_fence_gate": "Birch Fence Gate", + "block.minecraft.birch_hanging_sign": "Birch Hanging Sign", + "block.minecraft.birch_leaves": "Birch Leaves", + "block.minecraft.birch_log": "Birch Log", + "block.minecraft.birch_planks": "Birch Planks", + "block.minecraft.birch_pressure_plate": "Birch Pressure Plate", + "block.minecraft.birch_sapling": "Birch Sapling", + "block.minecraft.birch_sign": "Birch Sign", + "block.minecraft.birch_slab": "Birch Slab", + "block.minecraft.birch_stairs": "Birch Stairs", + "block.minecraft.birch_trapdoor": "Birch Trapdoor", + "block.minecraft.birch_wall_hanging_sign": "Birch Wall Hanging Sign", + "block.minecraft.birch_wall_sign": "Birch Wall Sign", + "block.minecraft.birch_wood": "Birch Wood", + "block.minecraft.black_banner": "Black Banner", + "block.minecraft.black_bed": "Black Bed", + "block.minecraft.black_candle": "Black Candle", + "block.minecraft.black_candle_cake": "Cake with Black Candle", + "block.minecraft.black_carpet": "Black Carpet", + "block.minecraft.black_concrete": "Black Concrete", + "block.minecraft.black_concrete_powder": "Black Concrete Powder", + "block.minecraft.black_glazed_terracotta": "Black Glazed Terracotta", + "block.minecraft.black_shulker_box": "Black Shulker Box", + "block.minecraft.black_stained_glass": "Black Stained Glass", + "block.minecraft.black_stained_glass_pane": "Black Stained Glass Pane", + "block.minecraft.black_terracotta": "Black Terracotta", + "block.minecraft.black_wool": "Black Wool", + "block.minecraft.blackstone": "Blackstone", + "block.minecraft.blackstone_slab": "Blackstone Slab", + "block.minecraft.blackstone_stairs": "Blackstone Stairs", + "block.minecraft.blackstone_wall": "Blackstone Wall", + "block.minecraft.blast_furnace": "Blast Furnace", + "block.minecraft.blue_banner": "Blue Banner", + "block.minecraft.blue_bed": "Blue Bed", + "block.minecraft.blue_candle": "Blue Candle", + "block.minecraft.blue_candle_cake": "Cake with Blue Candle", + "block.minecraft.blue_carpet": "Blue Carpet", + "block.minecraft.blue_concrete": "Blue Concrete", + "block.minecraft.blue_concrete_powder": "Blue Concrete Powder", + "block.minecraft.blue_glazed_terracotta": "Blue Glazed Terracotta", + "block.minecraft.blue_ice": "Blue Ice", + "block.minecraft.blue_orchid": "Blue Orchid", + "block.minecraft.blue_shulker_box": "Blue Shulker Box", + "block.minecraft.blue_stained_glass": "Blue Stained Glass", + "block.minecraft.blue_stained_glass_pane": "Blue Stained Glass Pane", + "block.minecraft.blue_terracotta": "Blue Terracotta", + "block.minecraft.blue_wool": "Blue Wool", + "block.minecraft.bone_block": "Bone Block", + "block.minecraft.bookshelf": "Bookshelf", + "block.minecraft.brain_coral": "Brain Coral", + "block.minecraft.brain_coral_block": "Brain Coral Block", + "block.minecraft.brain_coral_fan": "Brain Coral Fan", + "block.minecraft.brain_coral_wall_fan": "Brain Coral Wall Fan", + "block.minecraft.brewing_stand": "Brewing Stand", + "block.minecraft.brick_slab": "Brick Slab", + "block.minecraft.brick_stairs": "Brick Stairs", + "block.minecraft.brick_wall": "Brick Wall", + "block.minecraft.bricks": "Bricks", + "block.minecraft.brown_banner": "Brown Banner", + "block.minecraft.brown_bed": "Brown Bed", + "block.minecraft.brown_candle": "Brown Candle", + "block.minecraft.brown_candle_cake": "Cake with Brown Candle", + "block.minecraft.brown_carpet": "Brown Carpet", + "block.minecraft.brown_concrete": "Brown Concrete", + "block.minecraft.brown_concrete_powder": "Brown Concrete Powder", + "block.minecraft.brown_glazed_terracotta": "Brown Glazed Terracotta", + "block.minecraft.brown_mushroom": "Brown Mushroom", + "block.minecraft.brown_mushroom_block": "Brown Mushroom Block", + "block.minecraft.brown_shulker_box": "Brown Shulker Box", + "block.minecraft.brown_stained_glass": "Brown Stained Glass", + "block.minecraft.brown_stained_glass_pane": "Brown Stained Glass Pane", + "block.minecraft.brown_terracotta": "Brown Terracotta", + "block.minecraft.brown_wool": "Brown Wool", + "block.minecraft.bubble_column": "Bubble Column", + "block.minecraft.bubble_coral": "Bubble Coral", + "block.minecraft.bubble_coral_block": "Bubble Coral Block", + "block.minecraft.bubble_coral_fan": "Bubble Coral Fan", + "block.minecraft.bubble_coral_wall_fan": "Bubble Coral Wall Fan", + "block.minecraft.budding_amethyst": "Budding Amethyst", + "block.minecraft.cactus": "Cactus", + "block.minecraft.cake": "Cake", + "block.minecraft.calcite": "Calcite", + "block.minecraft.calibrated_sculk_sensor": "Calibrated Sculk Sensor", + "block.minecraft.campfire": "Campfire", + "block.minecraft.candle": "Candle", + "block.minecraft.candle_cake": "Cake with Candle", + "block.minecraft.carrots": "Carrots", + "block.minecraft.cartography_table": "Cartography Table", + "block.minecraft.carved_pumpkin": "Carved Pumpkin", + "block.minecraft.cauldron": "Cauldron", + "block.minecraft.cave_air": "Cave Air", + "block.minecraft.cave_vines": "Cave Vines", + "block.minecraft.cave_vines_plant": "Cave Vines Plant", + "block.minecraft.chain": "Chain", + "block.minecraft.chain_command_block": "Chain Command Block", + "block.minecraft.cherry_button": "Cherry Button", + "block.minecraft.cherry_door": "Cherry Door", + "block.minecraft.cherry_fence": "Cherry Fence", + "block.minecraft.cherry_fence_gate": "Cherry Fence Gate", + "block.minecraft.cherry_hanging_sign": "Cherry Hanging Sign", + "block.minecraft.cherry_leaves": "Cherry Leaves", + "block.minecraft.cherry_log": "Cherry Log", + "block.minecraft.cherry_planks": "Cherry Planks", + "block.minecraft.cherry_pressure_plate": "Cherry Pressure Plate", + "block.minecraft.cherry_sapling": "Cherry Sapling", + "block.minecraft.cherry_sign": "Cherry Sign", + "block.minecraft.cherry_slab": "Cherry Slab", + "block.minecraft.cherry_stairs": "Cherry Stairs", + "block.minecraft.cherry_trapdoor": "Cherry Trapdoor", + "block.minecraft.cherry_wall_hanging_sign": "Cherry Wall Hanging Sign", + "block.minecraft.cherry_wall_sign": "Cherry Wall Sign", + "block.minecraft.cherry_wood": "Cherry Wood", + "block.minecraft.chest": "Chest", + "block.minecraft.chipped_anvil": "Chipped Anvil", + "block.minecraft.chiseled_bookshelf": "Chiseled Bookshelf", + "block.minecraft.chiseled_copper": "Chiseled Copper", + "block.minecraft.chiseled_deepslate": "Chiseled Deepslate", + "block.minecraft.chiseled_nether_bricks": "Chiseled Nether Bricks", + "block.minecraft.chiseled_polished_blackstone": "Chiseled Polished Blackstone", + "block.minecraft.chiseled_quartz_block": "Chiseled Quartz Block", + "block.minecraft.chiseled_red_sandstone": "Chiseled Red Sandstone", + "block.minecraft.chiseled_sandstone": "Chiseled Sandstone", + "block.minecraft.chiseled_stone_bricks": "Chiseled Stone Bricks", + "block.minecraft.chiseled_tuff": "Chiseled Tuff", + "block.minecraft.chiseled_tuff_bricks": "Chiseled Tuff Bricks", + "block.minecraft.chorus_flower": "Chorus Flower", + "block.minecraft.chorus_plant": "Chorus Plant", + "block.minecraft.clay": "Clay", + "block.minecraft.coal_block": "Block of Coal", + "block.minecraft.coal_ore": "Coal Ore", + "block.minecraft.coarse_dirt": "Coarse Dirt", + "block.minecraft.cobbled_deepslate": "Cobbled Deepslate", + "block.minecraft.cobbled_deepslate_slab": "Cobbled Deepslate Slab", + "block.minecraft.cobbled_deepslate_stairs": "Cobbled Deepslate Stairs", + "block.minecraft.cobbled_deepslate_wall": "Cobbled Deepslate Wall", + "block.minecraft.cobblestone": "Cobblestone", + "block.minecraft.cobblestone_slab": "Cobblestone Slab", + "block.minecraft.cobblestone_stairs": "Cobblestone Stairs", + "block.minecraft.cobblestone_wall": "Cobblestone Wall", + "block.minecraft.cobweb": "Cobweb", + "block.minecraft.cocoa": "Cocoa", + "block.minecraft.command_block": "Command Block", + "block.minecraft.comparator": "Redstone Comparator", + "block.minecraft.composter": "Composter", + "block.minecraft.conduit": "Conduit", + "block.minecraft.copper_block": "Block of Copper", + "block.minecraft.copper_bulb": "Copper Bulb", + "block.minecraft.copper_door": "Copper Door", + "block.minecraft.copper_grate": "Copper Grate", + "block.minecraft.copper_ore": "Copper Ore", + "block.minecraft.copper_trapdoor": "Copper Trapdoor", + "block.minecraft.cornflower": "Cornflower", + "block.minecraft.cracked_deepslate_bricks": "Cracked Deepslate Bricks", + "block.minecraft.cracked_deepslate_tiles": "Cracked Deepslate Tiles", + "block.minecraft.cracked_nether_bricks": "Cracked Nether Bricks", + "block.minecraft.cracked_polished_blackstone_bricks": "Cracked Polished Blackstone Bricks", + "block.minecraft.cracked_stone_bricks": "Cracked Stone Bricks", + "block.minecraft.crafter": "Crafter", + "block.minecraft.crafting_table": "Crafting Table", + "block.minecraft.creeper_head": "Creeper Head", + "block.minecraft.creeper_wall_head": "Creeper Wall Head", + "block.minecraft.crimson_button": "Crimson Button", + "block.minecraft.crimson_door": "Crimson Door", + "block.minecraft.crimson_fence": "Crimson Fence", + "block.minecraft.crimson_fence_gate": "Crimson Fence Gate", + "block.minecraft.crimson_fungus": "Crimson Fungus", + "block.minecraft.crimson_hanging_sign": "Crimson Hanging Sign", + "block.minecraft.crimson_hyphae": "Crimson Hyphae", + "block.minecraft.crimson_nylium": "Crimson Nylium", + "block.minecraft.crimson_planks": "Crimson Planks", + "block.minecraft.crimson_pressure_plate": "Crimson Pressure Plate", + "block.minecraft.crimson_roots": "Crimson Roots", + "block.minecraft.crimson_sign": "Crimson Sign", + "block.minecraft.crimson_slab": "Crimson Slab", + "block.minecraft.crimson_stairs": "Crimson Stairs", + "block.minecraft.crimson_stem": "Crimson Stem", + "block.minecraft.crimson_trapdoor": "Crimson Trapdoor", + "block.minecraft.crimson_wall_hanging_sign": "Crimson Wall Hanging Sign", + "block.minecraft.crimson_wall_sign": "Crimson Wall Sign", + "block.minecraft.crying_obsidian": "Crying Obsidian", + "block.minecraft.cut_copper": "Cut Copper", + "block.minecraft.cut_copper_slab": "Cut Copper Slab", + "block.minecraft.cut_copper_stairs": "Cut Copper Stairs", + "block.minecraft.cut_red_sandstone": "Cut Red Sandstone", + "block.minecraft.cut_red_sandstone_slab": "Cut Red Sandstone Slab", + "block.minecraft.cut_sandstone": "Cut Sandstone", + "block.minecraft.cut_sandstone_slab": "Cut Sandstone Slab", + "block.minecraft.cyan_banner": "Cyan Banner", + "block.minecraft.cyan_bed": "Cyan Bed", + "block.minecraft.cyan_candle": "Cyan Candle", + "block.minecraft.cyan_candle_cake": "Cake with Cyan Candle", + "block.minecraft.cyan_carpet": "Cyan Carpet", + "block.minecraft.cyan_concrete": "Cyan Concrete", + "block.minecraft.cyan_concrete_powder": "Cyan Concrete Powder", + "block.minecraft.cyan_glazed_terracotta": "Cyan Glazed Terracotta", + "block.minecraft.cyan_shulker_box": "Cyan Shulker Box", + "block.minecraft.cyan_stained_glass": "Cyan Stained Glass", + "block.minecraft.cyan_stained_glass_pane": "Cyan Stained Glass Pane", + "block.minecraft.cyan_terracotta": "Cyan Terracotta", + "block.minecraft.cyan_wool": "Cyan Wool", + "block.minecraft.damaged_anvil": "Damaged Anvil", + "block.minecraft.dandelion": "Dandelion", + "block.minecraft.dark_oak_button": "Dark Oak Button", + "block.minecraft.dark_oak_door": "Dark Oak Door", + "block.minecraft.dark_oak_fence": "Dark Oak Fence", + "block.minecraft.dark_oak_fence_gate": "Dark Oak Fence Gate", + "block.minecraft.dark_oak_hanging_sign": "Dark Oak Hanging Sign", + "block.minecraft.dark_oak_leaves": "Dark Oak Leaves", + "block.minecraft.dark_oak_log": "Dark Oak Log", + "block.minecraft.dark_oak_planks": "Dark Oak Planks", + "block.minecraft.dark_oak_pressure_plate": "Dark Oak Pressure Plate", + "block.minecraft.dark_oak_sapling": "Dark Oak Sapling", + "block.minecraft.dark_oak_sign": "Dark Oak Sign", + "block.minecraft.dark_oak_slab": "Dark Oak Slab", + "block.minecraft.dark_oak_stairs": "Dark Oak Stairs", + "block.minecraft.dark_oak_trapdoor": "Dark Oak Trapdoor", + "block.minecraft.dark_oak_wall_hanging_sign": "Dark Oak Wall Hanging Sign", + "block.minecraft.dark_oak_wall_sign": "Dark Oak Wall Sign", + "block.minecraft.dark_oak_wood": "Dark Oak Wood", + "block.minecraft.dark_prismarine": "Dark Prismarine", + "block.minecraft.dark_prismarine_slab": "Dark Prismarine Slab", + "block.minecraft.dark_prismarine_stairs": "Dark Prismarine Stairs", + "block.minecraft.daylight_detector": "Daylight Detector", + "block.minecraft.dead_brain_coral": "Dead Brain Coral", + "block.minecraft.dead_brain_coral_block": "Dead Brain Coral Block", + "block.minecraft.dead_brain_coral_fan": "Dead Brain Coral Fan", + "block.minecraft.dead_brain_coral_wall_fan": "Dead Brain Coral Wall Fan", + "block.minecraft.dead_bubble_coral": "Dead Bubble Coral", + "block.minecraft.dead_bubble_coral_block": "Dead Bubble Coral Block", + "block.minecraft.dead_bubble_coral_fan": "Dead Bubble Coral Fan", + "block.minecraft.dead_bubble_coral_wall_fan": "Dead Bubble Coral Wall Fan", + "block.minecraft.dead_bush": "Dead Bush", + "block.minecraft.dead_fire_coral": "Dead Fire Coral", + "block.minecraft.dead_fire_coral_block": "Dead Fire Coral Block", + "block.minecraft.dead_fire_coral_fan": "Dead Fire Coral Fan", + "block.minecraft.dead_fire_coral_wall_fan": "Dead Fire Coral Wall Fan", + "block.minecraft.dead_horn_coral": "Dead Horn Coral", + "block.minecraft.dead_horn_coral_block": "Dead Horn Coral Block", + "block.minecraft.dead_horn_coral_fan": "Dead Horn Coral Fan", + "block.minecraft.dead_horn_coral_wall_fan": "Dead Horn Coral Wall Fan", + "block.minecraft.dead_tube_coral": "Dead Tube Coral", + "block.minecraft.dead_tube_coral_block": "Dead Tube Coral Block", + "block.minecraft.dead_tube_coral_fan": "Dead Tube Coral Fan", + "block.minecraft.dead_tube_coral_wall_fan": "Dead Tube Coral Wall Fan", + "block.minecraft.decorated_pot": "Decorated Pot", + "block.minecraft.deepslate": "Deepslate", + "block.minecraft.deepslate_brick_slab": "Deepslate Brick Slab", + "block.minecraft.deepslate_brick_stairs": "Deepslate Brick Stairs", + "block.minecraft.deepslate_brick_wall": "Deepslate Brick Wall", + "block.minecraft.deepslate_bricks": "Deepslate Bricks", + "block.minecraft.deepslate_coal_ore": "Deepslate Coal Ore", + "block.minecraft.deepslate_copper_ore": "Deepslate Copper Ore", + "block.minecraft.deepslate_diamond_ore": "Deepslate Diamond Ore", + "block.minecraft.deepslate_emerald_ore": "Deepslate Emerald Ore", + "block.minecraft.deepslate_gold_ore": "Deepslate Gold Ore", + "block.minecraft.deepslate_iron_ore": "Deepslate Iron Ore", + "block.minecraft.deepslate_lapis_ore": "Deepslate Lapis Lazuli Ore", + "block.minecraft.deepslate_redstone_ore": "Deepslate Redstone Ore", + "block.minecraft.deepslate_tile_slab": "Deepslate Tile Slab", + "block.minecraft.deepslate_tile_stairs": "Deepslate Tile Stairs", + "block.minecraft.deepslate_tile_wall": "Deepslate Tile Wall", + "block.minecraft.deepslate_tiles": "Deepslate Tiles", + "block.minecraft.detector_rail": "Detector Rail", + "block.minecraft.diamond_block": "Block of Diamond", + "block.minecraft.diamond_ore": "Diamond Ore", + "block.minecraft.diorite": "Diorite", + "block.minecraft.diorite_slab": "Diorite Slab", + "block.minecraft.diorite_stairs": "Diorite Stairs", + "block.minecraft.diorite_wall": "Diorite Wall", + "block.minecraft.dirt": "Dirt", + "block.minecraft.dirt_path": "Dirt Path", + "block.minecraft.dispenser": "Dispenser", + "block.minecraft.dragon_egg": "Dragon Egg", + "block.minecraft.dragon_head": "Dragon Head", + "block.minecraft.dragon_wall_head": "Dragon Wall Head", + "block.minecraft.dried_kelp_block": "Dried Kelp Block", + "block.minecraft.dripstone_block": "Dripstone Block", + "block.minecraft.dropper": "Dropper", + "block.minecraft.emerald_block": "Block of Emerald", + "block.minecraft.emerald_ore": "Emerald Ore", + "block.minecraft.enchanting_table": "Enchanting Table", + "block.minecraft.end_gateway": "End Gateway", + "block.minecraft.end_portal": "End Portal", + "block.minecraft.end_portal_frame": "End Portal Frame", + "block.minecraft.end_rod": "End Rod", + "block.minecraft.end_stone": "End Stone", + "block.minecraft.end_stone_brick_slab": "End Stone Brick Slab", + "block.minecraft.end_stone_brick_stairs": "End Stone Brick Stairs", + "block.minecraft.end_stone_brick_wall": "End Stone Brick Wall", + "block.minecraft.end_stone_bricks": "End Stone Bricks", + "block.minecraft.ender_chest": "Ender Chest", + "block.minecraft.exposed_chiseled_copper": "Exposed Chiseled Copper", + "block.minecraft.exposed_copper": "Exposed Copper", + "block.minecraft.exposed_copper_bulb": "Exposed Copper Bulb", + "block.minecraft.exposed_copper_door": "Exposed Copper Door", + "block.minecraft.exposed_copper_grate": "Exposed Copper Grate", + "block.minecraft.exposed_copper_trapdoor": "Exposed Copper Trapdoor", + "block.minecraft.exposed_cut_copper": "Exposed Cut Copper", + "block.minecraft.exposed_cut_copper_slab": "Exposed Cut Copper Slab", + "block.minecraft.exposed_cut_copper_stairs": "Exposed Cut Copper Stairs", + "block.minecraft.farmland": "Farmland", + "block.minecraft.fern": "Fern", + "block.minecraft.fire": "Fire", + "block.minecraft.fire_coral": "Fire Coral", + "block.minecraft.fire_coral_block": "Fire Coral Block", + "block.minecraft.fire_coral_fan": "Fire Coral Fan", + "block.minecraft.fire_coral_wall_fan": "Fire Coral Wall Fan", + "block.minecraft.fletching_table": "Fletching Table", + "block.minecraft.flower_pot": "Flower Pot", + "block.minecraft.flowering_azalea": "Flowering Azalea", + "block.minecraft.flowering_azalea_leaves": "Flowering Azalea Leaves", + "block.minecraft.frogspawn": "Frogspawn", + "block.minecraft.frosted_ice": "Frosted Ice", + "block.minecraft.furnace": "Furnace", + "block.minecraft.gilded_blackstone": "Gilded Blackstone", + "block.minecraft.glass": "Glass", + "block.minecraft.glass_pane": "Glass Pane", + "block.minecraft.glow_lichen": "Glow Lichen", + "block.minecraft.glowstone": "Glowstone", + "block.minecraft.gold_block": "Block of Gold", + "block.minecraft.gold_ore": "Gold Ore", + "block.minecraft.granite": "Granite", + "block.minecraft.granite_slab": "Granite Slab", + "block.minecraft.granite_stairs": "Granite Stairs", + "block.minecraft.granite_wall": "Granite Wall", + "block.minecraft.grass": "Grass", + "block.minecraft.grass_block": "Grass Block", + "block.minecraft.gravel": "Gravel", + "block.minecraft.gray_banner": "Gray Banner", + "block.minecraft.gray_bed": "Gray Bed", + "block.minecraft.gray_candle": "Gray Candle", + "block.minecraft.gray_candle_cake": "Cake with Gray Candle", + "block.minecraft.gray_carpet": "Gray Carpet", + "block.minecraft.gray_concrete": "Gray Concrete", + "block.minecraft.gray_concrete_powder": "Gray Concrete Powder", + "block.minecraft.gray_glazed_terracotta": "Gray Glazed Terracotta", + "block.minecraft.gray_shulker_box": "Gray Shulker Box", + "block.minecraft.gray_stained_glass": "Gray Stained Glass", + "block.minecraft.gray_stained_glass_pane": "Gray Stained Glass Pane", + "block.minecraft.gray_terracotta": "Gray Terracotta", + "block.minecraft.gray_wool": "Gray Wool", + "block.minecraft.green_banner": "Green Banner", + "block.minecraft.green_bed": "Green Bed", + "block.minecraft.green_candle": "Green Candle", + "block.minecraft.green_candle_cake": "Cake with Green Candle", + "block.minecraft.green_carpet": "Green Carpet", + "block.minecraft.green_concrete": "Green Concrete", + "block.minecraft.green_concrete_powder": "Green Concrete Powder", + "block.minecraft.green_glazed_terracotta": "Green Glazed Terracotta", + "block.minecraft.green_shulker_box": "Green Shulker Box", + "block.minecraft.green_stained_glass": "Green Stained Glass", + "block.minecraft.green_stained_glass_pane": "Green Stained Glass Pane", + "block.minecraft.green_terracotta": "Green Terracotta", + "block.minecraft.green_wool": "Green Wool", + "block.minecraft.grindstone": "Grindstone", + "block.minecraft.hanging_roots": "Hanging Roots", + "block.minecraft.hay_block": "Hay Bale", + "block.minecraft.heavy_core": "Heavy Core", + "block.minecraft.heavy_weighted_pressure_plate": "Heavy Weighted Pressure Plate", + "block.minecraft.honey_block": "Honey Block", + "block.minecraft.honeycomb_block": "Honeycomb Block", + "block.minecraft.hopper": "Hopper", + "block.minecraft.horn_coral": "Horn Coral", + "block.minecraft.horn_coral_block": "Horn Coral Block", + "block.minecraft.horn_coral_fan": "Horn Coral Fan", + "block.minecraft.horn_coral_wall_fan": "Horn Coral Wall Fan", + "block.minecraft.ice": "Ice", + "block.minecraft.infested_chiseled_stone_bricks": "Infested Chiseled Stone Bricks", + "block.minecraft.infested_cobblestone": "Infested Cobblestone", + "block.minecraft.infested_cracked_stone_bricks": "Infested Cracked Stone Bricks", + "block.minecraft.infested_deepslate": "Infested Deepslate", + "block.minecraft.infested_mossy_stone_bricks": "Infested Mossy Stone Bricks", + "block.minecraft.infested_stone": "Infested Stone", + "block.minecraft.infested_stone_bricks": "Infested Stone Bricks", + "block.minecraft.iron_bars": "Iron Bars", + "block.minecraft.iron_block": "Block of Iron", + "block.minecraft.iron_door": "Iron Door", + "block.minecraft.iron_ore": "Iron Ore", + "block.minecraft.iron_trapdoor": "Iron Trapdoor", + "block.minecraft.jack_o_lantern": "Jack o'Lantern", + "block.minecraft.jigsaw": "Jigsaw Block", + "block.minecraft.jukebox": "Jukebox", + "block.minecraft.jungle_button": "Jungle Button", + "block.minecraft.jungle_door": "Jungle Door", + "block.minecraft.jungle_fence": "Jungle Fence", + "block.minecraft.jungle_fence_gate": "Jungle Fence Gate", + "block.minecraft.jungle_hanging_sign": "Jungle Hanging Sign", + "block.minecraft.jungle_leaves": "Jungle Leaves", + "block.minecraft.jungle_log": "Jungle Log", + "block.minecraft.jungle_planks": "Jungle Planks", + "block.minecraft.jungle_pressure_plate": "Jungle Pressure Plate", + "block.minecraft.jungle_sapling": "Jungle Sapling", + "block.minecraft.jungle_sign": "Jungle Sign", + "block.minecraft.jungle_slab": "Jungle Slab", + "block.minecraft.jungle_stairs": "Jungle Stairs", + "block.minecraft.jungle_trapdoor": "Jungle Trapdoor", + "block.minecraft.jungle_wall_hanging_sign": "Jungle Wall Hanging Sign", + "block.minecraft.jungle_wall_sign": "Jungle Wall Sign", + "block.minecraft.jungle_wood": "Jungle Wood", + "block.minecraft.kelp": "Kelp", + "block.minecraft.kelp_plant": "Kelp Plant", + "block.minecraft.ladder": "Ladder", + "block.minecraft.lantern": "Lantern", + "block.minecraft.lapis_block": "Block of Lapis Lazuli", + "block.minecraft.lapis_ore": "Lapis Lazuli Ore", + "block.minecraft.large_amethyst_bud": "Large Amethyst Bud", + "block.minecraft.large_fern": "Large Fern", + "block.minecraft.lava": "Lava", + "block.minecraft.lava_cauldron": "Lava Cauldron", + "block.minecraft.lectern": "Lectern", + "block.minecraft.lever": "Lever", + "block.minecraft.light": "Light", + "block.minecraft.light_blue_banner": "Light Blue Banner", + "block.minecraft.light_blue_bed": "Light Blue Bed", + "block.minecraft.light_blue_candle": "Light Blue Candle", + "block.minecraft.light_blue_candle_cake": "Cake with Light Blue Candle", + "block.minecraft.light_blue_carpet": "Light Blue Carpet", + "block.minecraft.light_blue_concrete": "Light Blue Concrete", + "block.minecraft.light_blue_concrete_powder": "Light Blue Concrete Powder", + "block.minecraft.light_blue_glazed_terracotta": "Light Blue Glazed Terracotta", + "block.minecraft.light_blue_shulker_box": "Light Blue Shulker Box", + "block.minecraft.light_blue_stained_glass": "Light Blue Stained Glass", + "block.minecraft.light_blue_stained_glass_pane": "Light Blue Stained Glass Pane", + "block.minecraft.light_blue_terracotta": "Light Blue Terracotta", + "block.minecraft.light_blue_wool": "Light Blue Wool", + "block.minecraft.light_gray_banner": "Light Gray Banner", + "block.minecraft.light_gray_bed": "Light Gray Bed", + "block.minecraft.light_gray_candle": "Light Gray Candle", + "block.minecraft.light_gray_candle_cake": "Cake with Light Gray Candle", + "block.minecraft.light_gray_carpet": "Light Gray Carpet", + "block.minecraft.light_gray_concrete": "Light Gray Concrete", + "block.minecraft.light_gray_concrete_powder": "Light Gray Concrete Powder", + "block.minecraft.light_gray_glazed_terracotta": "Light Gray Glazed Terracotta", + "block.minecraft.light_gray_shulker_box": "Light Gray Shulker Box", + "block.minecraft.light_gray_stained_glass": "Light Gray Stained Glass", + "block.minecraft.light_gray_stained_glass_pane": "Light Gray Stained Glass Pane", + "block.minecraft.light_gray_terracotta": "Light Gray Terracotta", + "block.minecraft.light_gray_wool": "Light Gray Wool", + "block.minecraft.light_weighted_pressure_plate": "Light Weighted Pressure Plate", + "block.minecraft.lightning_rod": "Lightning Rod", + "block.minecraft.lilac": "Lilac", + "block.minecraft.lily_of_the_valley": "Lily of the Valley", + "block.minecraft.lily_pad": "Lily Pad", + "block.minecraft.lime_banner": "Lime Banner", + "block.minecraft.lime_bed": "Lime Bed", + "block.minecraft.lime_candle": "Lime Candle", + "block.minecraft.lime_candle_cake": "Cake with Lime Candle", + "block.minecraft.lime_carpet": "Lime Carpet", + "block.minecraft.lime_concrete": "Lime Concrete", + "block.minecraft.lime_concrete_powder": "Lime Concrete Powder", + "block.minecraft.lime_glazed_terracotta": "Lime Glazed Terracotta", + "block.minecraft.lime_shulker_box": "Lime Shulker Box", + "block.minecraft.lime_stained_glass": "Lime Stained Glass", + "block.minecraft.lime_stained_glass_pane": "Lime Stained Glass Pane", + "block.minecraft.lime_terracotta": "Lime Terracotta", + "block.minecraft.lime_wool": "Lime Wool", + "block.minecraft.lodestone": "Lodestone", + "block.minecraft.loom": "Loom", + "block.minecraft.magenta_banner": "Magenta Banner", + "block.minecraft.magenta_bed": "Magenta Bed", + "block.minecraft.magenta_candle": "Magenta Candle", + "block.minecraft.magenta_candle_cake": "Cake with Magenta Candle", + "block.minecraft.magenta_carpet": "Magenta Carpet", + "block.minecraft.magenta_concrete": "Magenta Concrete", + "block.minecraft.magenta_concrete_powder": "Magenta Concrete Powder", + "block.minecraft.magenta_glazed_terracotta": "Magenta Glazed Terracotta", + "block.minecraft.magenta_shulker_box": "Magenta Shulker Box", + "block.minecraft.magenta_stained_glass": "Magenta Stained Glass", + "block.minecraft.magenta_stained_glass_pane": "Magenta Stained Glass Pane", + "block.minecraft.magenta_terracotta": "Magenta Terracotta", + "block.minecraft.magenta_wool": "Magenta Wool", + "block.minecraft.magma_block": "Magma Block", + "block.minecraft.mangrove_button": "Mangrove Button", + "block.minecraft.mangrove_door": "Mangrove Door", + "block.minecraft.mangrove_fence": "Mangrove Fence", + "block.minecraft.mangrove_fence_gate": "Mangrove Fence Gate", + "block.minecraft.mangrove_hanging_sign": "Mangrove Hanging Sign", + "block.minecraft.mangrove_leaves": "Mangrove Leaves", + "block.minecraft.mangrove_log": "Mangrove Log", + "block.minecraft.mangrove_planks": "Mangrove Planks", + "block.minecraft.mangrove_pressure_plate": "Mangrove Pressure Plate", + "block.minecraft.mangrove_propagule": "Mangrove Propagule", + "block.minecraft.mangrove_roots": "Mangrove Roots", + "block.minecraft.mangrove_sign": "Mangrove Sign", + "block.minecraft.mangrove_slab": "Mangrove Slab", + "block.minecraft.mangrove_stairs": "Mangrove Stairs", + "block.minecraft.mangrove_trapdoor": "Mangrove Trapdoor", + "block.minecraft.mangrove_wall_hanging_sign": "Mangrove Wall Hanging Sign", + "block.minecraft.mangrove_wall_sign": "Mangrove Wall Sign", + "block.minecraft.mangrove_wood": "Mangrove Wood", + "block.minecraft.medium_amethyst_bud": "Medium Amethyst Bud", + "block.minecraft.melon": "Melon", + "block.minecraft.melon_stem": "Melon Stem", + "block.minecraft.moss_block": "Moss Block", + "block.minecraft.moss_carpet": "Moss Carpet", + "block.minecraft.mossy_cobblestone": "Mossy Cobblestone", + "block.minecraft.mossy_cobblestone_slab": "Mossy Cobblestone Slab", + "block.minecraft.mossy_cobblestone_stairs": "Mossy Cobblestone Stairs", + "block.minecraft.mossy_cobblestone_wall": "Mossy Cobblestone Wall", + "block.minecraft.mossy_stone_brick_slab": "Mossy Stone Brick Slab", + "block.minecraft.mossy_stone_brick_stairs": "Mossy Stone Brick Stairs", + "block.minecraft.mossy_stone_brick_wall": "Mossy Stone Brick Wall", + "block.minecraft.mossy_stone_bricks": "Mossy Stone Bricks", + "block.minecraft.moving_piston": "Moving Piston", + "block.minecraft.mud": "Mud", + "block.minecraft.mud_brick_slab": "Mud Brick Slab", + "block.minecraft.mud_brick_stairs": "Mud Brick Stairs", + "block.minecraft.mud_brick_wall": "Mud Brick Wall", + "block.minecraft.mud_bricks": "Mud Bricks", + "block.minecraft.muddy_mangrove_roots": "Muddy Mangrove Roots", + "block.minecraft.mushroom_stem": "Mushroom Stem", + "block.minecraft.mycelium": "Mycelium", + "block.minecraft.nether_brick_fence": "Nether Brick Fence", + "block.minecraft.nether_brick_slab": "Nether Brick Slab", + "block.minecraft.nether_brick_stairs": "Nether Brick Stairs", + "block.minecraft.nether_brick_wall": "Nether Brick Wall", + "block.minecraft.nether_bricks": "Nether Bricks", + "block.minecraft.nether_gold_ore": "Nether Gold Ore", + "block.minecraft.nether_portal": "Nether Portal", + "block.minecraft.nether_quartz_ore": "Nether Quartz Ore", + "block.minecraft.nether_sprouts": "Nether Sprouts", + "block.minecraft.nether_wart": "Nether Wart", + "block.minecraft.nether_wart_block": "Nether Wart Block", + "block.minecraft.netherite_block": "Block of Netherite", + "block.minecraft.netherrack": "Netherrack", + "block.minecraft.note_block": "Note Block", + "block.minecraft.oak_button": "Oak Button", + "block.minecraft.oak_door": "Oak Door", + "block.minecraft.oak_fence": "Oak Fence", + "block.minecraft.oak_fence_gate": "Oak Fence Gate", + "block.minecraft.oak_hanging_sign": "Oak Hanging Sign", + "block.minecraft.oak_leaves": "Oak Leaves", + "block.minecraft.oak_log": "Oak Log", + "block.minecraft.oak_planks": "Oak Planks", + "block.minecraft.oak_pressure_plate": "Oak Pressure Plate", + "block.minecraft.oak_sapling": "Oak Sapling", + "block.minecraft.oak_sign": "Oak Sign", + "block.minecraft.oak_slab": "Oak Slab", + "block.minecraft.oak_stairs": "Oak Stairs", + "block.minecraft.oak_trapdoor": "Oak Trapdoor", + "block.minecraft.oak_wall_hanging_sign": "Oak Wall Hanging Sign", + "block.minecraft.oak_wall_sign": "Oak Wall Sign", + "block.minecraft.oak_wood": "Oak Wood", + "block.minecraft.observer": "Observer", + "block.minecraft.obsidian": "Obsidian", + "block.minecraft.ochre_froglight": "Ochre Froglight", + "block.minecraft.ominous_banner": "Ominous Banner", + "block.minecraft.orange_banner": "Orange Banner", + "block.minecraft.orange_bed": "Orange Bed", + "block.minecraft.orange_candle": "Orange Candle", + "block.minecraft.orange_candle_cake": "Cake with Orange Candle", + "block.minecraft.orange_carpet": "Orange Carpet", + "block.minecraft.orange_concrete": "Orange Concrete", + "block.minecraft.orange_concrete_powder": "Orange Concrete Powder", + "block.minecraft.orange_glazed_terracotta": "Orange Glazed Terracotta", + "block.minecraft.orange_shulker_box": "Orange Shulker Box", + "block.minecraft.orange_stained_glass": "Orange Stained Glass", + "block.minecraft.orange_stained_glass_pane": "Orange Stained Glass Pane", + "block.minecraft.orange_terracotta": "Orange Terracotta", + "block.minecraft.orange_tulip": "Orange Tulip", + "block.minecraft.orange_wool": "Orange Wool", + "block.minecraft.oxeye_daisy": "Oxeye Daisy", + "block.minecraft.oxidized_chiseled_copper": "Oxidized Chiseled Copper", + "block.minecraft.oxidized_copper": "Oxidized Copper", + "block.minecraft.oxidized_copper_bulb": "Oxidized Copper Bulb", + "block.minecraft.oxidized_copper_door": "Oxidized Copper Door", + "block.minecraft.oxidized_copper_grate": "Oxidized Copper Grate", + "block.minecraft.oxidized_copper_trapdoor": "Oxidized Copper Trapdoor", + "block.minecraft.oxidized_cut_copper": "Oxidized Cut Copper", + "block.minecraft.oxidized_cut_copper_slab": "Oxidized Cut Copper Slab", + "block.minecraft.oxidized_cut_copper_stairs": "Oxidized Cut Copper Stairs", + "block.minecraft.packed_ice": "Packed Ice", + "block.minecraft.packed_mud": "Packed Mud", + "block.minecraft.pearlescent_froglight": "Pearlescent Froglight", + "block.minecraft.peony": "Peony", + "block.minecraft.petrified_oak_slab": "Petrified Oak Slab", + "block.minecraft.piglin_head": "Piglin Head", + "block.minecraft.piglin_wall_head": "Piglin Wall Head", + "block.minecraft.pink_banner": "Pink Banner", + "block.minecraft.pink_bed": "Pink Bed", + "block.minecraft.pink_candle": "Pink Candle", + "block.minecraft.pink_candle_cake": "Cake with Pink Candle", + "block.minecraft.pink_carpet": "Pink Carpet", + "block.minecraft.pink_concrete": "Pink Concrete", + "block.minecraft.pink_concrete_powder": "Pink Concrete Powder", + "block.minecraft.pink_glazed_terracotta": "Pink Glazed Terracotta", + "block.minecraft.pink_petals": "Pink Petals", + "block.minecraft.pink_shulker_box": "Pink Shulker Box", + "block.minecraft.pink_stained_glass": "Pink Stained Glass", + "block.minecraft.pink_stained_glass_pane": "Pink Stained Glass Pane", + "block.minecraft.pink_terracotta": "Pink Terracotta", + "block.minecraft.pink_tulip": "Pink Tulip", + "block.minecraft.pink_wool": "Pink Wool", + "block.minecraft.piston": "Piston", + "block.minecraft.piston_head": "Piston Head", + "block.minecraft.pitcher_crop": "Pitcher Crop", + "block.minecraft.pitcher_plant": "Pitcher Plant", + "block.minecraft.player_head": "Player Head", + "block.minecraft.player_head.named": "%s's Head", + "block.minecraft.player_wall_head": "Player Wall Head", + "block.minecraft.podzol": "Podzol", + "block.minecraft.pointed_dripstone": "Pointed Dripstone", + "block.minecraft.polished_andesite": "Polished Andesite", + "block.minecraft.polished_andesite_slab": "Polished Andesite Slab", + "block.minecraft.polished_andesite_stairs": "Polished Andesite Stairs", + "block.minecraft.polished_basalt": "Polished Basalt", + "block.minecraft.polished_blackstone": "Polished Blackstone", + "block.minecraft.polished_blackstone_brick_slab": "Polished Blackstone Brick Slab", + "block.minecraft.polished_blackstone_brick_stairs": "Polished Blackstone Brick Stairs", + "block.minecraft.polished_blackstone_brick_wall": "Polished Blackstone Brick Wall", + "block.minecraft.polished_blackstone_bricks": "Polished Blackstone Bricks", + "block.minecraft.polished_blackstone_button": "Polished Blackstone Button", + "block.minecraft.polished_blackstone_pressure_plate": "Polished Blackstone Pressure Plate", + "block.minecraft.polished_blackstone_slab": "Polished Blackstone Slab", + "block.minecraft.polished_blackstone_stairs": "Polished Blackstone Stairs", + "block.minecraft.polished_blackstone_wall": "Polished Blackstone Wall", + "block.minecraft.polished_deepslate": "Polished Deepslate", + "block.minecraft.polished_deepslate_slab": "Polished Deepslate Slab", + "block.minecraft.polished_deepslate_stairs": "Polished Deepslate Stairs", + "block.minecraft.polished_deepslate_wall": "Polished Deepslate Wall", + "block.minecraft.polished_diorite": "Polished Diorite", + "block.minecraft.polished_diorite_slab": "Polished Diorite Slab", + "block.minecraft.polished_diorite_stairs": "Polished Diorite Stairs", + "block.minecraft.polished_granite": "Polished Granite", + "block.minecraft.polished_granite_slab": "Polished Granite Slab", + "block.minecraft.polished_granite_stairs": "Polished Granite Stairs", + "block.minecraft.polished_tuff": "Polished Tuff", + "block.minecraft.polished_tuff_slab": "Polished Tuff Slab", + "block.minecraft.polished_tuff_stairs": "Polished Tuff Stairs", + "block.minecraft.polished_tuff_wall": "Polished Tuff Wall", + "block.minecraft.poppy": "Poppy", + "block.minecraft.potatoes": "Potatoes", + "block.minecraft.potted_acacia_sapling": "Potted Acacia Sapling", + "block.minecraft.potted_allium": "Potted Allium", + "block.minecraft.potted_azalea_bush": "Potted Azalea", + "block.minecraft.potted_azure_bluet": "Potted Azure Bluet", + "block.minecraft.potted_bamboo": "Potted Bamboo", + "block.minecraft.potted_birch_sapling": "Potted Birch Sapling", + "block.minecraft.potted_blue_orchid": "Potted Blue Orchid", + "block.minecraft.potted_brown_mushroom": "Potted Brown Mushroom", + "block.minecraft.potted_cactus": "Potted Cactus", + "block.minecraft.potted_cherry_sapling": "Potted Cherry Sapling", + "block.minecraft.potted_cornflower": "Potted Cornflower", + "block.minecraft.potted_crimson_fungus": "Potted Crimson Fungus", + "block.minecraft.potted_crimson_roots": "Potted Crimson Roots", + "block.minecraft.potted_dandelion": "Potted Dandelion", + "block.minecraft.potted_dark_oak_sapling": "Potted Dark Oak Sapling", + "block.minecraft.potted_dead_bush": "Potted Dead Bush", + "block.minecraft.potted_fern": "Potted Fern", + "block.minecraft.potted_flowering_azalea_bush": "Potted Flowering Azalea", + "block.minecraft.potted_jungle_sapling": "Potted Jungle Sapling", + "block.minecraft.potted_lily_of_the_valley": "Potted Lily of the Valley", + "block.minecraft.potted_mangrove_propagule": "Potted Mangrove Propagule", + "block.minecraft.potted_oak_sapling": "Potted Oak Sapling", + "block.minecraft.potted_orange_tulip": "Potted Orange Tulip", + "block.minecraft.potted_oxeye_daisy": "Potted Oxeye Daisy", + "block.minecraft.potted_pink_tulip": "Potted Pink Tulip", + "block.minecraft.potted_poppy": "Potted Poppy", + "block.minecraft.potted_red_mushroom": "Potted Red Mushroom", + "block.minecraft.potted_red_tulip": "Potted Red Tulip", + "block.minecraft.potted_spruce_sapling": "Potted Spruce Sapling", + "block.minecraft.potted_torchflower": "Potted Torchflower", + "block.minecraft.potted_warped_fungus": "Potted Warped Fungus", + "block.minecraft.potted_warped_roots": "Potted Warped Roots", + "block.minecraft.potted_white_tulip": "Potted White Tulip", + "block.minecraft.potted_wither_rose": "Potted Wither Rose", + "block.minecraft.powder_snow": "Powder Snow", + "block.minecraft.powder_snow_cauldron": "Powder Snow Cauldron", + "block.minecraft.powered_rail": "Powered Rail", + "block.minecraft.prismarine": "Prismarine", + "block.minecraft.prismarine_brick_slab": "Prismarine Brick Slab", + "block.minecraft.prismarine_brick_stairs": "Prismarine Brick Stairs", + "block.minecraft.prismarine_bricks": "Prismarine Bricks", + "block.minecraft.prismarine_slab": "Prismarine Slab", + "block.minecraft.prismarine_stairs": "Prismarine Stairs", + "block.minecraft.prismarine_wall": "Prismarine Wall", + "block.minecraft.pumpkin": "Pumpkin", + "block.minecraft.pumpkin_stem": "Pumpkin Stem", + "block.minecraft.purple_banner": "Purple Banner", + "block.minecraft.purple_bed": "Purple Bed", + "block.minecraft.purple_candle": "Purple Candle", + "block.minecraft.purple_candle_cake": "Cake with Purple Candle", + "block.minecraft.purple_carpet": "Purple Carpet", + "block.minecraft.purple_concrete": "Purple Concrete", + "block.minecraft.purple_concrete_powder": "Purple Concrete Powder", + "block.minecraft.purple_glazed_terracotta": "Purple Glazed Terracotta", + "block.minecraft.purple_shulker_box": "Purple Shulker Box", + "block.minecraft.purple_stained_glass": "Purple Stained Glass", + "block.minecraft.purple_stained_glass_pane": "Purple Stained Glass Pane", + "block.minecraft.purple_terracotta": "Purple Terracotta", + "block.minecraft.purple_wool": "Purple Wool", + "block.minecraft.purpur_block": "Purpur Block", + "block.minecraft.purpur_pillar": "Purpur Pillar", + "block.minecraft.purpur_slab": "Purpur Slab", + "block.minecraft.purpur_stairs": "Purpur Stairs", + "block.minecraft.quartz_block": "Block of Quartz", + "block.minecraft.quartz_bricks": "Quartz Bricks", + "block.minecraft.quartz_pillar": "Quartz Pillar", + "block.minecraft.quartz_slab": "Quartz Slab", + "block.minecraft.quartz_stairs": "Quartz Stairs", + "block.minecraft.rail": "Rail", + "block.minecraft.raw_copper_block": "Block of Raw Copper", + "block.minecraft.raw_gold_block": "Block of Raw Gold", + "block.minecraft.raw_iron_block": "Block of Raw Iron", + "block.minecraft.red_banner": "Red Banner", + "block.minecraft.red_bed": "Red Bed", + "block.minecraft.red_candle": "Red Candle", + "block.minecraft.red_candle_cake": "Cake with Red Candle", + "block.minecraft.red_carpet": "Red Carpet", + "block.minecraft.red_concrete": "Red Concrete", + "block.minecraft.red_concrete_powder": "Red Concrete Powder", + "block.minecraft.red_glazed_terracotta": "Red Glazed Terracotta", + "block.minecraft.red_mushroom": "Red Mushroom", + "block.minecraft.red_mushroom_block": "Red Mushroom Block", + "block.minecraft.red_nether_brick_slab": "Red Nether Brick Slab", + "block.minecraft.red_nether_brick_stairs": "Red Nether Brick Stairs", + "block.minecraft.red_nether_brick_wall": "Red Nether Brick Wall", + "block.minecraft.red_nether_bricks": "Red Nether Bricks", + "block.minecraft.red_sand": "Red Sand", + "block.minecraft.red_sandstone": "Red Sandstone", + "block.minecraft.red_sandstone_slab": "Red Sandstone Slab", + "block.minecraft.red_sandstone_stairs": "Red Sandstone Stairs", + "block.minecraft.red_sandstone_wall": "Red Sandstone Wall", + "block.minecraft.red_shulker_box": "Red Shulker Box", + "block.minecraft.red_stained_glass": "Red Stained Glass", + "block.minecraft.red_stained_glass_pane": "Red Stained Glass Pane", + "block.minecraft.red_terracotta": "Red Terracotta", + "block.minecraft.red_tulip": "Red Tulip", + "block.minecraft.red_wool": "Red Wool", + "block.minecraft.redstone_block": "Block of Redstone", + "block.minecraft.redstone_lamp": "Redstone Lamp", + "block.minecraft.redstone_ore": "Redstone Ore", + "block.minecraft.redstone_torch": "Redstone Torch", + "block.minecraft.redstone_wall_torch": "Redstone Wall Torch", + "block.minecraft.redstone_wire": "Redstone Wire", + "block.minecraft.reinforced_deepslate": "Reinforced Deepslate", + "block.minecraft.repeater": "Redstone Repeater", + "block.minecraft.repeating_command_block": "Repeating Command Block", + "block.minecraft.respawn_anchor": "Respawn Anchor", + "block.minecraft.rooted_dirt": "Rooted Dirt", + "block.minecraft.rose_bush": "Rose Bush", + "block.minecraft.sand": "Sand", + "block.minecraft.sandstone": "Sandstone", + "block.minecraft.sandstone_slab": "Sandstone Slab", + "block.minecraft.sandstone_stairs": "Sandstone Stairs", + "block.minecraft.sandstone_wall": "Sandstone Wall", + "block.minecraft.scaffolding": "Scaffolding", + "block.minecraft.sculk": "Sculk", + "block.minecraft.sculk_catalyst": "Sculk Catalyst", + "block.minecraft.sculk_sensor": "Sculk Sensor", + "block.minecraft.sculk_shrieker": "Sculk Shrieker", + "block.minecraft.sculk_vein": "Sculk Vein", + "block.minecraft.sea_lantern": "Sea Lantern", + "block.minecraft.sea_pickle": "Sea Pickle", + "block.minecraft.seagrass": "Seagrass", + "block.minecraft.set_spawn": "Respawn point set", + "block.minecraft.short_grass": "Short Grass", + "block.minecraft.shroomlight": "Shroomlight", + "block.minecraft.shulker_box": "Shulker Box", + "block.minecraft.skeleton_skull": "Skeleton Skull", + "block.minecraft.skeleton_wall_skull": "Skeleton Wall Skull", + "block.minecraft.slime_block": "Slime Block", + "block.minecraft.small_amethyst_bud": "Small Amethyst Bud", + "block.minecraft.small_dripleaf": "Small Dripleaf", + "block.minecraft.smithing_table": "Smithing Table", + "block.minecraft.smoker": "Smoker", + "block.minecraft.smooth_basalt": "Smooth Basalt", + "block.minecraft.smooth_quartz": "Smooth Quartz Block", + "block.minecraft.smooth_quartz_slab": "Smooth Quartz Slab", + "block.minecraft.smooth_quartz_stairs": "Smooth Quartz Stairs", + "block.minecraft.smooth_red_sandstone": "Smooth Red Sandstone", + "block.minecraft.smooth_red_sandstone_slab": "Smooth Red Sandstone Slab", + "block.minecraft.smooth_red_sandstone_stairs": "Smooth Red Sandstone Stairs", + "block.minecraft.smooth_sandstone": "Smooth Sandstone", + "block.minecraft.smooth_sandstone_slab": "Smooth Sandstone Slab", + "block.minecraft.smooth_sandstone_stairs": "Smooth Sandstone Stairs", + "block.minecraft.smooth_stone": "Smooth Stone", + "block.minecraft.smooth_stone_slab": "Smooth Stone Slab", + "block.minecraft.sniffer_egg": "Sniffer Egg", + "block.minecraft.snow": "Snow", + "block.minecraft.snow_block": "Snow Block", + "block.minecraft.soul_campfire": "Soul Campfire", + "block.minecraft.soul_fire": "Soul Fire", + "block.minecraft.soul_lantern": "Soul Lantern", + "block.minecraft.soul_sand": "Soul Sand", + "block.minecraft.soul_soil": "Soul Soil", + "block.minecraft.soul_torch": "Soul Torch", + "block.minecraft.soul_wall_torch": "Soul Wall Torch", + "block.minecraft.spawn.not_valid": "You have no home bed or charged respawn anchor, or it was obstructed", + "block.minecraft.spawner": "Monster Spawner", + "block.minecraft.spawner.desc1": "Interact with Spawn Egg:", + "block.minecraft.spawner.desc2": "Sets Mob Type", + "block.minecraft.sponge": "Sponge", + "block.minecraft.spore_blossom": "Spore Blossom", + "block.minecraft.spruce_button": "Spruce Button", + "block.minecraft.spruce_door": "Spruce Door", + "block.minecraft.spruce_fence": "Spruce Fence", + "block.minecraft.spruce_fence_gate": "Spruce Fence Gate", + "block.minecraft.spruce_hanging_sign": "Spruce Hanging Sign", + "block.minecraft.spruce_leaves": "Spruce Leaves", + "block.minecraft.spruce_log": "Spruce Log", + "block.minecraft.spruce_planks": "Spruce Planks", + "block.minecraft.spruce_pressure_plate": "Spruce Pressure Plate", + "block.minecraft.spruce_sapling": "Spruce Sapling", + "block.minecraft.spruce_sign": "Spruce Sign", + "block.minecraft.spruce_slab": "Spruce Slab", + "block.minecraft.spruce_stairs": "Spruce Stairs", + "block.minecraft.spruce_trapdoor": "Spruce Trapdoor", + "block.minecraft.spruce_wall_hanging_sign": "Spruce Wall Hanging Sign", + "block.minecraft.spruce_wall_sign": "Spruce Wall Sign", + "block.minecraft.spruce_wood": "Spruce Wood", + "block.minecraft.sticky_piston": "Sticky Piston", + "block.minecraft.stone": "Stone", + "block.minecraft.stone_brick_slab": "Stone Brick Slab", + "block.minecraft.stone_brick_stairs": "Stone Brick Stairs", + "block.minecraft.stone_brick_wall": "Stone Brick Wall", + "block.minecraft.stone_bricks": "Stone Bricks", + "block.minecraft.stone_button": "Stone Button", + "block.minecraft.stone_pressure_plate": "Stone Pressure Plate", + "block.minecraft.stone_slab": "Stone Slab", + "block.minecraft.stone_stairs": "Stone Stairs", + "block.minecraft.stonecutter": "Stonecutter", + "block.minecraft.stripped_acacia_log": "Stripped Acacia Log", + "block.minecraft.stripped_acacia_wood": "Stripped Acacia Wood", + "block.minecraft.stripped_bamboo_block": "Block of Stripped Bamboo", + "block.minecraft.stripped_birch_log": "Stripped Birch Log", + "block.minecraft.stripped_birch_wood": "Stripped Birch Wood", + "block.minecraft.stripped_cherry_log": "Stripped Cherry Log", + "block.minecraft.stripped_cherry_wood": "Stripped Cherry Wood", + "block.minecraft.stripped_crimson_hyphae": "Stripped Crimson Hyphae", + "block.minecraft.stripped_crimson_stem": "Stripped Crimson Stem", + "block.minecraft.stripped_dark_oak_log": "Stripped Dark Oak Log", + "block.minecraft.stripped_dark_oak_wood": "Stripped Dark Oak Wood", + "block.minecraft.stripped_jungle_log": "Stripped Jungle Log", + "block.minecraft.stripped_jungle_wood": "Stripped Jungle Wood", + "block.minecraft.stripped_mangrove_log": "Stripped Mangrove Log", + "block.minecraft.stripped_mangrove_wood": "Stripped Mangrove Wood", + "block.minecraft.stripped_oak_log": "Stripped Oak Log", + "block.minecraft.stripped_oak_wood": "Stripped Oak Wood", + "block.minecraft.stripped_spruce_log": "Stripped Spruce Log", + "block.minecraft.stripped_spruce_wood": "Stripped Spruce Wood", + "block.minecraft.stripped_warped_hyphae": "Stripped Warped Hyphae", + "block.minecraft.stripped_warped_stem": "Stripped Warped Stem", + "block.minecraft.structure_block": "Structure Block", + "block.minecraft.structure_void": "Structure Void", + "block.minecraft.sugar_cane": "Sugar Cane", + "block.minecraft.sunflower": "Sunflower", + "block.minecraft.suspicious_gravel": "Suspicious Gravel", + "block.minecraft.suspicious_sand": "Suspicious Sand", + "block.minecraft.sweet_berry_bush": "Sweet Berry Bush", + "block.minecraft.tall_grass": "Tall Grass", + "block.minecraft.tall_seagrass": "Tall Seagrass", + "block.minecraft.target": "Target", + "block.minecraft.terracotta": "Terracotta", + "block.minecraft.tinted_glass": "Tinted Glass", + "block.minecraft.tnt": "TNT", + "block.minecraft.torch": "Torch", + "block.minecraft.torchflower": "Torchflower", + "block.minecraft.torchflower_crop": "Torchflower Crop", + "block.minecraft.trapped_chest": "Trapped Chest", + "block.minecraft.trial_spawner": "Trial Spawner", + "block.minecraft.tripwire": "Tripwire", + "block.minecraft.tripwire_hook": "Tripwire Hook", + "block.minecraft.tube_coral": "Tube Coral", + "block.minecraft.tube_coral_block": "Tube Coral Block", + "block.minecraft.tube_coral_fan": "Tube Coral Fan", + "block.minecraft.tube_coral_wall_fan": "Tube Coral Wall Fan", + "block.minecraft.tuff": "Tuff", + "block.minecraft.tuff_brick_slab": "Tuff Brick Slab", + "block.minecraft.tuff_brick_stairs": "Tuff Brick Stairs", + "block.minecraft.tuff_brick_wall": "Tuff Brick Wall", + "block.minecraft.tuff_bricks": "Tuff Bricks", + "block.minecraft.tuff_slab": "Tuff Slab", + "block.minecraft.tuff_stairs": "Tuff Stairs", + "block.minecraft.tuff_wall": "Tuff Wall", + "block.minecraft.turtle_egg": "Turtle Egg", + "block.minecraft.twisting_vines": "Twisting Vines", + "block.minecraft.twisting_vines_plant": "Twisting Vines Plant", + "block.minecraft.vault": "Vault", + "block.minecraft.verdant_froglight": "Verdant Froglight", + "block.minecraft.vine": "Vines", + "block.minecraft.void_air": "Void Air", + "block.minecraft.wall_torch": "Wall Torch", + "block.minecraft.warped_button": "Warped Button", + "block.minecraft.warped_door": "Warped Door", + "block.minecraft.warped_fence": "Warped Fence", + "block.minecraft.warped_fence_gate": "Warped Fence Gate", + "block.minecraft.warped_fungus": "Warped Fungus", + "block.minecraft.warped_hanging_sign": "Warped Hanging Sign", + "block.minecraft.warped_hyphae": "Warped Hyphae", + "block.minecraft.warped_nylium": "Warped Nylium", + "block.minecraft.warped_planks": "Warped Planks", + "block.minecraft.warped_pressure_plate": "Warped Pressure Plate", + "block.minecraft.warped_roots": "Warped Roots", + "block.minecraft.warped_sign": "Warped Sign", + "block.minecraft.warped_slab": "Warped Slab", + "block.minecraft.warped_stairs": "Warped Stairs", + "block.minecraft.warped_stem": "Warped Stem", + "block.minecraft.warped_trapdoor": "Warped Trapdoor", + "block.minecraft.warped_wall_hanging_sign": "Warped Wall Hanging Sign", + "block.minecraft.warped_wall_sign": "Warped Wall Sign", + "block.minecraft.warped_wart_block": "Warped Wart Block", + "block.minecraft.water": "Water", + "block.minecraft.water_cauldron": "Water Cauldron", + "block.minecraft.waxed_chiseled_copper": "Waxed Chiseled Copper", + "block.minecraft.waxed_copper_block": "Waxed Block of Copper", + "block.minecraft.waxed_copper_bulb": "Waxed Copper Bulb", + "block.minecraft.waxed_copper_door": "Waxed Copper Door", + "block.minecraft.waxed_copper_grate": "Waxed Copper Grate", + "block.minecraft.waxed_copper_trapdoor": "Waxed Copper Trapdoor", + "block.minecraft.waxed_cut_copper": "Waxed Cut Copper", + "block.minecraft.waxed_cut_copper_slab": "Waxed Cut Copper Slab", + "block.minecraft.waxed_cut_copper_stairs": "Waxed Cut Copper Stairs", + "block.minecraft.waxed_exposed_chiseled_copper": "Waxed Exposed Chiseled Copper", + "block.minecraft.waxed_exposed_copper": "Waxed Exposed Copper", + "block.minecraft.waxed_exposed_copper_bulb": "Waxed Exposed Copper Bulb", + "block.minecraft.waxed_exposed_copper_door": "Waxed Exposed Copper Door", + "block.minecraft.waxed_exposed_copper_grate": "Waxed Exposed Copper Grate", + "block.minecraft.waxed_exposed_copper_trapdoor": "Waxed Exposed Copper Trapdoor", + "block.minecraft.waxed_exposed_cut_copper": "Waxed Exposed Cut Copper", + "block.minecraft.waxed_exposed_cut_copper_slab": "Waxed Exposed Cut Copper Slab", + "block.minecraft.waxed_exposed_cut_copper_stairs": "Waxed Exposed Cut Copper Stairs", + "block.minecraft.waxed_oxidized_chiseled_copper": "Waxed Oxidized Chiseled Copper", + "block.minecraft.waxed_oxidized_copper": "Waxed Oxidized Copper", + "block.minecraft.waxed_oxidized_copper_bulb": "Waxed Oxidized Copper Bulb", + "block.minecraft.waxed_oxidized_copper_door": "Waxed Oxidized Copper Door", + "block.minecraft.waxed_oxidized_copper_grate": "Waxed Oxidized Copper Grate", + "block.minecraft.waxed_oxidized_copper_trapdoor": "Waxed Oxidized Copper Trapdoor", + "block.minecraft.waxed_oxidized_cut_copper": "Waxed Oxidized Cut Copper", + "block.minecraft.waxed_oxidized_cut_copper_slab": "Waxed Oxidized Cut Copper Slab", + "block.minecraft.waxed_oxidized_cut_copper_stairs": "Waxed Oxidized Cut Copper Stairs", + "block.minecraft.waxed_weathered_chiseled_copper": "Waxed Weathered Chiseled Copper", + "block.minecraft.waxed_weathered_copper": "Waxed Weathered Copper", + "block.minecraft.waxed_weathered_copper_bulb": "Waxed Weathered Copper Bulb", + "block.minecraft.waxed_weathered_copper_door": "Waxed Weathered Copper Door", + "block.minecraft.waxed_weathered_copper_grate": "Waxed Weathered Copper Grate", + "block.minecraft.waxed_weathered_copper_trapdoor": "Waxed Weathered Copper Trapdoor", + "block.minecraft.waxed_weathered_cut_copper": "Waxed Weathered Cut Copper", + "block.minecraft.waxed_weathered_cut_copper_slab": "Waxed Weathered Cut Copper Slab", + "block.minecraft.waxed_weathered_cut_copper_stairs": "Waxed Weathered Cut Copper Stairs", + "block.minecraft.weathered_chiseled_copper": "Weathered Chiseled Copper", + "block.minecraft.weathered_copper": "Weathered Copper", + "block.minecraft.weathered_copper_bulb": "Weathered Copper Bulb", + "block.minecraft.weathered_copper_door": "Weathered Copper Door", + "block.minecraft.weathered_copper_grate": "Weathered Copper Grate", + "block.minecraft.weathered_copper_trapdoor": "Weathered Copper Trapdoor", + "block.minecraft.weathered_cut_copper": "Weathered Cut Copper", + "block.minecraft.weathered_cut_copper_slab": "Weathered Cut Copper Slab", + "block.minecraft.weathered_cut_copper_stairs": "Weathered Cut Copper Stairs", + "block.minecraft.weeping_vines": "Weeping Vines", + "block.minecraft.weeping_vines_plant": "Weeping Vines Plant", + "block.minecraft.wet_sponge": "Wet Sponge", + "block.minecraft.wheat": "Wheat Crops", + "block.minecraft.white_banner": "White Banner", + "block.minecraft.white_bed": "White Bed", + "block.minecraft.white_candle": "White Candle", + "block.minecraft.white_candle_cake": "Cake with White Candle", + "block.minecraft.white_carpet": "White Carpet", + "block.minecraft.white_concrete": "White Concrete", + "block.minecraft.white_concrete_powder": "White Concrete Powder", + "block.minecraft.white_glazed_terracotta": "White Glazed Terracotta", + "block.minecraft.white_shulker_box": "White Shulker Box", + "block.minecraft.white_stained_glass": "White Stained Glass", + "block.minecraft.white_stained_glass_pane": "White Stained Glass Pane", + "block.minecraft.white_terracotta": "White Terracotta", + "block.minecraft.white_tulip": "White Tulip", + "block.minecraft.white_wool": "White Wool", + "block.minecraft.wither_rose": "Wither Rose", + "block.minecraft.wither_skeleton_skull": "Wither Skeleton Skull", + "block.minecraft.wither_skeleton_wall_skull": "Wither Skeleton Wall Skull", + "block.minecraft.yellow_banner": "Yellow Banner", + "block.minecraft.yellow_bed": "Yellow Bed", + "block.minecraft.yellow_candle": "Yellow Candle", + "block.minecraft.yellow_candle_cake": "Cake with Yellow Candle", + "block.minecraft.yellow_carpet": "Yellow Carpet", + "block.minecraft.yellow_concrete": "Yellow Concrete", + "block.minecraft.yellow_concrete_powder": "Yellow Concrete Powder", + "block.minecraft.yellow_glazed_terracotta": "Yellow Glazed Terracotta", + "block.minecraft.yellow_shulker_box": "Yellow Shulker Box", + "block.minecraft.yellow_stained_glass": "Yellow Stained Glass", + "block.minecraft.yellow_stained_glass_pane": "Yellow Stained Glass Pane", + "block.minecraft.yellow_terracotta": "Yellow Terracotta", + "block.minecraft.yellow_wool": "Yellow Wool", + "block.minecraft.zombie_head": "Zombie Head", + "block.minecraft.zombie_wall_head": "Zombie Wall Head", + "book.byAuthor": "by %1$s", + "book.editTitle": "Enter Book Title:", + "book.finalizeButton": "Sign and Close", + "book.finalizeWarning": "Note! When you sign the book, it will no longer be editable.", + "book.generation.0": "Original", + "book.generation.1": "Copy of original", + "book.generation.2": "Copy of a copy", + "book.generation.3": "Tattered", + "book.invalid.tag": "* Invalid book tag *", + "book.pageIndicator": "Page %1$s of %2$s", + "book.signButton": "Sign", + "build.tooHigh": "Height limit for building is %s", + "chat_screen.message": "Message to send: %s", + "chat_screen.title": "Chat screen", + "chat_screen.usage": "Input message and press Enter to send", + "chat.cannotSend": "Cannot send chat message", + "chat.coordinates": "%s, %s, %s", + "chat.coordinates.tooltip": "Click to teleport", + "chat.copy": "Copy to Clipboard", + "chat.copy.click": "Click to Copy to Clipboard", + "chat.deleted_marker": "This chat message has been deleted by the server.", + "chat.disabled.chain_broken": "Chat disabled due to broken chain. Please try reconnecting.", + "chat.disabled.expiredProfileKey": "Chat disabled due to expired profile public key. Please try reconnecting.", + "chat.disabled.invalid_command_signature": "Command had unexpected or missing command argument signatures.", + "chat.disabled.invalid_signature": "Chat had an invalid signature. Please try reconnecting.", + "chat.disabled.launcher": "Chat disabled by launcher option. Cannot send message.", + "chat.disabled.missingProfileKey": "Chat disabled due to missing profile public key. Please try reconnecting.", + "chat.disabled.options": "Chat disabled in client options.", + "chat.disabled.out_of_order_chat": "Chat received out-of-order. Did your system time change?", + "chat.disabled.profile": "Chat is not allowed by account settings. Press '%s' again for more information.", + "chat.disabled.profile.moreInfo": "Chat is not allowed by account settings. Cannot send or view messages.", + "chat.editBox": "chat", + "chat.filtered": "Filtered by the server.", + "chat.filtered_full": "The server has hidden your message for some players.", + "chat.link.confirm": "Are you sure you want to open the following website?", + "chat.link.confirmTrusted": "Do you want to open this link or copy it to your clipboard?", + "chat.link.open": "Open in Browser", + "chat.link.warning": "Never open links from people that you don't trust!", + "chat.queue": "[+%s pending lines]", + "chat.square_brackets": "[%s]", + "chat.tag.error": "Server sent invalid message.", + "chat.tag.modified": "Message modified by the server. Original:", + "chat.tag.not_secure": "Unverified message. Cannot be reported.", + "chat.tag.system": "Server message. Cannot be reported.", + "chat.tag.system_single_player": "Server message.", + "chat.type.admin": "[%s: %s]", + "chat.type.advancement.challenge": "%s has completed the challenge %s", + "chat.type.advancement.goal": "%s has reached the goal %s", + "chat.type.advancement.task": "%s has made the advancement %s", + "chat.type.announcement": "[%s] %s", + "chat.type.emote": "* %s %s", + "chat.type.team.hover": "Message Team", + "chat.type.team.sent": "-> %s <%s> %s", + "chat.type.team.text": "%s <%s> %s", + "chat.type.text": "<%s> %s", + "chat.type.text.narrate": "%s says %s", + "chat.validation_error": "Chat validation error", + "chunk.toast.checkLog": "See log for more details", + "chunk.toast.loadFailure": "Failed to load chunk at %s", + "chunk.toast.lowDiskSpace": "Low disk space!", + "chunk.toast.lowDiskSpace.description": "Might not be able to save the world.", + "chunk.toast.saveFailure": "Failed to save chunk at %s", + "clear.failed.multiple": "No items were found on %s players", + "clear.failed.single": "No items were found on player %s", + "color.minecraft.black": "Black", + "color.minecraft.blue": "Blue", + "color.minecraft.brown": "Brown", + "color.minecraft.cyan": "Cyan", + "color.minecraft.gray": "Gray", + "color.minecraft.green": "Green", + "color.minecraft.light_blue": "Light Blue", + "color.minecraft.light_gray": "Light Gray", + "color.minecraft.lime": "Lime", + "color.minecraft.magenta": "Magenta", + "color.minecraft.orange": "Orange", + "color.minecraft.pink": "Pink", + "color.minecraft.purple": "Purple", + "color.minecraft.red": "Red", + "color.minecraft.white": "White", + "color.minecraft.yellow": "Yellow", + "command.context.here": "<--[HERE]", + "command.context.parse_error": "%s at position %s: %s", + "command.exception": "Could not parse command: %s", + "command.expected.separator": "Expected whitespace to end one argument, but found trailing data", + "command.failed": "An unexpected error occurred trying to execute that command", + "command.forkLimit": "Maximum number of contexts (%s) reached", + "command.unknown.argument": "Incorrect argument for command", + "command.unknown.command": "Unknown or incomplete command, see below for error", + "commands.advancement.advancementNotFound": "No advancement was found by the name '%1$s'", + "commands.advancement.criterionNotFound": "The advancement %1$s does not contain the criterion '%2$s'", + "commands.advancement.grant.criterion.to.many.failure": "Couldn't grant criterion '%s' of advancement %s to %s players as they already have it", + "commands.advancement.grant.criterion.to.many.success": "Granted criterion '%s' of advancement %s to %s players", + "commands.advancement.grant.criterion.to.one.failure": "Couldn't grant criterion '%s' of advancement %s to %s as they already have it", + "commands.advancement.grant.criterion.to.one.success": "Granted criterion '%s' of advancement %s to %s", + "commands.advancement.grant.many.to.many.failure": "Couldn't grant %s advancements to %s players as they already have them", + "commands.advancement.grant.many.to.many.success": "Granted %s advancements to %s players", + "commands.advancement.grant.many.to.one.failure": "Couldn't grant %s advancements to %s as they already have them", + "commands.advancement.grant.many.to.one.success": "Granted %s advancements to %s", + "commands.advancement.grant.one.to.many.failure": "Couldn't grant advancement %s to %s players as they already have it", + "commands.advancement.grant.one.to.many.success": "Granted the advancement %s to %s players", + "commands.advancement.grant.one.to.one.failure": "Couldn't grant advancement %s to %s as they already have it", + "commands.advancement.grant.one.to.one.success": "Granted the advancement %s to %s", + "commands.advancement.revoke.criterion.to.many.failure": "Couldn't revoke criterion '%s' of advancement %s from %s players as they don't have it", + "commands.advancement.revoke.criterion.to.many.success": "Revoked criterion '%s' of advancement %s from %s players", + "commands.advancement.revoke.criterion.to.one.failure": "Couldn't revoke criterion '%s' of advancement %s from %s as they don't have it", + "commands.advancement.revoke.criterion.to.one.success": "Revoked criterion '%s' of advancement %s from %s", + "commands.advancement.revoke.many.to.many.failure": "Couldn't revoke %s advancements from %s players as they don't have them", + "commands.advancement.revoke.many.to.many.success": "Revoked %s advancements from %s players", + "commands.advancement.revoke.many.to.one.failure": "Couldn't revoke %s advancements from %s as they don't have them", + "commands.advancement.revoke.many.to.one.success": "Revoked %s advancements from %s", + "commands.advancement.revoke.one.to.many.failure": "Couldn't revoke advancement %s from %s players as they don't have it", + "commands.advancement.revoke.one.to.many.success": "Revoked the advancement %s from %s players", + "commands.advancement.revoke.one.to.one.failure": "Couldn't revoke advancement %s from %s as they don't have it", + "commands.advancement.revoke.one.to.one.success": "Revoked the advancement %s from %s", + "commands.attribute.base_value.get.success": "Base value of attribute %s for entity %s is %s", + "commands.attribute.base_value.set.success": "Base value for attribute %s for entity %s set to %s", + "commands.attribute.failed.entity": "%s is not a valid entity for this command", + "commands.attribute.failed.modifier_already_present": "Modifier %s is already present on attribute %s for entity %s", + "commands.attribute.failed.no_attribute": "Entity %s has no attribute %s", + "commands.attribute.failed.no_modifier": "Attribute %s for entity %s has no modifier %s", + "commands.attribute.modifier.add.success": "Added modifier %s to attribute %s for entity %s", + "commands.attribute.modifier.remove.success": "Removed modifier %s from attribute %s for entity %s", + "commands.attribute.modifier.value.get.success": "Value of modifier %s on attribute %s for entity %s is %s", + "commands.attribute.value.get.success": "Value of attribute %s for entity %s is %s", + "commands.ban.failed": "Nothing changed. The player is already banned", + "commands.ban.success": "Banned %s: %s", + "commands.banip.failed": "Nothing changed. That IP is already banned", + "commands.banip.info": "This ban affects %s player(s): %s", + "commands.banip.invalid": "Invalid IP address or unknown player", + "commands.banip.success": "Banned IP %s: %s", + "commands.banlist.entry": "%s was banned by %s: %s", + "commands.banlist.entry.unknown": "(Unknown)", + "commands.banlist.list": "There are %s ban(s):", + "commands.banlist.none": "There are no bans", + "commands.bossbar.create.failed": "A bossbar already exists with the ID '%s'", + "commands.bossbar.create.success": "Created custom bossbar %s", + "commands.bossbar.get.max": "Custom bossbar %s has a maximum of %s", + "commands.bossbar.get.players.none": "Custom bossbar %s has no players currently online", + "commands.bossbar.get.players.some": "Custom bossbar %s has %s player(s) currently online: %s", + "commands.bossbar.get.value": "Custom bossbar %s has a value of %s", + "commands.bossbar.get.visible.hidden": "Custom bossbar %s is currently hidden", + "commands.bossbar.get.visible.visible": "Custom bossbar %s is currently shown", + "commands.bossbar.list.bars.none": "There are no custom bossbars active", + "commands.bossbar.list.bars.some": "There are %s custom bossbar(s) active: %s", + "commands.bossbar.remove.success": "Removed custom bossbar %s", + "commands.bossbar.set.color.success": "Custom bossbar %s has changed color", + "commands.bossbar.set.color.unchanged": "Nothing changed. That's already the color of this bossbar", + "commands.bossbar.set.max.success": "Custom bossbar %s has changed maximum to %s", + "commands.bossbar.set.max.unchanged": "Nothing changed. That's already the max of this bossbar", + "commands.bossbar.set.name.success": "Custom bossbar %s has been renamed", + "commands.bossbar.set.name.unchanged": "Nothing changed. That's already the name of this bossbar", + "commands.bossbar.set.players.success.none": "Custom bossbar %s no longer has any players", + "commands.bossbar.set.players.success.some": "Custom bossbar %s now has %s player(s): %s", + "commands.bossbar.set.players.unchanged": "Nothing changed. Those players are already on the bossbar with nobody to add or remove", + "commands.bossbar.set.style.success": "Custom bossbar %s has changed style", + "commands.bossbar.set.style.unchanged": "Nothing changed. That's already the style of this bossbar", + "commands.bossbar.set.value.success": "Custom bossbar %s has changed value to %s", + "commands.bossbar.set.value.unchanged": "Nothing changed. That's already the value of this bossbar", + "commands.bossbar.set.visibility.unchanged.hidden": "Nothing changed. The bossbar is already hidden", + "commands.bossbar.set.visibility.unchanged.visible": "Nothing changed. The bossbar is already visible", + "commands.bossbar.set.visible.success.hidden": "Custom bossbar %s is now hidden", + "commands.bossbar.set.visible.success.visible": "Custom bossbar %s is now visible", + "commands.bossbar.unknown": "No bossbar exists with the ID '%s'", + "commands.clear.success.multiple": "Removed %s item(s) from %s players", + "commands.clear.success.single": "Removed %s item(s) from player %s", + "commands.clear.test.multiple": "Found %s matching item(s) on %s players", + "commands.clear.test.single": "Found %s matching item(s) on player %s", + "commands.clone.failed": "No blocks were cloned", + "commands.clone.overlap": "The source and destination areas cannot overlap", + "commands.clone.success": "Successfully cloned %s block(s)", + "commands.clone.toobig": "Too many blocks in the specified area (maximum %s, specified %s)", + "commands.damage.invulnerable": "Target is invulnerable to the given damage type", + "commands.damage.success": "Applied %s damage to %s", + "commands.data.block.get": "%s on block %s, %s, %s after scale factor of %s is %s", + "commands.data.block.invalid": "The target block is not a block entity", + "commands.data.block.modified": "Modified block data of %s, %s, %s", + "commands.data.block.query": "%s, %s, %s has the following block data: %s", + "commands.data.entity.get": "%s on %s after scale factor of %s is %s", + "commands.data.entity.invalid": "Unable to modify player data", + "commands.data.entity.modified": "Modified entity data of %s", + "commands.data.entity.query": "%s has the following entity data: %s", + "commands.data.get.invalid": "Can't get %s; only numeric tags are allowed", + "commands.data.get.multiple": "This argument accepts a single NBT value", + "commands.data.get.unknown": "Can't get %s; tag doesn't exist", + "commands.data.merge.failed": "Nothing changed. The specified properties already have these values", + "commands.data.modify.expected_list": "Expected list, got: %s", + "commands.data.modify.expected_object": "Expected object, got: %s", + "commands.data.modify.expected_value": "Expected value, got: %s", + "commands.data.modify.invalid_index": "Invalid list index: %s", + "commands.data.modify.invalid_substring": "Invalid substring indices: %s to %s", + "commands.data.storage.get": "%s in storage %s after scale factor of %s is %s", + "commands.data.storage.modified": "Modified storage %s", + "commands.data.storage.query": "Storage %s has the following contents: %s", + "commands.datapack.disable.failed": "Pack '%s' is not enabled!", + "commands.datapack.disable.failed.feature": "Pack '%s' cannot be disabled, since it is part of an enabled flag!", + "commands.datapack.enable.failed": "Pack '%s' is already enabled!", + "commands.datapack.enable.failed.no_flags": "Pack '%s' cannot be enabled, since required flags are not enabled in this world: %s!", + "commands.datapack.list.available.none": "There are no more data packs available", + "commands.datapack.list.available.success": "There are %s data pack(s) available: %s", + "commands.datapack.list.enabled.none": "There are no data packs enabled", + "commands.datapack.list.enabled.success": "There are %s data pack(s) enabled: %s", + "commands.datapack.modify.disable": "Disabling data pack %s", + "commands.datapack.modify.enable": "Enabling data pack %s", + "commands.datapack.unknown": "Unknown data pack '%s'", + "commands.debug.alreadyRunning": "The tick profiler is already started", + "commands.debug.function.noRecursion": "Can't trace from inside of function", + "commands.debug.function.noReturnRun": "Tracing can't be used with return run", + "commands.debug.function.success.multiple": "Traced %s command(s) from %s functions to output file %s", + "commands.debug.function.success.single": "Traced %s command(s) from function '%s' to output file %s", + "commands.debug.function.traceFailed": "Failed to trace function", + "commands.debug.notRunning": "The tick profiler hasn't started", + "commands.debug.started": "Started tick profiling", + "commands.debug.stopped": "Stopped tick profiling after %s seconds and %s ticks (%s ticks per second)", + "commands.defaultgamemode.success": "The default game mode is now %s", + "commands.deop.failed": "Nothing changed. The player is not an operator", + "commands.deop.success": "Made %s no longer a server operator", + "commands.difficulty.failure": "The difficulty did not change; it is already set to %s", + "commands.difficulty.query": "The difficulty is %s", + "commands.difficulty.success": "The difficulty has been set to %s", + "commands.drop.no_held_items": "Entity can't hold any items", + "commands.drop.no_loot_table": "Entity %s has no loot table", + "commands.drop.success.multiple": "Dropped %s items", + "commands.drop.success.multiple_with_table": "Dropped %s items from loot table %s", + "commands.drop.success.single": "Dropped %s %s", + "commands.drop.success.single_with_table": "Dropped %s %s from loot table %s", + "commands.effect.clear.everything.failed": "Target has no effects to remove", + "commands.effect.clear.everything.success.multiple": "Removed every effect from %s targets", + "commands.effect.clear.everything.success.single": "Removed every effect from %s", + "commands.effect.clear.specific.failed": "Target doesn't have the requested effect", + "commands.effect.clear.specific.success.multiple": "Removed effect %s from %s targets", + "commands.effect.clear.specific.success.single": "Removed effect %s from %s", + "commands.effect.give.failed": "Unable to apply this effect (target is either immune to effects, or has something stronger)", + "commands.effect.give.success.multiple": "Applied effect %s to %s targets", + "commands.effect.give.success.single": "Applied effect %s to %s", + "commands.enchant.failed": "Nothing changed. Targets either have no item in their hands or the enchantment could not be applied", + "commands.enchant.failed.entity": "%s is not a valid entity for this command", + "commands.enchant.failed.incompatible": "%s cannot support that enchantment", + "commands.enchant.failed.itemless": "%s is not holding any item", + "commands.enchant.failed.level": "%s is higher than the maximum level of %s supported by that enchantment", + "commands.enchant.success.multiple": "Applied enchantment %s to %s entities", + "commands.enchant.success.single": "Applied enchantment %s to %s's item", + "commands.execute.blocks.toobig": "Too many blocks in the specified area (maximum %s, specified %s)", + "commands.execute.conditional.fail": "Test failed", + "commands.execute.conditional.fail_count": "Test failed, count: %s", + "commands.execute.conditional.pass": "Test passed", + "commands.execute.conditional.pass_count": "Test passed, count: %s", + "commands.execute.function.instantiationFailure": "Failed to instantiate function %s: %s", + "commands.experience.add.levels.success.multiple": "Gave %s experience levels to %s players", + "commands.experience.add.levels.success.single": "Gave %s experience levels to %s", + "commands.experience.add.points.success.multiple": "Gave %s experience points to %s players", + "commands.experience.add.points.success.single": "Gave %s experience points to %s", + "commands.experience.query.levels": "%s has %s experience levels", + "commands.experience.query.points": "%s has %s experience points", + "commands.experience.set.levels.success.multiple": "Set %s experience levels on %s players", + "commands.experience.set.levels.success.single": "Set %s experience levels on %s", + "commands.experience.set.points.invalid": "Cannot set experience points above the maximum points for the player's current level", + "commands.experience.set.points.success.multiple": "Set %s experience points on %s players", + "commands.experience.set.points.success.single": "Set %s experience points on %s", + "commands.fill.failed": "No blocks were filled", + "commands.fill.success": "Successfully filled %s block(s)", + "commands.fill.toobig": "Too many blocks in the specified area (maximum %s, specified %s)", + "commands.fillbiome.success": "Biomes set between %s, %s, %s and %s, %s, %s", + "commands.fillbiome.success.count": "%s biome entry/entries set between %s, %s, %s and %s, %s, %s", + "commands.fillbiome.toobig": "Too many blocks in the specified volume (maximum %s, specified %s)", + "commands.forceload.added.failure": "No chunks were marked for force loading", + "commands.forceload.added.multiple": "Marked %s chunks in %s from %s to %s to be force loaded", + "commands.forceload.added.none": "No force loaded chunks were found in %s", + "commands.forceload.added.single": "Marked chunk %s in %s to be force loaded", + "commands.forceload.list.multiple": "%s force loaded chunks were found in %s at: %s", + "commands.forceload.list.single": "A force loaded chunk was found in %s at: %s", + "commands.forceload.query.failure": "Chunk at %s in %s is not marked for force loading", + "commands.forceload.query.success": "Chunk at %s in %s is marked for force loading", + "commands.forceload.removed.all": "Unmarked all force loaded chunks in %s", + "commands.forceload.removed.failure": "No chunks were removed from force loading", + "commands.forceload.removed.multiple": "Unmarked %s chunks in %s from %s to %s for force loading", + "commands.forceload.removed.single": "Unmarked chunk %s in %s for force loading", + "commands.forceload.toobig": "Too many chunks in the specified area (maximum %s, specified %s)", + "commands.function.error.argument_not_compound": "Invalid argument type: %s, expected Compound", + "commands.function.error.missing_argument": "Missing argument %2$s to function %1$s", + "commands.function.error.missing_arguments": "Missing arguments to function %s", + "commands.function.error.parse": "While instantiating macro %s: Command '%s' caused error: %s", + "commands.function.instantiationFailure": "Failed to instantiate function %s: %s", + "commands.function.result": "Function %s returned %s", + "commands.function.scheduled.multiple": "Running functions %s", + "commands.function.scheduled.no_functions": "Can't find any functions for name %s", + "commands.function.scheduled.single": "Running function %s", + "commands.function.success.multiple": "Executed %s command(s) from %s functions", + "commands.function.success.multiple.result": "Executed %s functions", + "commands.function.success.single": "Executed %s command(s) from function '%s'", + "commands.function.success.single.result": "Function '%2$s' returned %1$s", + "commands.gamemode.success.other": "Set %s's game mode to %s", + "commands.gamemode.success.self": "Set own game mode to %s", + "commands.gamerule.query": "Gamerule %s is currently set to: %s", + "commands.gamerule.set": "Gamerule %s is now set to: %s", + "commands.give.failed.toomanyitems": "Can't give more than %s of %s", + "commands.give.success.multiple": "Gave %s %s to %s players", + "commands.give.success.single": "Gave %s %s to %s", + "commands.help.failed": "Unknown command or insufficient permissions", + "commands.item.block.set.success": "Replaced a slot at %s, %s, %s with %s", + "commands.item.entity.set.success.multiple": "Replaced a slot on %s entities with %s", + "commands.item.entity.set.success.single": "Replaced a slot on %s with %s", + "commands.item.source.no_such_slot": "The source does not have slot %s", + "commands.item.source.not_a_container": "Source position %s, %s, %s is not a container", + "commands.item.target.no_changed.known_item": "No targets accepted item %s into slot %s", + "commands.item.target.no_changes": "No targets accepted item into slot %s", + "commands.item.target.no_such_slot": "The target does not have slot %s", + "commands.item.target.not_a_container": "Target position %s, %s, %s is not a container", + "commands.jfr.dump.failed": "Failed to dump JFR recording: %s", + "commands.jfr.start.failed": "Failed to start JFR profiling", + "commands.jfr.started": "JFR profiling started", + "commands.jfr.stopped": "JFR profiling stopped and dumped to %s", + "commands.kick.owner.failed": "Cannot kick server owner in LAN game", + "commands.kick.singleplayer.failed": "Cannot kick in an offline singleplayer game", + "commands.kick.success": "Kicked %s: %s", + "commands.kill.success.multiple": "Killed %s entities", + "commands.kill.success.single": "Killed %s", + "commands.list.nameAndId": "%s (%s)", + "commands.list.players": "There are %s of a max of %s players online: %s", + "commands.locate.biome.not_found": "Could not find a biome of type \"%s\" within reasonable distance", + "commands.locate.biome.success": "The nearest %s is at %s (%s blocks away)", + "commands.locate.poi.not_found": "Could not find a point of interest of type \"%s\" within reasonable distance", + "commands.locate.poi.success": "The nearest %s is at %s (%s blocks away)", + "commands.locate.structure.invalid": "There is no structure with type \"%s\"", + "commands.locate.structure.not_found": "Could not find a structure of type \"%s\" nearby", + "commands.locate.structure.success": "The nearest %s is at %s (%s blocks away)", + "commands.message.display.incoming": "%s whispers to you: %s", + "commands.message.display.outgoing": "You whisper to %s: %s", + "commands.op.failed": "Nothing changed. The player already is an operator", + "commands.op.success": "Made %s a server operator", + "commands.pardon.failed": "Nothing changed. The player isn't banned", + "commands.pardon.success": "Unbanned %s", + "commands.pardonip.failed": "Nothing changed. That IP isn't banned", + "commands.pardonip.invalid": "Invalid IP address", + "commands.pardonip.success": "Unbanned IP %s", + "commands.particle.failed": "The particle was not visible for anybody", + "commands.particle.success": "Displaying particle %s", + "commands.perf.alreadyRunning": "The performance profiler is already started", + "commands.perf.notRunning": "The performance profiler hasn't started", + "commands.perf.reportFailed": "Failed to create debug report", + "commands.perf.reportSaved": "Created debug report in %s", + "commands.perf.started": "Started 10 second performance profiling run (use '/perf stop' to stop early)", + "commands.perf.stopped": "Stopped performance profiling after %s second(s) and %s tick(s) (%s tick(s) per second)", + "commands.place.feature.failed": "Failed to place feature", + "commands.place.feature.invalid": "There is no feature with type \"%s\"", + "commands.place.feature.success": "Placed \"%s\" at %s, %s, %s", + "commands.place.jigsaw.failed": "Failed to generate jigsaw", + "commands.place.jigsaw.invalid": "There is no template pool with type \"%s\"", + "commands.place.jigsaw.success": "Generated jigsaw at %s, %s, %s", + "commands.place.structure.failed": "Failed to place structure", + "commands.place.structure.invalid": "There is no structure with type \"%s\"", + "commands.place.structure.success": "Generated structure \"%s\" at %s, %s, %s", + "commands.place.template.failed": "Failed to place template", + "commands.place.template.invalid": "There is no template with id \"%s\"", + "commands.place.template.success": "Loaded template \"%s\" at %s, %s, %s", + "commands.playsound.failed": "The sound is too far away to be heard", + "commands.playsound.success.multiple": "Played sound %s to %s players", + "commands.playsound.success.single": "Played sound %s to %s", + "commands.publish.alreadyPublished": "Multiplayer game is already hosted on port %s", + "commands.publish.failed": "Unable to host local game", + "commands.publish.started": "Local game hosted on port %s", + "commands.publish.success": "Multiplayer game is now hosted on port %s", + "commands.random.error.range_too_large": "The range of the random value must be at most 2147483646", + "commands.random.error.range_too_small": "The range of the random value must be at least 2", + "commands.random.reset.all.success": "Reset %s random sequence(s)", + "commands.random.reset.success": "Reset random sequence %s", + "commands.random.roll": "%s rolled %s (from %s to %s)", + "commands.random.sample.success": "Randomized value: %s", + "commands.recipe.give.failed": "No new recipes were learned", + "commands.recipe.give.success.multiple": "Unlocked %s recipes for %s players", + "commands.recipe.give.success.single": "Unlocked %s recipes for %s", + "commands.recipe.take.failed": "No recipes could be forgotten", + "commands.recipe.take.success.multiple": "Took %s recipes from %s players", + "commands.recipe.take.success.single": "Took %s recipes from %s", + "commands.reload.failure": "Reload failed; keeping old data", + "commands.reload.success": "Reloading!", + "commands.ride.already_riding": "%s is already riding %s", + "commands.ride.dismount.success": "%s stopped riding %s", + "commands.ride.mount.failure.cant_ride_players": "Players can't be ridden", + "commands.ride.mount.failure.generic": "%s couldn't start riding %s", + "commands.ride.mount.failure.loop": "Can't mount entity on itself or any of its passengers", + "commands.ride.mount.failure.wrong_dimension": "Can't mount entity in different dimension", + "commands.ride.mount.success": "%s started riding %s", + "commands.ride.not_riding": "%s is not riding any vehicle", + "commands.save.alreadyOff": "Saving is already turned off", + "commands.save.alreadyOn": "Saving is already turned on", + "commands.save.disabled": "Automatic saving is now disabled", + "commands.save.enabled": "Automatic saving is now enabled", + "commands.save.failed": "Unable to save the game (is there enough disk space?)", + "commands.save.saving": "Saving the game (this may take a moment!)", + "commands.save.success": "Saved the game", + "commands.schedule.cleared.failure": "No schedules with id %s", + "commands.schedule.cleared.success": "Removed %s schedule(s) with id %s", + "commands.schedule.created.function": "Scheduled function '%s' in %s tick(s) at gametime %s", + "commands.schedule.created.tag": "Scheduled tag '%s' in %s ticks at gametime %s", + "commands.schedule.same_tick": "Can't schedule for current tick", + "commands.scoreboard.objectives.add.duplicate": "An objective already exists by that name", + "commands.scoreboard.objectives.add.success": "Created new objective %s", + "commands.scoreboard.objectives.display.alreadyEmpty": "Nothing changed. That display slot is already empty", + "commands.scoreboard.objectives.display.alreadySet": "Nothing changed. That display slot is already showing that objective", + "commands.scoreboard.objectives.display.cleared": "Cleared any objectives in display slot %s", + "commands.scoreboard.objectives.display.set": "Set display slot %s to show objective %s", + "commands.scoreboard.objectives.list.empty": "There are no objectives", + "commands.scoreboard.objectives.list.success": "There are %s objective(s): %s", + "commands.scoreboard.objectives.modify.displayAutoUpdate.disable": "Disabled display auto-update for objective %s", + "commands.scoreboard.objectives.modify.displayAutoUpdate.enable": "Enabled display auto-update for objective %s", + "commands.scoreboard.objectives.modify.displayname": "Changed the display name of %s to %s", + "commands.scoreboard.objectives.modify.objectiveFormat.clear": "Cleared default number format of objective %s", + "commands.scoreboard.objectives.modify.objectiveFormat.set": "Changed default number format of objective %s", + "commands.scoreboard.objectives.modify.rendertype": "Changed the render type of objective %s", + "commands.scoreboard.objectives.remove.success": "Removed objective %s", + "commands.scoreboard.players.add.success.multiple": "Added %s to %s for %s entities", + "commands.scoreboard.players.add.success.single": "Added %s to %s for %s (now %s)", + "commands.scoreboard.players.display.name.clear.success.multiple": "Cleared display name for %s entities in %s", + "commands.scoreboard.players.display.name.clear.success.single": "Cleared display name for %s in %s", + "commands.scoreboard.players.display.name.set.success.multiple": "Changed display name to %s for %s entities in %s", + "commands.scoreboard.players.display.name.set.success.single": "Changed display name to %s for %s in %s", + "commands.scoreboard.players.display.numberFormat.clear.success.multiple": "Cleared number format for %s entities in %s", + "commands.scoreboard.players.display.numberFormat.clear.success.single": "Cleared number format for %s in %s", + "commands.scoreboard.players.display.numberFormat.set.success.multiple": "Changed number format for %s entities in %s", + "commands.scoreboard.players.display.numberFormat.set.success.single": "Changed number format for %s in %s", + "commands.scoreboard.players.enable.failed": "Nothing changed. That trigger is already enabled", + "commands.scoreboard.players.enable.invalid": "Enable only works on trigger-objectives", + "commands.scoreboard.players.enable.success.multiple": "Enabled trigger %s for %s entities", + "commands.scoreboard.players.enable.success.single": "Enabled trigger %s for %s", + "commands.scoreboard.players.get.null": "Can't get value of %s for %s; none is set", + "commands.scoreboard.players.get.success": "%s has %s %s", + "commands.scoreboard.players.list.empty": "There are no tracked entities", + "commands.scoreboard.players.list.entity.empty": "%s has no scores to show", + "commands.scoreboard.players.list.entity.entry": "%s: %s", + "commands.scoreboard.players.list.entity.success": "%s has %s score(s):", + "commands.scoreboard.players.list.success": "There are %s tracked entity/entities: %s", + "commands.scoreboard.players.operation.success.multiple": "Updated %s for %s entities", + "commands.scoreboard.players.operation.success.single": "Set %s for %s to %s", + "commands.scoreboard.players.remove.success.multiple": "Removed %s from %s for %s entities", + "commands.scoreboard.players.remove.success.single": "Removed %s from %s for %s (now %s)", + "commands.scoreboard.players.reset.all.multiple": "Reset all scores for %s entities", + "commands.scoreboard.players.reset.all.single": "Reset all scores for %s", + "commands.scoreboard.players.reset.specific.multiple": "Reset %s for %s entities", + "commands.scoreboard.players.reset.specific.single": "Reset %s for %s", + "commands.scoreboard.players.set.success.multiple": "Set %s for %s entities to %s", + "commands.scoreboard.players.set.success.single": "Set %s for %s to %s", + "commands.seed.success": "Seed: %s", + "commands.setblock.failed": "Could not set the block", + "commands.setblock.success": "Changed the block at %s, %s, %s", + "commands.setidletimeout.success": "The player idle timeout is now %s minute(s)", + "commands.setworldspawn.failure.not_overworld": "Can only set the world spawn for overworld", + "commands.setworldspawn.success": "Set the world spawn point to %s, %s, %s [%s]", + "commands.spawnpoint.success.multiple": "Set spawn point to %s, %s, %s [%s] in %s for %s players", + "commands.spawnpoint.success.single": "Set spawn point to %s, %s, %s [%s] in %s for %s", + "commands.spectate.not_spectator": "%s is not in spectator mode", + "commands.spectate.self": "Cannot spectate yourself", + "commands.spectate.success.started": "Now spectating %s", + "commands.spectate.success.stopped": "No longer spectating an entity", + "commands.spreadplayers.failed.entities": "Could not spread %s entity/entities around %s, %s (too many entities for space - try using spread of at most %s)", + "commands.spreadplayers.failed.invalid.height": "Invalid maxHeight %s; expected higher than world minimum %s", + "commands.spreadplayers.failed.teams": "Could not spread %s team(s) around %s, %s (too many entities for space - try using spread of at most %s)", + "commands.spreadplayers.success.entities": "Spread %s player(s) around %s, %s with an average distance of %s blocks apart", + "commands.spreadplayers.success.teams": "Spread %s team(s) around %s, %s with an average distance of %s blocks apart", + "commands.stop.stopping": "Stopping the server", + "commands.stopsound.success.source.any": "Stopped all '%s' sounds", + "commands.stopsound.success.source.sound": "Stopped sound '%s' on source '%s'", + "commands.stopsound.success.sourceless.any": "Stopped all sounds", + "commands.stopsound.success.sourceless.sound": "Stopped sound '%s'", + "commands.summon.failed": "Unable to summon entity", + "commands.summon.failed.uuid": "Unable to summon entity due to duplicate UUIDs", + "commands.summon.invalidPosition": "Invalid position for summon", + "commands.summon.success": "Summoned new %s", + "commands.tag.add.failed": "Target either already has the tag or has too many tags", + "commands.tag.add.success.multiple": "Added tag '%s' to %s entities", + "commands.tag.add.success.single": "Added tag '%s' to %s", + "commands.tag.list.multiple.empty": "There are no tags on the %s entities", + "commands.tag.list.multiple.success": "The %s entities have %s total tags: %s", + "commands.tag.list.single.empty": "%s has no tags", + "commands.tag.list.single.success": "%s has %s tags: %s", + "commands.tag.remove.failed": "Target does not have this tag", + "commands.tag.remove.success.multiple": "Removed tag '%s' from %s entities", + "commands.tag.remove.success.single": "Removed tag '%s' from %s", + "commands.team.add.duplicate": "A team already exists by that name", + "commands.team.add.success": "Created team %s", + "commands.team.empty.success": "Removed %s member(s) from team %s", + "commands.team.empty.unchanged": "Nothing changed. That team is already empty", + "commands.team.join.success.multiple": "Added %s members to team %s", + "commands.team.join.success.single": "Added %s to team %s", + "commands.team.leave.success.multiple": "Removed %s members from any team", + "commands.team.leave.success.single": "Removed %s from any team", + "commands.team.list.members.empty": "There are no members on team %s", + "commands.team.list.members.success": "Team %s has %s member(s): %s", + "commands.team.list.teams.empty": "There are no teams", + "commands.team.list.teams.success": "There are %s team(s): %s", + "commands.team.option.collisionRule.success": "Collision rule for team %s is now \"%s\"", + "commands.team.option.collisionRule.unchanged": "Nothing changed. Collision rule is already that value", + "commands.team.option.color.success": "Updated the color for team %s to %s", + "commands.team.option.color.unchanged": "Nothing changed. That team already has that color", + "commands.team.option.deathMessageVisibility.success": "Death message visibility for team %s is now \"%s\"", + "commands.team.option.deathMessageVisibility.unchanged": "Nothing changed. Death message visibility is already that value", + "commands.team.option.friendlyfire.alreadyDisabled": "Nothing changed. Friendly fire is already disabled for that team", + "commands.team.option.friendlyfire.alreadyEnabled": "Nothing changed. Friendly fire is already enabled for that team", + "commands.team.option.friendlyfire.disabled": "Disabled friendly fire for team %s", + "commands.team.option.friendlyfire.enabled": "Enabled friendly fire for team %s", + "commands.team.option.name.success": "Updated the name of team %s", + "commands.team.option.name.unchanged": "Nothing changed. That team already has that name", + "commands.team.option.nametagVisibility.success": "Nametag visibility for team %s is now \"%s\"", + "commands.team.option.nametagVisibility.unchanged": "Nothing changed. Nametag visibility is already that value", + "commands.team.option.prefix.success": "Team prefix set to %s", + "commands.team.option.seeFriendlyInvisibles.alreadyDisabled": "Nothing changed. That team already can't see invisible teammates", + "commands.team.option.seeFriendlyInvisibles.alreadyEnabled": "Nothing changed. That team can already see invisible teammates", + "commands.team.option.seeFriendlyInvisibles.disabled": "Team %s can no longer see invisible teammates", + "commands.team.option.seeFriendlyInvisibles.enabled": "Team %s can now see invisible teammates", + "commands.team.option.suffix.success": "Team suffix set to %s", + "commands.team.remove.success": "Removed team %s", + "commands.teammsg.failed.noteam": "You must be on a team to message your team", + "commands.teleport.invalidPosition": "Invalid position for teleport", + "commands.teleport.success.entity.multiple": "Teleported %s entities to %s", + "commands.teleport.success.entity.single": "Teleported %s to %s", + "commands.teleport.success.location.multiple": "Teleported %s entities to %s, %s, %s", + "commands.teleport.success.location.single": "Teleported %s to %s, %s, %s", + "commands.tick.query.percentiles": "Percentiles: P50: %sms P95: %sms P99: %sms, sample: %s", + "commands.tick.query.rate.running": "Target tick rate: %s per second.\nAverage time per tick: %sms (Target: %sms)", + "commands.tick.query.rate.sprinting": "Target tick rate: %s per second (ignored, reference only).\nAverage time per tick: %sms", + "commands.tick.rate.success": "Set the target tick rate to %s per second", + "commands.tick.sprint.report": "Sprint completed with %s ticks per second, or %s ms per tick", + "commands.tick.sprint.stop.fail": "No tick sprint in progress", + "commands.tick.sprint.stop.success": "Interrupted the current tick sprint", + "commands.tick.status.frozen": "The game is frozen", + "commands.tick.status.lagging": "The game is running, but can't keep up with the target tick rate", + "commands.tick.status.running": "The game is running normally", + "commands.tick.status.sprinting": "The game is sprinting", + "commands.tick.step.fail": "Unable to step the game - the game must be frozen first", + "commands.tick.step.stop.fail": "No tick step in progress", + "commands.tick.step.stop.success": "Interrupted the current tick step", + "commands.tick.step.success": "Stepping %s tick(s)", + "commands.time.query": "The time is %s", + "commands.time.set": "Set the time to %s", + "commands.title.cleared.multiple": "Cleared titles for %s players", + "commands.title.cleared.single": "Cleared titles for %s", + "commands.title.reset.multiple": "Reset title options for %s players", + "commands.title.reset.single": "Reset title options for %s", + "commands.title.show.actionbar.multiple": "Showing new actionbar title for %s players", + "commands.title.show.actionbar.single": "Showing new actionbar title for %s", + "commands.title.show.subtitle.multiple": "Showing new subtitle for %s players", + "commands.title.show.subtitle.single": "Showing new subtitle for %s", + "commands.title.show.title.multiple": "Showing new title for %s players", + "commands.title.show.title.single": "Showing new title for %s", + "commands.title.times.multiple": "Changed title display times for %s players", + "commands.title.times.single": "Changed title display times for %s", + "commands.transfer.error.no_players": "Must specify at least one player to transfer", + "commands.transfer.success.multiple": "Transferring %s players to %s:%s", + "commands.transfer.success.single": "Transferring %s to %s:%s", + "commands.trigger.add.success": "Triggered %s (added %s to value)", + "commands.trigger.failed.invalid": "You can only trigger objectives that are 'trigger' type", + "commands.trigger.failed.unprimed": "You cannot trigger this objective yet", + "commands.trigger.set.success": "Triggered %s (set value to %s)", + "commands.trigger.simple.success": "Triggered %s", + "commands.weather.set.clear": "Set the weather to clear", + "commands.weather.set.rain": "Set the weather to rain", + "commands.weather.set.thunder": "Set the weather to rain & thunder", + "commands.whitelist.add.failed": "Player is already whitelisted", + "commands.whitelist.add.success": "Added %s to the whitelist", + "commands.whitelist.alreadyOff": "Whitelist is already turned off", + "commands.whitelist.alreadyOn": "Whitelist is already turned on", + "commands.whitelist.disabled": "Whitelist is now turned off", + "commands.whitelist.enabled": "Whitelist is now turned on", + "commands.whitelist.list": "There are %s whitelisted player(s): %s", + "commands.whitelist.none": "There are no whitelisted players", + "commands.whitelist.reloaded": "Reloaded the whitelist", + "commands.whitelist.remove.failed": "Player is not whitelisted", + "commands.whitelist.remove.success": "Removed %s from the whitelist", + "commands.worldborder.center.failed": "Nothing changed. The world border is already centered there", + "commands.worldborder.center.success": "Set the center of the world border to %s, %s", + "commands.worldborder.damage.amount.failed": "Nothing changed. The world border damage is already that amount", + "commands.worldborder.damage.amount.success": "Set the world border damage to %s per block each second", + "commands.worldborder.damage.buffer.failed": "Nothing changed. The world border damage buffer is already that distance", + "commands.worldborder.damage.buffer.success": "Set the world border damage buffer to %s block(s)", + "commands.worldborder.get": "The world border is currently %s block(s) wide", + "commands.worldborder.set.failed.big": "World border cannot be bigger than %s blocks wide", + "commands.worldborder.set.failed.far": "World border cannot be further out than %s blocks", + "commands.worldborder.set.failed.nochange": "Nothing changed. The world border is already that size", + "commands.worldborder.set.failed.small": "World border cannot be smaller than 1 block wide", + "commands.worldborder.set.grow": "Growing the world border to %s blocks wide over %s seconds", + "commands.worldborder.set.immediate": "Set the world border to %s block(s) wide", + "commands.worldborder.set.shrink": "Shrinking the world border to %s block(s) wide over %s second(s)", + "commands.worldborder.warning.distance.failed": "Nothing changed. The world border warning is already that distance", + "commands.worldborder.warning.distance.success": "Set the world border warning distance to %s block(s)", + "commands.worldborder.warning.time.failed": "Nothing changed. The world border warning is already that amount of time", + "commands.worldborder.warning.time.success": "Set the world border warning time to %s second(s)", + "compliance.playtime.greaterThan24Hours": "You've been playing for greater than 24 hours", + "compliance.playtime.hours": "You've been playing for %s hour(s)", + "compliance.playtime.message": "Excessive gaming may interfere with normal daily life", + "connect.aborted": "Aborted", + "connect.authorizing": "Logging in...", + "connect.connecting": "Connecting to the server...", + "connect.encrypting": "Encrypting...", + "connect.failed": "Failed to connect to the server", + "connect.failed.transfer": "Connection failed while transferring to the server", + "connect.joining": "Joining world...", + "connect.negotiating": "Negotiating...", + "connect.reconfiging": "Reconfiguring...", + "connect.reconfiguring": "Reconfiguring...", + "connect.transferring": "Transferring to new server...", + "container.barrel": "Barrel", + "container.beacon": "Beacon", + "container.blast_furnace": "Blast Furnace", + "container.brewing": "Brewing Stand", + "container.cartography_table": "Cartography Table", + "container.chest": "Chest", + "container.chestDouble": "Large Chest", + "container.crafter": "Crafter", + "container.crafting": "Crafting", + "container.creative": "Item Selection", + "container.dispenser": "Dispenser", + "container.dropper": "Dropper", + "container.enchant": "Enchant", + "container.enchant.clue": "%s . . . ?", + "container.enchant.lapis.many": "%s Lapis Lazuli", + "container.enchant.lapis.one": "1 Lapis Lazuli", + "container.enchant.level.many": "%s Enchantment Levels", + "container.enchant.level.one": "1 Enchantment Level", + "container.enchant.level.requirement": "Level Requirement: %s", + "container.enderchest": "Ender Chest", + "container.furnace": "Furnace", + "container.grindstone_title": "Repair & Disenchant", + "container.hopper": "Item Hopper", + "container.inventory": "Inventory", + "container.isLocked": "%s is locked!", + "container.lectern": "Lectern", + "container.loom": "Loom", + "container.repair": "Repair & Name", + "container.repair.cost": "Enchantment Cost: %1$s", + "container.repair.expensive": "Too Expensive!", + "container.shulkerBox": "Shulker Box", + "container.shulkerBox.itemCount": "%s x%s", + "container.shulkerBox.more": "and %s more...", + "container.shulkerBox.unknownContents": "???????", + "container.smoker": "Smoker", + "container.spectatorCantOpen": "Unable to open. Loot not generated yet.", + "container.stonecutter": "Stonecutter", + "container.upgrade": "Upgrade Gear", + "container.upgrade.error_tooltip": "Item can't be upgraded this way", + "container.upgrade.missing_template_tooltip": "Add Smithing Template", + "controls.keybinds": "Key Binds...", + "controls.keybinds.duplicateKeybinds": "This key is also used for:\n%s", + "controls.keybinds.title": "Key Binds", + "controls.reset": "Reset", + "controls.resetAll": "Reset Keys", + "controls.title": "Controls", + "createWorld.customize.buffet.biome": "Please select a biome", + "createWorld.customize.buffet.title": "Buffet world customization", + "createWorld.customize.custom.baseSize": "Depth Base Size", + "createWorld.customize.custom.biomeDepthOffset": "Biome Depth Offset", + "createWorld.customize.custom.biomeDepthWeight": "Biome Depth Weight", + "createWorld.customize.custom.biomeScaleOffset": "Biome Scale Offset", + "createWorld.customize.custom.biomeScaleWeight": "Biome Scale Weight", + "createWorld.customize.custom.biomeSize": "Biome Size", + "createWorld.customize.custom.center": "Center Height", + "createWorld.customize.custom.confirm1": "This will overwrite your current", + "createWorld.customize.custom.confirm2": "settings and cannot be undone.", + "createWorld.customize.custom.confirmTitle": "Warning!", + "createWorld.customize.custom.coordinateScale": "Coordinate Scale", + "createWorld.customize.custom.count": "Spawn Tries", + "createWorld.customize.custom.defaults": "Defaults", + "createWorld.customize.custom.depthNoiseScaleExponent": "Depth Noise Exponent", + "createWorld.customize.custom.depthNoiseScaleX": "Depth Noise Scale X", + "createWorld.customize.custom.depthNoiseScaleZ": "Depth Noise Scale Z", + "createWorld.customize.custom.dungeonChance": "Dungeon Count", + "createWorld.customize.custom.fixedBiome": "Biome", + "createWorld.customize.custom.heightScale": "Height Scale", + "createWorld.customize.custom.lavaLakeChance": "Lava Lake Rarity", + "createWorld.customize.custom.lowerLimitScale": "Lower Limit Scale", + "createWorld.customize.custom.mainNoiseScaleX": "Main Noise Scale X", + "createWorld.customize.custom.mainNoiseScaleY": "Main Noise Scale Y", + "createWorld.customize.custom.mainNoiseScaleZ": "Main Noise Scale Z", + "createWorld.customize.custom.maxHeight": "Max. Height", + "createWorld.customize.custom.minHeight": "Min. Height", + "createWorld.customize.custom.next": "Next Page", + "createWorld.customize.custom.page0": "Basic Settings", + "createWorld.customize.custom.page1": "Ore Settings", + "createWorld.customize.custom.page2": "Advanced Settings (Expert Users Only!)", + "createWorld.customize.custom.page3": "Extra Advanced Settings (Expert Users Only!)", + "createWorld.customize.custom.preset.caveChaos": "Caves of Chaos", + "createWorld.customize.custom.preset.caveDelight": "Caver's Delight", + "createWorld.customize.custom.preset.drought": "Drought", + "createWorld.customize.custom.preset.goodLuck": "Good Luck", + "createWorld.customize.custom.preset.isleLand": "Isle Land", + "createWorld.customize.custom.preset.mountains": "Mountain Madness", + "createWorld.customize.custom.preset.waterWorld": "Water World", + "createWorld.customize.custom.presets": "Presets", + "createWorld.customize.custom.presets.title": "Customize World Presets", + "createWorld.customize.custom.prev": "Previous Page", + "createWorld.customize.custom.randomize": "Randomize", + "createWorld.customize.custom.riverSize": "River Size", + "createWorld.customize.custom.seaLevel": "Sea Level", + "createWorld.customize.custom.size": "Spawn Size", + "createWorld.customize.custom.spread": "Spread Height", + "createWorld.customize.custom.stretchY": "Height Stretch", + "createWorld.customize.custom.upperLimitScale": "Upper Limit Scale", + "createWorld.customize.custom.useCaves": "Caves", + "createWorld.customize.custom.useDungeons": "Dungeons", + "createWorld.customize.custom.useLavaLakes": "Lava Lakes", + "createWorld.customize.custom.useLavaOceans": "Lava Oceans", + "createWorld.customize.custom.useMansions": "Woodland Mansions", + "createWorld.customize.custom.useMineShafts": "Mineshafts", + "createWorld.customize.custom.useMonuments": "Ocean Monuments", + "createWorld.customize.custom.useOceanRuins": "Ocean Ruins", + "createWorld.customize.custom.useRavines": "Ravines", + "createWorld.customize.custom.useStrongholds": "Strongholds", + "createWorld.customize.custom.useTemples": "Temples", + "createWorld.customize.custom.useVillages": "Villages", + "createWorld.customize.custom.useWaterLakes": "Water Lakes", + "createWorld.customize.custom.waterLakeChance": "Water Lake Rarity", + "createWorld.customize.flat.height": "Height", + "createWorld.customize.flat.layer": "%s", + "createWorld.customize.flat.layer.bottom": "Bottom - %s", + "createWorld.customize.flat.layer.top": "Top - %s", + "createWorld.customize.flat.removeLayer": "Remove Layer", + "createWorld.customize.flat.tile": "Layer Material", + "createWorld.customize.flat.title": "Superflat Customization", + "createWorld.customize.presets": "Presets", + "createWorld.customize.presets.list": "Alternatively, here's some we made earlier!", + "createWorld.customize.presets.select": "Use Preset", + "createWorld.customize.presets.share": "Want to share your preset with someone? Use the box below!", + "createWorld.customize.presets.title": "Select a Preset", + "createWorld.preparing": "Preparing for world creation...", + "createWorld.tab.game.title": "Game", + "createWorld.tab.more.title": "More", + "createWorld.tab.world.title": "World", + "credits_and_attribution.button.attribution": "Attribution", + "credits_and_attribution.button.credits": "Credits", + "credits_and_attribution.button.licenses": "Licenses", + "credits_and_attribution.screen.title": "Credits and Attribution", + "dataPack.bundle.description": "Enables experimental Bundle item", + "dataPack.bundle.name": "Bundles", + "dataPack.title": "Select Data Packs", + "dataPack.trade_rebalance.description": "Updated trades for Villagers", + "dataPack.trade_rebalance.name": "Villager Trade Rebalance", + "dataPack.update_1_20.description": "New features and content for Minecraft 1.20", + "dataPack.update_1_20.name": "Update 1.20", + "dataPack.update_1_21.description": "New features and content for Minecraft 1.21", + "dataPack.update_1_21.name": "Update 1.21", + "dataPack.validation.back": "Go Back", + "dataPack.validation.failed": "Data pack validation failed!", + "dataPack.validation.reset": "Reset to Default", + "dataPack.validation.working": "Validating selected data packs...", + "dataPack.vanilla.description": "The default data for Minecraft", + "dataPack.vanilla.name": "Default", + "datapackFailure.safeMode": "Safe Mode", + "datapackFailure.safeMode.failed.description": "This world contains invalid or corrupted save data.", + "datapackFailure.safeMode.failed.title": "Failed to load world in Safe Mode.", + "datapackFailure.title": "Errors in currently selected data packs prevented the world from loading.\nYou can either try to load it with only the vanilla data pack (\"safe mode\"), or go back to the title screen and fix it manually.", + "death.attack.anvil": "%1$s was squashed by a falling anvil", + "death.attack.anvil.player": "%1$s was squashed by a falling anvil while fighting %2$s", + "death.attack.arrow": "%1$s was shot by %2$s", + "death.attack.arrow.item": "%1$s was shot by %2$s using %3$s", + "death.attack.badRespawnPoint.link": "Intentional Game Design", + "death.attack.badRespawnPoint.message": "%1$s was killed by %2$s", + "death.attack.cactus": "%1$s was pricked to death", + "death.attack.cactus.player": "%1$s walked into a cactus while trying to escape %2$s", + "death.attack.cramming": "%1$s was squished too much", + "death.attack.cramming.player": "%1$s was squashed by %2$s", + "death.attack.dragonBreath": "%1$s was roasted in dragon's breath", + "death.attack.dragonBreath.player": "%1$s was roasted in dragon's breath by %2$s", + "death.attack.drown": "%1$s drowned", + "death.attack.drown.player": "%1$s drowned while trying to escape %2$s", + "death.attack.dryout": "%1$s died from dehydration", + "death.attack.dryout.player": "%1$s died from dehydration while trying to escape %2$s", + "death.attack.even_more_magic": "%1$s was killed by even more magic", + "death.attack.explosion": "%1$s blew up", + "death.attack.explosion.player": "%1$s was blown up by %2$s", + "death.attack.explosion.player.item": "%1$s was blown up by %2$s using %3$s", + "death.attack.fall": "%1$s hit the ground too hard", + "death.attack.fall.player": "%1$s hit the ground too hard while trying to escape %2$s", + "death.attack.fallingBlock": "%1$s was squashed by a falling block", + "death.attack.fallingBlock.player": "%1$s was squashed by a falling block while fighting %2$s", + "death.attack.fallingStalactite": "%1$s was skewered by a falling stalactite", + "death.attack.fallingStalactite.player": "%1$s was skewered by a falling stalactite while fighting %2$s", + "death.attack.fireball": "%1$s was fireballed by %2$s", + "death.attack.fireball.item": "%1$s was fireballed by %2$s using %3$s", + "death.attack.fireworks": "%1$s went off with a bang", + "death.attack.fireworks.item": "%1$s went off with a bang due to a firework fired from %3$s by %2$s", + "death.attack.fireworks.player": "%1$s went off with a bang while fighting %2$s", + "death.attack.flyIntoWall": "%1$s experienced kinetic energy", + "death.attack.flyIntoWall.player": "%1$s experienced kinetic energy while trying to escape %2$s", + "death.attack.freeze": "%1$s froze to death", + "death.attack.freeze.player": "%1$s was frozen to death by %2$s", + "death.attack.generic": "%1$s died", + "death.attack.generic.player": "%1$s died because of %2$s", + "death.attack.genericKill": "%1$s was killed", + "death.attack.genericKill.player": "%1$s was killed while fighting %2$s", + "death.attack.hotFloor": "%1$s discovered the floor was lava", + "death.attack.hotFloor.player": "%1$s walked into the danger zone due to %2$s", + "death.attack.indirectMagic": "%1$s was killed by %2$s using magic", + "death.attack.indirectMagic.item": "%1$s was killed by %2$s using %3$s", + "death.attack.inFire": "%1$s went up in flames", + "death.attack.inFire.player": "%1$s walked into fire while fighting %2$s", + "death.attack.inWall": "%1$s suffocated in a wall", + "death.attack.inWall.player": "%1$s suffocated in a wall while fighting %2$s", + "death.attack.lava": "%1$s tried to swim in lava", + "death.attack.lava.player": "%1$s tried to swim in lava to escape %2$s", + "death.attack.lightningBolt": "%1$s was struck by lightning", + "death.attack.lightningBolt.player": "%1$s was struck by lightning while fighting %2$s", + "death.attack.magic": "%1$s was killed by magic", + "death.attack.magic.player": "%1$s was killed by magic while trying to escape %2$s", + "death.attack.message_too_long": "Actually, the message was too long to deliver fully. Sorry! Here's a stripped version: %s", + "death.attack.mob": "%1$s was slain by %2$s", + "death.attack.mob.item": "%1$s was slain by %2$s using %3$s", + "death.attack.onFire": "%1$s burned to death", + "death.attack.onFire.item": "%1$s was burned to a crisp while fighting %2$s wielding %3$s", + "death.attack.onFire.player": "%1$s was burned to a crisp while fighting %2$s", + "death.attack.outOfWorld": "%1$s fell out of the world", + "death.attack.outOfWorld.player": "%1$s didn't want to live in the same world as %2$s", + "death.attack.outsideBorder": "%1$s left the confines of this world", + "death.attack.outsideBorder.player": "%1$s left the confines of this world while fighting %2$s", + "death.attack.player": "%1$s was slain by %2$s", + "death.attack.player.item": "%1$s was slain by %2$s using %3$s", + "death.attack.sonic_boom": "%1$s was obliterated by a sonically-charged shriek", + "death.attack.sonic_boom.item": "%1$s was obliterated by a sonically-charged shriek while trying to escape %2$s wielding %3$s", + "death.attack.sonic_boom.player": "%1$s was obliterated by a sonically-charged shriek while trying to escape %2$s", + "death.attack.stalagmite": "%1$s was impaled on a stalagmite", + "death.attack.stalagmite.player": "%1$s was impaled on a stalagmite while fighting %2$s", + "death.attack.starve": "%1$s starved to death", + "death.attack.starve.player": "%1$s starved to death while fighting %2$s", + "death.attack.sting": "%1$s was stung to death", + "death.attack.sting.item": "%1$s was stung to death by %2$s using %3$s", + "death.attack.sting.player": "%1$s was stung to death by %2$s", + "death.attack.sweetBerryBush": "%1$s was poked to death by a sweet berry bush", + "death.attack.sweetBerryBush.player": "%1$s was poked to death by a sweet berry bush while trying to escape %2$s", + "death.attack.thorns": "%1$s was killed while trying to hurt %2$s", + "death.attack.thorns.item": "%1$s was killed by %3$s while trying to hurt %2$s", + "death.attack.thrown": "%1$s was pummeled by %2$s", + "death.attack.thrown.item": "%1$s was pummeled by %2$s using %3$s", + "death.attack.trident": "%1$s was impaled by %2$s", + "death.attack.trident.item": "%1$s was impaled by %2$s with %3$s", + "death.attack.wither": "%1$s withered away", + "death.attack.wither.player": "%1$s withered away while fighting %2$s", + "death.attack.witherSkull": "%1$s was shot by a skull from %2$s", + "death.attack.witherSkull.item": "%1$s was shot by a skull from %2$s using %3$s", + "death.fell.accident.generic": "%1$s fell from a high place", + "death.fell.accident.ladder": "%1$s fell off a ladder", + "death.fell.accident.other_climbable": "%1$s fell while climbing", + "death.fell.accident.scaffolding": "%1$s fell off scaffolding", + "death.fell.accident.twisting_vines": "%1$s fell off some twisting vines", + "death.fell.accident.vines": "%1$s fell off some vines", + "death.fell.accident.weeping_vines": "%1$s fell off some weeping vines", + "death.fell.assist": "%1$s was doomed to fall by %2$s", + "death.fell.assist.item": "%1$s was doomed to fall by %2$s using %3$s", + "death.fell.finish": "%1$s fell too far and was finished by %2$s", + "death.fell.finish.item": "%1$s fell too far and was finished by %2$s using %3$s", + "death.fell.killer": "%1$s was doomed to fall", + "deathScreen.quit.confirm": "Are you sure you want to quit?", + "deathScreen.respawn": "Respawn", + "deathScreen.score": "Score", + "deathScreen.score.value": "Score: %s", + "deathScreen.spectate": "Spectate World", + "deathScreen.title": "You Died!", + "deathScreen.title.hardcore": "Game Over!", + "deathScreen.titleScreen": "Title Screen", + "debug.advanced_tooltips.help": "F3 + H = Advanced tooltips", + "debug.advanced_tooltips.off": "Advanced tooltips: hidden", + "debug.advanced_tooltips.on": "Advanced tooltips: shown", + "debug.chunk_boundaries.help": "F3 + G = Show chunk boundaries", + "debug.chunk_boundaries.off": "Chunk borders: hidden", + "debug.chunk_boundaries.on": "Chunk borders: shown", + "debug.clear_chat.help": "F3 + D = Clear chat", + "debug.copy_location.help": "F3 + C = Copy location as /tp command, hold F3 + C to crash the game", + "debug.copy_location.message": "Copied location to clipboard", + "debug.crash.message": "F3 + C is held down. This will crash the game unless released.", + "debug.crash.warning": "Crashing in %s...", + "debug.creative_spectator.error": "Unable to switch game mode; no permission", + "debug.creative_spectator.help": "F3 + N = Cycle previous game mode <-> spectator", + "debug.dump_dynamic_textures": "Saved dynamic textures to %s", + "debug.dump_dynamic_textures.help": "F3 + S = Dump dynamic textures", + "debug.gamemodes.error": "Unable to open game mode switcher; no permission", + "debug.gamemodes.help": "F3 + F4 = Open game mode switcher", + "debug.gamemodes.press_f4": "[ F4 ]", + "debug.gamemodes.select_next": "%s Next", + "debug.help.help": "F3 + Q = Show this list", + "debug.help.message": "Key bindings:", + "debug.inspect.client.block": "Copied client-side block data to clipboard", + "debug.inspect.client.entity": "Copied client-side entity data to clipboard", + "debug.inspect.help": "F3 + I = Copy entity or block data to clipboard", + "debug.inspect.server.block": "Copied server-side block data to clipboard", + "debug.inspect.server.entity": "Copied server-side entity data to clipboard", + "debug.pause_focus.help": "F3 + P = Pause on lost focus", + "debug.pause_focus.off": "Pause on lost focus: disabled", + "debug.pause_focus.on": "Pause on lost focus: enabled", + "debug.pause.help": "F3 + Esc = Pause without pause menu (if pausing is possible)", + "debug.prefix": "[Debug]:", + "debug.profiling.help": "F3 + L = Start/stop profiling", + "debug.profiling.start": "Profiling started for %s seconds. Use F3 + L to stop early", + "debug.profiling.stop": "Profiling ended. Saved results to %s", + "debug.reload_chunks.help": "F3 + A = Reload chunks", + "debug.reload_chunks.message": "Reloading all chunks", + "debug.reload_resourcepacks.help": "F3 + T = Reload resource packs", + "debug.reload_resourcepacks.message": "Reloaded resource packs", + "debug.show_hitboxes.help": "F3 + B = Show hitboxes", + "debug.show_hitboxes.off": "Hitboxes: hidden", + "debug.show_hitboxes.on": "Hitboxes: shown", + "demo.day.1": "This demo will last five game days. Do your best!", + "demo.day.2": "Day Two", + "demo.day.3": "Day Three", + "demo.day.4": "Day Four", + "demo.day.5": "This is your last day!", + "demo.day.6": "You have passed your fifth day. Use %s to save a screenshot of your creation.", + "demo.day.warning": "Your time is almost up!", + "demo.demoExpired": "Demo time's up!", + "demo.help.buy": "Purchase Now!", + "demo.help.fullWrapped": "This demo will last 5 in-game days (about 1 hour and 40 minutes of real time). Check the advancements for hints! Have fun!", + "demo.help.inventory": "Use the %1$s key to open your inventory", + "demo.help.jump": "Jump by pressing the %1$s key", + "demo.help.later": "Continue Playing!", + "demo.help.movement": "Use the %1$s, %2$s, %3$s, %4$s keys and the mouse to move around", + "demo.help.movementMouse": "Look around using the mouse", + "demo.help.movementShort": "Move by pressing the %1$s, %2$s, %3$s, %4$s keys", + "demo.help.title": "Minecraft Demo Mode", + "demo.remainingTime": "Remaining time: %s", + "demo.reminder": "The demo time has expired. Buy the game to continue or start a new world!", + "difficulty.lock.question": "Are you sure you want to lock the difficulty of this world? This will set this world to always be %1$s, and you will never be able to change that again.", + "difficulty.lock.title": "Lock World Difficulty", + "disconnect.closed": "Connection closed", + "disconnect.disconnected": "Disconnected by Server", + "disconnect.endOfStream": "End of stream", + "disconnect.exceeded_packet_rate": "Kicked for exceeding packet rate limit", + "disconnect.genericReason": "%s", + "disconnect.ignoring_status_request": "Ignoring status request", + "disconnect.kicked": "Was kicked from the game", + "disconnect.loginFailed": "Failed to log in", + "disconnect.loginFailedInfo": "Failed to log in: %s", + "disconnect.loginFailedInfo.insufficientPrivileges": "Multiplayer is disabled. Please check your Microsoft account settings.", + "disconnect.loginFailedInfo.invalidSession": "Invalid session (Try restarting your game and the launcher)", + "disconnect.loginFailedInfo.serversUnavailable": "The authentication servers are currently not reachable. Please try again.", + "disconnect.loginFailedInfo.userBanned": "You are banned from playing online", + "disconnect.lost": "Connection Lost", + "disconnect.overflow": "Buffer overflow", + "disconnect.packetError": "Network Protocol Error", + "disconnect.quitting": "Quitting", + "disconnect.spam": "Kicked for spamming", + "disconnect.timeout": "Timed out", + "disconnect.transfer": "Transferred to another server", + "disconnect.unknownHost": "Unknown host", + "download.pack.failed": "%s out of %s pack(s) failed to download", + "download.pack.progress.bytes": "Progress: %s (total size unknown)", + "download.pack.progress.percent": "Progress: %s%%", + "download.pack.title": "Downloading resource pack %s/%s", + "editGamerule.default": "Default: %s", + "editGamerule.title": "Edit Game Rules", + "effect.duration.infinite": "∞", + "effect.minecraft.absorption": "Absorption", + "effect.minecraft.bad_omen": "Bad Omen", + "effect.minecraft.blindness": "Blindness", + "effect.minecraft.conduit_power": "Conduit Power", + "effect.minecraft.darkness": "Darkness", + "effect.minecraft.dolphins_grace": "Dolphin's Grace", + "effect.minecraft.fire_resistance": "Fire Resistance", + "effect.minecraft.glowing": "Glowing", + "effect.minecraft.haste": "Haste", + "effect.minecraft.health_boost": "Health Boost", + "effect.minecraft.hero_of_the_village": "Hero of the Village", + "effect.minecraft.hunger": "Hunger", + "effect.minecraft.infested": "Infested", + "effect.minecraft.instant_damage": "Instant Damage", + "effect.minecraft.instant_health": "Instant Health", + "effect.minecraft.invisibility": "Invisibility", + "effect.minecraft.jump_boost": "Jump Boost", + "effect.minecraft.levitation": "Levitation", + "effect.minecraft.luck": "Luck", + "effect.minecraft.mining_fatigue": "Mining Fatigue", + "effect.minecraft.nausea": "Nausea", + "effect.minecraft.night_vision": "Night Vision", + "effect.minecraft.oozing": "Oozing", + "effect.minecraft.poison": "Poison", + "effect.minecraft.raid_omen": "Raid Omen", + "effect.minecraft.regeneration": "Regeneration", + "effect.minecraft.resistance": "Resistance", + "effect.minecraft.saturation": "Saturation", + "effect.minecraft.slow_falling": "Slow Falling", + "effect.minecraft.slowness": "Slowness", + "effect.minecraft.speed": "Speed", + "effect.minecraft.strength": "Strength", + "effect.minecraft.trial_omen": "Trial Omen", + "effect.minecraft.unluck": "Bad Luck", + "effect.minecraft.water_breathing": "Water Breathing", + "effect.minecraft.weakness": "Weakness", + "effect.minecraft.weaving": "Weaving", + "effect.minecraft.wind_charged": "Wind Charged", + "effect.minecraft.wither": "Wither", + "effect.none": "No Effects", + "enchantment.level.1": "I", + "enchantment.level.2": "II", + "enchantment.level.3": "III", + "enchantment.level.4": "IV", + "enchantment.level.5": "V", + "enchantment.level.6": "VI", + "enchantment.level.7": "VII", + "enchantment.level.8": "VIII", + "enchantment.level.9": "IX", + "enchantment.level.10": "X", + "enchantment.minecraft.aqua_affinity": "Aqua Affinity", + "enchantment.minecraft.bane_of_arthropods": "Bane of Arthropods", + "enchantment.minecraft.binding_curse": "Curse of Binding", + "enchantment.minecraft.blast_protection": "Blast Protection", + "enchantment.minecraft.breach": "Breach", + "enchantment.minecraft.channeling": "Channeling", + "enchantment.minecraft.density": "Density", + "enchantment.minecraft.depth_strider": "Depth Strider", + "enchantment.minecraft.efficiency": "Efficiency", + "enchantment.minecraft.feather_falling": "Feather Falling", + "enchantment.minecraft.fire_aspect": "Fire Aspect", + "enchantment.minecraft.fire_protection": "Fire Protection", + "enchantment.minecraft.flame": "Flame", + "enchantment.minecraft.fortune": "Fortune", + "enchantment.minecraft.frost_walker": "Frost Walker", + "enchantment.minecraft.impaling": "Impaling", + "enchantment.minecraft.infinity": "Infinity", + "enchantment.minecraft.knockback": "Knockback", + "enchantment.minecraft.looting": "Looting", + "enchantment.minecraft.loyalty": "Loyalty", + "enchantment.minecraft.luck_of_the_sea": "Luck of the Sea", + "enchantment.minecraft.lure": "Lure", + "enchantment.minecraft.mending": "Mending", + "enchantment.minecraft.multishot": "Multishot", + "enchantment.minecraft.piercing": "Piercing", + "enchantment.minecraft.power": "Power", + "enchantment.minecraft.projectile_protection": "Projectile Protection", + "enchantment.minecraft.protection": "Protection", + "enchantment.minecraft.punch": "Punch", + "enchantment.minecraft.quick_charge": "Quick Charge", + "enchantment.minecraft.respiration": "Respiration", + "enchantment.minecraft.riptide": "Riptide", + "enchantment.minecraft.sharpness": "Sharpness", + "enchantment.minecraft.silk_touch": "Silk Touch", + "enchantment.minecraft.smite": "Smite", + "enchantment.minecraft.soul_speed": "Soul Speed", + "enchantment.minecraft.sweeping": "Sweeping Edge", + "enchantment.minecraft.sweeping_edge": "Sweeping Edge", + "enchantment.minecraft.swift_sneak": "Swift Sneak", + "enchantment.minecraft.thorns": "Thorns", + "enchantment.minecraft.unbreaking": "Unbreaking", + "enchantment.minecraft.vanishing_curse": "Curse of Vanishing", + "enchantment.minecraft.wind_burst": "Wind Burst", + "entity.minecraft.allay": "Allay", + "entity.minecraft.area_effect_cloud": "Area Effect Cloud", + "entity.minecraft.armadillo": "Armadillo", + "entity.minecraft.armor_stand": "Armor Stand", + "entity.minecraft.arrow": "Arrow", + "entity.minecraft.axolotl": "Axolotl", + "entity.minecraft.bat": "Bat", + "entity.minecraft.bee": "Bee", + "entity.minecraft.blaze": "Blaze", + "entity.minecraft.block_display": "Block Display", + "entity.minecraft.boat": "Boat", + "entity.minecraft.bogged": "Bogged", + "entity.minecraft.breeze": "Breeze", + "entity.minecraft.breeze_wind_charge": "Wind Charge", + "entity.minecraft.camel": "Camel", + "entity.minecraft.cat": "Cat", + "entity.minecraft.cave_spider": "Cave Spider", + "entity.minecraft.chest_boat": "Boat with Chest", + "entity.minecraft.chest_minecart": "Minecart with Chest", + "entity.minecraft.chicken": "Chicken", + "entity.minecraft.cod": "Cod", + "entity.minecraft.command_block_minecart": "Minecart with Command Block", + "entity.minecraft.cow": "Cow", + "entity.minecraft.creeper": "Creeper", + "entity.minecraft.dolphin": "Dolphin", + "entity.minecraft.donkey": "Donkey", + "entity.minecraft.dragon_fireball": "Dragon Fireball", + "entity.minecraft.drowned": "Drowned", + "entity.minecraft.egg": "Thrown Egg", + "entity.minecraft.elder_guardian": "Elder Guardian", + "entity.minecraft.end_crystal": "End Crystal", + "entity.minecraft.ender_dragon": "Ender Dragon", + "entity.minecraft.ender_pearl": "Thrown Ender Pearl", + "entity.minecraft.enderman": "Enderman", + "entity.minecraft.endermite": "Endermite", + "entity.minecraft.evoker": "Evoker", + "entity.minecraft.evoker_fangs": "Evoker Fangs", + "entity.minecraft.experience_bottle": "Thrown Bottle o' Enchanting", + "entity.minecraft.experience_orb": "Experience Orb", + "entity.minecraft.eye_of_ender": "Eye of Ender", + "entity.minecraft.falling_block": "Falling Block", + "entity.minecraft.falling_block_type": "Falling %s", + "entity.minecraft.fireball": "Fireball", + "entity.minecraft.firework_rocket": "Firework Rocket", + "entity.minecraft.fishing_bobber": "Fishing Bobber", + "entity.minecraft.fox": "Fox", + "entity.minecraft.frog": "Frog", + "entity.minecraft.furnace_minecart": "Minecart with Furnace", + "entity.minecraft.ghast": "Ghast", + "entity.minecraft.giant": "Giant", + "entity.minecraft.glow_item_frame": "Glow Item Frame", + "entity.minecraft.glow_squid": "Glow Squid", + "entity.minecraft.goat": "Goat", + "entity.minecraft.guardian": "Guardian", + "entity.minecraft.hoglin": "Hoglin", + "entity.minecraft.hopper_minecart": "Minecart with Hopper", + "entity.minecraft.horse": "Horse", + "entity.minecraft.husk": "Husk", + "entity.minecraft.illusioner": "Illusioner", + "entity.minecraft.interaction": "Interaction", + "entity.minecraft.iron_golem": "Iron Golem", + "entity.minecraft.item": "Item", + "entity.minecraft.item_display": "Item Display", + "entity.minecraft.item_frame": "Item Frame", + "entity.minecraft.killer_bunny": "The Killer Bunny", + "entity.minecraft.leash_knot": "Leash Knot", + "entity.minecraft.lightning_bolt": "Lightning Bolt", + "entity.minecraft.llama": "Llama", + "entity.minecraft.llama_spit": "Llama Spit", + "entity.minecraft.magma_cube": "Magma Cube", + "entity.minecraft.marker": "Marker", + "entity.minecraft.minecart": "Minecart", + "entity.minecraft.mooshroom": "Mooshroom", + "entity.minecraft.mule": "Mule", + "entity.minecraft.ocelot": "Ocelot", + "entity.minecraft.ominous_item_spawner": "Ominous Item Spawner", + "entity.minecraft.painting": "Painting", + "entity.minecraft.panda": "Panda", + "entity.minecraft.parrot": "Parrot", + "entity.minecraft.phantom": "Phantom", + "entity.minecraft.pig": "Pig", + "entity.minecraft.piglin": "Piglin", + "entity.minecraft.piglin_brute": "Piglin Brute", + "entity.minecraft.pillager": "Pillager", + "entity.minecraft.player": "Player", + "entity.minecraft.polar_bear": "Polar Bear", + "entity.minecraft.potion": "Potion", + "entity.minecraft.pufferfish": "Pufferfish", + "entity.minecraft.rabbit": "Rabbit", + "entity.minecraft.ravager": "Ravager", + "entity.minecraft.salmon": "Salmon", + "entity.minecraft.sheep": "Sheep", + "entity.minecraft.shulker": "Shulker", + "entity.minecraft.shulker_bullet": "Shulker Bullet", + "entity.minecraft.silverfish": "Silverfish", + "entity.minecraft.skeleton": "Skeleton", + "entity.minecraft.skeleton_horse": "Skeleton Horse", + "entity.minecraft.slime": "Slime", + "entity.minecraft.small_fireball": "Small Fireball", + "entity.minecraft.sniffer": "Sniffer", + "entity.minecraft.snow_golem": "Snow Golem", + "entity.minecraft.snowball": "Snowball", + "entity.minecraft.spawner_minecart": "Minecart with Monster Spawner", + "entity.minecraft.spectral_arrow": "Spectral Arrow", + "entity.minecraft.spider": "Spider", + "entity.minecraft.squid": "Squid", + "entity.minecraft.stray": "Stray", + "entity.minecraft.strider": "Strider", + "entity.minecraft.tadpole": "Tadpole", + "entity.minecraft.text_display": "Text Display", + "entity.minecraft.tnt": "Primed TNT", + "entity.minecraft.tnt_minecart": "Minecart with TNT", + "entity.minecraft.trader_llama": "Trader Llama", + "entity.minecraft.trident": "Trident", + "entity.minecraft.tropical_fish": "Tropical Fish", + "entity.minecraft.tropical_fish.predefined.0": "Anemone", + "entity.minecraft.tropical_fish.predefined.1": "Black Tang", + "entity.minecraft.tropical_fish.predefined.2": "Blue Tang", + "entity.minecraft.tropical_fish.predefined.3": "Butterflyfish", + "entity.minecraft.tropical_fish.predefined.4": "Cichlid", + "entity.minecraft.tropical_fish.predefined.5": "Clownfish", + "entity.minecraft.tropical_fish.predefined.6": "Cotton Candy Betta", + "entity.minecraft.tropical_fish.predefined.7": "Dottyback", + "entity.minecraft.tropical_fish.predefined.8": "Emperor Red Snapper", + "entity.minecraft.tropical_fish.predefined.9": "Goatfish", + "entity.minecraft.tropical_fish.predefined.10": "Moorish Idol", + "entity.minecraft.tropical_fish.predefined.11": "Ornate Butterflyfish", + "entity.minecraft.tropical_fish.predefined.12": "Parrotfish", + "entity.minecraft.tropical_fish.predefined.13": "Queen Angelfish", + "entity.minecraft.tropical_fish.predefined.14": "Red Cichlid", + "entity.minecraft.tropical_fish.predefined.15": "Red Lipped Blenny", + "entity.minecraft.tropical_fish.predefined.16": "Red Snapper", + "entity.minecraft.tropical_fish.predefined.17": "Threadfin", + "entity.minecraft.tropical_fish.predefined.18": "Tomato Clownfish", + "entity.minecraft.tropical_fish.predefined.19": "Triggerfish", + "entity.minecraft.tropical_fish.predefined.20": "Yellowtail Parrotfish", + "entity.minecraft.tropical_fish.predefined.21": "Yellow Tang", + "entity.minecraft.tropical_fish.type.betty": "Betty", + "entity.minecraft.tropical_fish.type.blockfish": "Blockfish", + "entity.minecraft.tropical_fish.type.brinely": "Brinely", + "entity.minecraft.tropical_fish.type.clayfish": "Clayfish", + "entity.minecraft.tropical_fish.type.dasher": "Dasher", + "entity.minecraft.tropical_fish.type.flopper": "Flopper", + "entity.minecraft.tropical_fish.type.glitter": "Glitter", + "entity.minecraft.tropical_fish.type.kob": "Kob", + "entity.minecraft.tropical_fish.type.snooper": "Snooper", + "entity.minecraft.tropical_fish.type.spotty": "Spotty", + "entity.minecraft.tropical_fish.type.stripey": "Stripey", + "entity.minecraft.tropical_fish.type.sunstreak": "Sunstreak", + "entity.minecraft.turtle": "Turtle", + "entity.minecraft.vex": "Vex", + "entity.minecraft.villager": "Villager", + "entity.minecraft.villager.armorer": "Armorer", + "entity.minecraft.villager.butcher": "Butcher", + "entity.minecraft.villager.cartographer": "Cartographer", + "entity.minecraft.villager.cleric": "Cleric", + "entity.minecraft.villager.farmer": "Farmer", + "entity.minecraft.villager.fisherman": "Fisherman", + "entity.minecraft.villager.fletcher": "Fletcher", + "entity.minecraft.villager.leatherworker": "Leatherworker", + "entity.minecraft.villager.librarian": "Librarian", + "entity.minecraft.villager.mason": "Mason", + "entity.minecraft.villager.nitwit": "Nitwit", + "entity.minecraft.villager.none": "Villager", + "entity.minecraft.villager.shepherd": "Shepherd", + "entity.minecraft.villager.toolsmith": "Toolsmith", + "entity.minecraft.villager.weaponsmith": "Weaponsmith", + "entity.minecraft.vindicator": "Vindicator", + "entity.minecraft.wandering_trader": "Wandering Trader", + "entity.minecraft.warden": "Warden", + "entity.minecraft.wind_charge": "Wind Charge", + "entity.minecraft.witch": "Witch", + "entity.minecraft.wither": "Wither", + "entity.minecraft.wither_skeleton": "Wither Skeleton", + "entity.minecraft.wither_skull": "Wither Skull", + "entity.minecraft.wolf": "Wolf", + "entity.minecraft.zoglin": "Zoglin", + "entity.minecraft.zombie": "Zombie", + "entity.minecraft.zombie_horse": "Zombie Horse", + "entity.minecraft.zombie_villager": "Zombie Villager", + "entity.minecraft.zombified_piglin": "Zombified Piglin", + "entity.not_summonable": "Can't summon entity of type %s", + "event.minecraft.raid": "Raid", + "event.minecraft.raid.defeat": "Defeat", + "event.minecraft.raid.defeat.full": "Raid - Defeat", + "event.minecraft.raid.raiders_remaining": "Raiders Remaining: %s", + "event.minecraft.raid.victory": "Victory", + "event.minecraft.raid.victory.full": "Raid - Victory", + "filled_map.buried_treasure": "Buried Treasure Map", + "filled_map.explorer_jungle": "Jungle Explorer Map", + "filled_map.explorer_swamp": "Swamp Explorer Map", + "filled_map.id": "Id #%s", + "filled_map.level": "(Level %s/%s)", + "filled_map.locked": "Locked", + "filled_map.mansion": "Woodland Explorer Map", + "filled_map.monument": "Ocean Explorer Map", + "filled_map.scale": "Scaling at 1:%s", + "filled_map.trial_chambers": "Trial Explorer Map", + "filled_map.unknown": "Unknown Map", + "filled_map.village_desert": "Desert Village Map", + "filled_map.village_plains": "Plains Village Map", + "filled_map.village_savanna": "Savanna Village Map", + "filled_map.village_snowy": "Snowy Village Map", + "filled_map.village_taiga": "Taiga Village Map", + "flat_world_preset.minecraft.bottomless_pit": "Bottomless Pit", + "flat_world_preset.minecraft.classic_flat": "Classic Flat", + "flat_world_preset.minecraft.desert": "Desert", + "flat_world_preset.minecraft.overworld": "Overworld", + "flat_world_preset.minecraft.redstone_ready": "Redstone Ready", + "flat_world_preset.minecraft.snowy_kingdom": "Snowy Kingdom", + "flat_world_preset.minecraft.the_void": "The Void", + "flat_world_preset.minecraft.tunnelers_dream": "Tunnelers' Dream", + "flat_world_preset.minecraft.water_world": "Water World", + "flat_world_preset.unknown": "???", + "gameMode.adventure": "Adventure Mode", + "gameMode.changed": "Your game mode has been updated to %s", + "gameMode.creative": "Creative Mode", + "gameMode.hardcore": "Hardcore Mode!", + "gameMode.spectator": "Spectator Mode", + "gameMode.survival": "Survival Mode", + "gamerule.announceAdvancements": "Announce advancements", + "gamerule.blockExplosionDropDecay": "In block interaction explosions, some blocks won't drop their loot", + "gamerule.blockExplosionDropDecay.description": "Some of the drops from blocks destroyed by explosions caused by block interactions are lost in the explosion.", + "gamerule.category.chat": "Chat", + "gamerule.category.drops": "Drops", + "gamerule.category.misc": "Miscellaneous", + "gamerule.category.mobs": "Mobs", + "gamerule.category.player": "Player", + "gamerule.category.spawning": "Spawning", + "gamerule.category.updates": "World Updates", + "gamerule.commandBlockOutput": "Broadcast command block output", + "gamerule.commandModificationBlockLimit": "Command modification block limit", + "gamerule.commandModificationBlockLimit.description": "Number of blocks that can be changed at once by one command, such as fill or clone.", + "gamerule.disableElytraMovementCheck": "Disable elytra movement check", + "gamerule.disableRaids": "Disable raids", + "gamerule.doDaylightCycle": "Advance time of day", + "gamerule.doEntityDrops": "Drop entity equipment", + "gamerule.doEntityDrops.description": "Controls drops from minecarts (including inventories), item frames, boats, etc.", + "gamerule.doFireTick": "Update fire", + "gamerule.doImmediateRespawn": "Respawn immediately", + "gamerule.doInsomnia": "Spawn phantoms", + "gamerule.doLimitedCrafting": "Require recipe for crafting", + "gamerule.doLimitedCrafting.description": "If enabled, players will be able to craft only unlocked recipes.", + "gamerule.doMobLoot": "Drop mob loot", + "gamerule.doMobLoot.description": "Controls resource drops from mobs, including experience orbs.", + "gamerule.doMobSpawning": "Spawn mobs", + "gamerule.doMobSpawning.description": "Some entities might have separate rules.", + "gamerule.doPatrolSpawning": "Spawn pillager patrols", + "gamerule.doTileDrops": "Drop blocks", + "gamerule.doTileDrops.description": "Controls resource drops from blocks, including experience orbs.", + "gamerule.doTraderSpawning": "Spawn Wandering Traders", + "gamerule.doVinesSpread": "Vines spread", + "gamerule.doVinesSpread.description": "Controls whether or not the Vines block spreads randomly to adjacent blocks. Does not affect other types of vine blocks such as Weeping Vines, Twisting Vines, etc.", + "gamerule.doWardenSpawning": "Spawn Wardens", + "gamerule.doWeatherCycle": "Update weather", + "gamerule.drowningDamage": "Deal drowning damage", + "gamerule.enderPearlsVanishOnDeath": "Thrown Ender Pearls vanish on death", + "gamerule.enderPearlsVanishOnDeath.description": "Whether Ender Pearls thrown by a player vanish when that player dies.", + "gamerule.entitiesWithPassengersCanUsePortals": "Entities with passengers can use portals", + "gamerule.entitiesWithPassengersCanUsePortals.description": "Allow entities with passengers to teleport through Nether Portals, End Portals, and End Gateways.", + "gamerule.fallDamage": "Deal fall damage", + "gamerule.fireDamage": "Deal fire damage", + "gamerule.forgiveDeadPlayers": "Forgive dead players", + "gamerule.forgiveDeadPlayers.description": "Angered neutral mobs stop being angry when the targeted player dies nearby.", + "gamerule.freezeDamage": "Deal freeze damage", + "gamerule.globalSoundEvents": "Global sound events", + "gamerule.globalSoundEvents.description": "When certain game events happen, like a boss spawning, the sound is heard everywhere.", + "gamerule.keepInventory": "Keep inventory after death", + "gamerule.lavaSourceConversion": "Lava converts to source", + "gamerule.lavaSourceConversion.description": "When flowing lava is surrounded on two sides by lava sources it converts into a source.", + "gamerule.logAdminCommands": "Broadcast admin commands", + "gamerule.maxCommandChainLength": "Command chain size limit", + "gamerule.maxCommandChainLength.description": "Applies to command block chains and functions.", + "gamerule.maxCommandForkCount": "Command context limit", + "gamerule.maxCommandForkCount.description": "Maximum number of contexts that can be used by commands like 'execute as'.", + "gamerule.maxEntityCramming": "Entity cramming threshold", + "gamerule.mobExplosionDropDecay": "In mob explosions, some blocks won't drop their loot", + "gamerule.mobExplosionDropDecay.description": "Some of the drops from blocks destroyed by explosions caused by mobs are lost in the explosion.", + "gamerule.mobGriefing": "Allow destructive mob actions", + "gamerule.naturalRegeneration": "Regenerate health", + "gamerule.playersNetherPortalCreativeDelay": "Player's Nether portal delay in creative mode", + "gamerule.playersNetherPortalCreativeDelay.description": "Time (in ticks) that a creative mode player needs to stand in a Nether portal before changing dimensions.", + "gamerule.playersNetherPortalDefaultDelay": "Player's Nether portal delay in non-creative mode", + "gamerule.playersNetherPortalDefaultDelay.description": "Time (in ticks) that a non-creative mode player needs to stand in a Nether portal before changing dimensions.", + "gamerule.playersSleepingPercentage": "Sleep percentage", + "gamerule.playersSleepingPercentage.description": "The percentage of players who must be sleeping to skip the night.", + "gamerule.projectilesCanBreakBlocks": "Projectiles can break blocks", + "gamerule.projectilesCanBreakBlocks.description": "Controls whether impact projectiles will destroy blocks that are destructible by them.", + "gamerule.randomTickSpeed": "Random tick speed rate", + "gamerule.reducedDebugInfo": "Reduce debug info", + "gamerule.reducedDebugInfo.description": "Limits contents of debug screen.", + "gamerule.sendCommandFeedback": "Send command feedback", + "gamerule.showDeathMessages": "Show death messages", + "gamerule.snowAccumulationHeight": "Snow accumulation height", + "gamerule.snowAccumulationHeight.description": "When it snows, layers of snow form on the ground up to at most this number of layers.", + "gamerule.spawnChunkRadius": "Spawn chunk radius", + "gamerule.spawnChunkRadius.description": "Amount of chunks that stay loaded around the overworld spawn position.", + "gamerule.spawnRadius": "Respawn location radius", + "gamerule.spawnRadius.description": "Controls the size of the area around the spawn point that players can spawn in.", + "gamerule.spectatorsGenerateChunks": "Allow spectators to generate terrain", + "gamerule.tntExplosionDropDecay": "In TNT explosions, some blocks won't drop their loot", + "gamerule.tntExplosionDropDecay.description": "Some of the drops from blocks destroyed by explosions caused by TNT are lost in the explosion.", + "gamerule.universalAnger": "Universal anger", + "gamerule.universalAnger.description": "Angered neutral mobs attack any nearby player, not just the player that angered them. Works best if forgiveDeadPlayers is disabled.", + "gamerule.waterSourceConversion": "Water converts to source", + "gamerule.waterSourceConversion.description": "When flowing water is surrounded on two sides by water sources it converts into a source.", + "generator.custom": "Custom", + "generator.customized": "Old Customized", + "generator.minecraft.amplified": "AMPLIFIED", + "generator.minecraft.amplified.info": "Notice: Just for fun! Requires a beefy computer.", + "generator.minecraft.debug_all_block_states": "Debug Mode", + "generator.minecraft.flat": "Superflat", + "generator.minecraft.large_biomes": "Large Biomes", + "generator.minecraft.normal": "Default", + "generator.minecraft.single_biome_surface": "Single Biome", + "generator.single_biome_caves": "Caves", + "generator.single_biome_floating_islands": "Floating Islands", + "gui.abuseReport.attestation": "By submitting this report, you confirm that the information you have provided is accurate and complete to the best of your knowledge.", + "gui.abuseReport.comments": "Comments", + "gui.abuseReport.describe": "Sharing details will help us make a well-informed decision.", + "gui.abuseReport.discard.content": "If you leave, you'll lose this report and your comments.\nAre you sure you want to leave?", + "gui.abuseReport.discard.discard": "Leave and Discard Report", + "gui.abuseReport.discard.draft": "Save as Draft", + "gui.abuseReport.discard.return": "Continue Editing", + "gui.abuseReport.discard.title": "Discard report and comments?", + "gui.abuseReport.draft.content": "Would you like to continue editing the existing report or discard it and create a new one?", + "gui.abuseReport.draft.discard": "Discard", + "gui.abuseReport.draft.edit": "Continue Editing", + "gui.abuseReport.draft.quittotitle.content": "Would you like to continue editing it or discard it?", + "gui.abuseReport.draft.quittotitle.title": "You have a draft chat report that will be lost if you quit", + "gui.abuseReport.draft.title": "Edit draft chat report?", + "gui.abuseReport.error.title": "Problem sending your report", + "gui.abuseReport.message": "Where did you observe the bad behavior?\nThis will help us in researching your case.", + "gui.abuseReport.more_comments": "Please describe what happened:", + "gui.abuseReport.name.reporting": "You are reporting \"%s\".", + "gui.abuseReport.name.title": "Report Player Name", + "gui.abuseReport.observed_what": "Why are you reporting this?", + "gui.abuseReport.read_info": "Learn About Reporting", + "gui.abuseReport.reason.alcohol_tobacco_drugs": "Drugs or alcohol", + "gui.abuseReport.reason.alcohol_tobacco_drugs.description": "Someone is encouraging others to partake in illegal drug related activities or encouraging underage drinking.", + "gui.abuseReport.reason.child_sexual_exploitation_or_abuse": "Child sexual exploitation or abuse", + "gui.abuseReport.reason.child_sexual_exploitation_or_abuse.description": "Someone is talking about or otherwise promoting indecent behavior involving children.", + "gui.abuseReport.reason.defamation_impersonation_false_information": "Defamation", + "gui.abuseReport.reason.defamation_impersonation_false_information.description": "Someone is damaging your or someone else's reputation, for example sharing false information with the aim to exploit or mislead others.", + "gui.abuseReport.reason.description": "Description:", + "gui.abuseReport.reason.false_reporting": "False Reporting", + "gui.abuseReport.reason.generic": "I want to report them", + "gui.abuseReport.reason.generic.description": "I'm annoyed with them / they have done something I do not like.", + "gui.abuseReport.reason.harassment_or_bullying": "Harassment or bullying", + "gui.abuseReport.reason.harassment_or_bullying.description": "Someone is shaming, attacking, or bullying you or someone else. This includes when someone is repeatedly trying to contact you or someone else without consent or posting private personal information about you or someone else without consent (\"doxing\").", + "gui.abuseReport.reason.hate_speech": "Hate speech", + "gui.abuseReport.reason.hate_speech.description": "Someone is attacking you or another player based on characteristics of their identity, like religion, race, or sexuality.", + "gui.abuseReport.reason.imminent_harm": "Threat of harm to others", + "gui.abuseReport.reason.imminent_harm.description": "Someone is threatening to harm you or someone else in real life.", + "gui.abuseReport.reason.narration": "%s: %s", + "gui.abuseReport.reason.non_consensual_intimate_imagery": "Non-consensual intimate imagery", + "gui.abuseReport.reason.non_consensual_intimate_imagery.description": "Someone is talking about, sharing, or otherwise promoting private and intimate images.", + "gui.abuseReport.reason.self_harm_or_suicide": "Self-harm or suicide", + "gui.abuseReport.reason.self_harm_or_suicide.description": "Someone is threatening to harm themselves in real life or talking about harming themselves in real life.", + "gui.abuseReport.reason.terrorism_or_violent_extremism": "Terrorism or violent extremism", + "gui.abuseReport.reason.terrorism_or_violent_extremism.description": "Someone is talking about, promoting, or threatening to commit acts of terrorism or violent extremism for political, religious, ideological, or other reasons.", + "gui.abuseReport.reason.title": "Select Report Category", + "gui.abuseReport.report_sent_msg": "We’ve successfully received your report. Thank you!\n\nOur team will review it as soon as possible.", + "gui.abuseReport.select_reason": "Select Report Category", + "gui.abuseReport.send": "Send Report", + "gui.abuseReport.send.comment_too_long": "Please shorten the comment", + "gui.abuseReport.send.error_message": "An error was returned while sending your report:\n'%s'", + "gui.abuseReport.send.generic_error": "Encountered an unexpected error while sending your report.", + "gui.abuseReport.send.http_error": "An unexpected HTTP error occurred while sending your report.", + "gui.abuseReport.send.json_error": "Encountered malformed payload while sending your report.", + "gui.abuseReport.send.no_reason": "Please select a report category", + "gui.abuseReport.send.not_attested": "Please read the text above and tick the checkbox to be able to send the report", + "gui.abuseReport.send.service_unavailable": "Unable to reach the Abuse Reporting service. Please make sure you are connected to the internet and try again.", + "gui.abuseReport.sending.title": "Sending your report...", + "gui.abuseReport.sent.title": "Report sent", + "gui.abuseReport.skin.title": "Report Player Skin", + "gui.abuseReport.title": "Report Player", + "gui.abuseReport.type.chat": "Chat Messages", + "gui.abuseReport.type.name": "Player Name", + "gui.abuseReport.type.skin": "Player Skin", + "gui.acknowledge": "Acknowledge", + "gui.advancements": "Advancements", + "gui.all": "All", + "gui.back": "Back", + "gui.banned.description": "%s\n\n%s\n\nLearn more at the following link: %s", + "gui.banned.description.permanent": "Your account is permanently banned, which means you can’t play online or join Realms.", + "gui.banned.description.reason": "We recently received a report for bad behavior by your account. Our moderators have now reviewed your case and identified it as %s, which goes against the Minecraft Community Standards.", + "gui.banned.description.reason_id": "Code: %s", + "gui.banned.description.reason_id_message": "Code: %s - %s", + "gui.banned.description.temporary": "%s Until then, you can’t play online or join Realms.", + "gui.banned.description.temporary.duration": "Your account is temporarily suspended and will be reactivated in %s.", + "gui.banned.description.unknownreason": "We recently received a report for bad behavior by your account. Our moderators have now reviewed your case and identified that it goes against the Minecraft Community Standards.", + "gui.banned.name.description": "Your current name - \"%s\" - violates our Community Standards. You can play singleplayer, but will need to change your name to play online.\n\nLearn more or submit a case review at the following link: %s", + "gui.banned.name.title": "Name Not Allowed in Multiplayer", + "gui.banned.reason.defamation_impersonation_false_information": "Impersonation or sharing information to exploit or mislead others", + "gui.banned.reason.drugs": "References to illegal drugs", + "gui.banned.reason.extreme_violence_or_gore": "Depictions of real-life excessive violence or gore", + "gui.banned.reason.false_reporting": "Excessive false or inaccurate reports", + "gui.banned.reason.fraud": "Fraudulent acquisition or use of content", + "gui.banned.reason.generic_violation": "Violating Community Standards", + "gui.banned.reason.harassment_or_bullying": "Abusive language used in a directed, harmful manner", + "gui.banned.reason.hate_speech": "Hate speech or discrimination", + "gui.banned.reason.hate_terrorism_notorious_figure": "References to hate groups, terrorist organizations, or notorious figures", + "gui.banned.reason.imminent_harm_to_person_or_property": "Intent to cause real-life harm to persons or property", + "gui.banned.reason.nudity_or_pornography": "Displaying lewd or pornographic material", + "gui.banned.reason.sexually_inappropriate": "Topics or content of a sexual nature", + "gui.banned.reason.spam_or_advertising": "Spam or advertising", + "gui.banned.skin.description": "Your current skin violates our Community Standards. You can still play with a default skin, or select a new one.\n\nLearn more or submit a case review at the following link: %s", + "gui.banned.skin.title": "Skin Not Allowed", + "gui.banned.title.permanent": "Account permanently banned", + "gui.banned.title.temporary": "Account temporarily suspended", + "gui.cancel": "Cancel", + "gui.chatReport.comments": "Comments", + "gui.chatReport.describe": "Sharing details will help us make a well-informed decision.", + "gui.chatReport.discard.content": "If you leave, you'll lose this report and your comments.\nAre you sure you want to leave?", + "gui.chatReport.discard.discard": "Leave and Discard Report", + "gui.chatReport.discard.draft": "Save as Draft", + "gui.chatReport.discard.return": "Continue Editing", + "gui.chatReport.discard.title": "Discard report and comments?", + "gui.chatReport.draft.content": "Would you like to continue editing the existing report or discard it and create a new one?", + "gui.chatReport.draft.discard": "Discard", + "gui.chatReport.draft.edit": "Continue Editing", + "gui.chatReport.draft.quittotitle.content": "Would you like to continue editing it or discard it?", + "gui.chatReport.draft.quittotitle.title": "You have a draft chat report that will be lost if you quit", + "gui.chatReport.draft.title": "Edit draft chat report?", + "gui.chatReport.more_comments": "Please describe what happened:", + "gui.chatReport.observed_what": "Why are you reporting this?", + "gui.chatReport.read_info": "Learn About Reporting", + "gui.chatReport.report_sent_msg": "We’ve successfully received your report. Thank you!\n\nOur team will review it as soon as possible.", + "gui.chatReport.select_chat": "Select Chat Messages to Report", + "gui.chatReport.select_reason": "Select Report Category", + "gui.chatReport.selected_chat": "%s Chat Message(s) Selected to Report", + "gui.chatReport.send": "Send Report", + "gui.chatReport.send.comments_too_long": "Please shorten the comment", + "gui.chatReport.send.no_reason": "Please select a report category", + "gui.chatReport.send.no_reported_messages": "Please select at least one chat message to report", + "gui.chatReport.send.too_many_messages": "Trying to include too many messages in the report", + "gui.chatReport.title": "Report Player Chat", + "gui.chatSelection.context": "Messages surrounding this selection will be included to provide additional context", + "gui.chatSelection.fold": "%s message(s) hidden", + "gui.chatSelection.heading": "%s %s", + "gui.chatSelection.join": "%s joined the chat", + "gui.chatSelection.message.narrate": "%s said: %s at %s", + "gui.chatSelection.selected": "%s/%s message(s) selected", + "gui.chatSelection.title": "Select Chat Messages to Report", + "gui.continue": "Continue", + "gui.copy_link_to_clipboard": "Copy Link to Clipboard", + "gui.days": "%s day(s)", + "gui.done": "Done", + "gui.down": "Down", + "gui.entity_tooltip.type": "Type: %s", + "gui.fileDropFailure.detail": "Rejected %d files", + "gui.fileDropFailure.title": "Failed to add files", + "gui.hours": "%s hour(s)", + "gui.loadingMinecraft": "Loading Minecraft", + "gui.minutes": "%s minute(s)", + "gui.multiLineEditBox.character_limit": "%s/%s", + "gui.narrate.button": "%s button", + "gui.narrate.editBox": "%s edit box: %s", + "gui.narrate.slider": "%s slider", + "gui.narrate.tab": "%s tab", + "gui.no": "No", + "gui.none": "None", + "gui.ok": "Ok", + "gui.open_report_dir": "Open Report Directory", + "gui.proceed": "Proceed", + "gui.recipebook.moreRecipes": "Right Click for More", + "gui.recipebook.page": "%s/%s", + "gui.recipebook.search_hint": "Search...", + "gui.recipebook.toggleRecipes.all": "Showing All", + "gui.recipebook.toggleRecipes.blastable": "Showing Blastable", + "gui.recipebook.toggleRecipes.craftable": "Showing Craftable", + "gui.recipebook.toggleRecipes.smeltable": "Showing Smeltable", + "gui.recipebook.toggleRecipes.smokable": "Showing Smokable", + "gui.report_to_server": "Report To Server", + "gui.socialInteractions.blocking_hint": "Manage with Microsoft account", + "gui.socialInteractions.empty_blocked": "No blocked players in chat", + "gui.socialInteractions.empty_hidden": "No players hidden in chat", + "gui.socialInteractions.hidden_in_chat": "Chat messages from %s will be hidden", + "gui.socialInteractions.hide": "Hide in Chat", + "gui.socialInteractions.narration.hide": "Hide messages from %s", + "gui.socialInteractions.narration.report": "Report player %s", + "gui.socialInteractions.narration.show": "Show messages from %s", + "gui.socialInteractions.report": "Report", + "gui.socialInteractions.search_empty": "Couldn't find any players with that name", + "gui.socialInteractions.search_hint": "Search...", + "gui.socialInteractions.server_label.multiple": "%s - %s players", + "gui.socialInteractions.server_label.single": "%s - %s player", + "gui.socialInteractions.show": "Show in Chat", + "gui.socialInteractions.shown_in_chat": "Chat messages from %s will be shown", + "gui.socialInteractions.status_blocked": "Blocked", + "gui.socialInteractions.status_blocked_offline": "Blocked - Offline", + "gui.socialInteractions.status_hidden": "Hidden", + "gui.socialInteractions.status_hidden_offline": "Hidden - Offline", + "gui.socialInteractions.status_offline": "Offline", + "gui.socialInteractions.tab_all": "All", + "gui.socialInteractions.tab_blocked": "Blocked", + "gui.socialInteractions.tab_hidden": "Hidden", + "gui.socialInteractions.title": "Social Interactions", + "gui.socialInteractions.tooltip.hide": "Hide messages", + "gui.socialInteractions.tooltip.report": "Report player", + "gui.socialInteractions.tooltip.report.disabled": "The reporting service is unavailable", + "gui.socialInteractions.tooltip.report.no_messages": "No reportable messages from player %s", + "gui.socialInteractions.tooltip.report.not_reportable": "This player can't be reported, because their chat messages can't be verified on this server", + "gui.socialInteractions.tooltip.show": "Show messages", + "gui.stats": "Statistics", + "gui.togglable_slot": "Click to disable slot", + "gui.toMenu": "Back to Server List", + "gui.toRealms": "Back to Realms List", + "gui.toTitle": "Back to Title Screen", + "gui.toWorld": "Back to World List", + "gui.up": "Up", + "gui.yes": "Yes", + "hanging_sign.edit": "Edit Hanging Sign Message", + "instrument.minecraft.admire_goat_horn": "Admire", + "instrument.minecraft.call_goat_horn": "Call", + "instrument.minecraft.dream_goat_horn": "Dream", + "instrument.minecraft.feel_goat_horn": "Feel", + "instrument.minecraft.ponder_goat_horn": "Ponder", + "instrument.minecraft.seek_goat_horn": "Seek", + "instrument.minecraft.sing_goat_horn": "Sing", + "instrument.minecraft.yearn_goat_horn": "Yearn", + "inventory.binSlot": "Destroy Item", + "inventory.hotbarInfo": "Save hotbar with %1$s+%2$s", + "inventory.hotbarSaved": "Item hotbar saved (restore with %1$s+%2$s)", + "item_modifier.unknown": "Unknown item modifier: %s", + "item.canBreak": "Can break:", + "item.canPlace": "Can be placed on:", + "item.canUse.unknown": "Unknown", + "item.color": "Color: %s", + "item.components": "%s component(s)", + "item.disabled": "Disabled item", + "item.durability": "Durability: %s / %s", + "item.dyed": "Dyed", + "item.minecraft.acacia_boat": "Acacia Boat", + "item.minecraft.acacia_chest_boat": "Acacia Boat with Chest", + "item.minecraft.allay_spawn_egg": "Allay Spawn Egg", + "item.minecraft.amethyst_shard": "Amethyst Shard", + "item.minecraft.angler_pottery_shard": "Angler Pottery Shard", + "item.minecraft.angler_pottery_sherd": "Angler Pottery Sherd", + "item.minecraft.apple": "Apple", + "item.minecraft.archer_pottery_shard": "Archer Pottery Shard", + "item.minecraft.archer_pottery_sherd": "Archer Pottery Sherd", + "item.minecraft.armadillo_scute": "Armadillo Scute", + "item.minecraft.armadillo_spawn_egg": "Armadillo Spawn Egg", + "item.minecraft.armor_stand": "Armor Stand", + "item.minecraft.arms_up_pottery_shard": "Arms Up Pottery Shard", + "item.minecraft.arms_up_pottery_sherd": "Arms Up Pottery Sherd", + "item.minecraft.arrow": "Arrow", + "item.minecraft.axolotl_bucket": "Bucket of Axolotl", + "item.minecraft.axolotl_spawn_egg": "Axolotl Spawn Egg", + "item.minecraft.baked_potato": "Baked Potato", + "item.minecraft.bamboo_chest_raft": "Bamboo Raft with Chest", + "item.minecraft.bamboo_raft": "Bamboo Raft", + "item.minecraft.bat_spawn_egg": "Bat Spawn Egg", + "item.minecraft.bee_spawn_egg": "Bee Spawn Egg", + "item.minecraft.beef": "Raw Beef", + "item.minecraft.beetroot": "Beetroot", + "item.minecraft.beetroot_seeds": "Beetroot Seeds", + "item.minecraft.beetroot_soup": "Beetroot Soup", + "item.minecraft.birch_boat": "Birch Boat", + "item.minecraft.birch_chest_boat": "Birch Boat with Chest", + "item.minecraft.black_dye": "Black Dye", + "item.minecraft.blade_pottery_shard": "Blade Pottery Shard", + "item.minecraft.blade_pottery_sherd": "Blade Pottery Sherd", + "item.minecraft.blaze_powder": "Blaze Powder", + "item.minecraft.blaze_rod": "Blaze Rod", + "item.minecraft.blaze_spawn_egg": "Blaze Spawn Egg", + "item.minecraft.blue_dye": "Blue Dye", + "item.minecraft.bogged_spawn_egg": "Bogged Spawn Egg", + "item.minecraft.bolt_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.bone": "Bone", + "item.minecraft.bone_meal": "Bone Meal", + "item.minecraft.book": "Book", + "item.minecraft.bow": "Bow", + "item.minecraft.bowl": "Bowl", + "item.minecraft.bread": "Bread", + "item.minecraft.breeze_rod": "Breeze Rod", + "item.minecraft.breeze_spawn_egg": "Breeze Spawn Egg", + "item.minecraft.brewer_pottery_shard": "Brewer Pottery Shard", + "item.minecraft.brewer_pottery_sherd": "Brewer Pottery Sherd", + "item.minecraft.brewing_stand": "Brewing Stand", + "item.minecraft.brick": "Brick", + "item.minecraft.brown_dye": "Brown Dye", + "item.minecraft.brush": "Brush", + "item.minecraft.bucket": "Bucket", + "item.minecraft.bundle": "Bundle", + "item.minecraft.bundle.fullness": "%s/%s", + "item.minecraft.burn_pottery_shard": "Burn Pottery Shard", + "item.minecraft.burn_pottery_sherd": "Burn Pottery Sherd", + "item.minecraft.camel_spawn_egg": "Camel Spawn Egg", + "item.minecraft.carrot": "Carrot", + "item.minecraft.carrot_on_a_stick": "Carrot on a Stick", + "item.minecraft.cat_spawn_egg": "Cat Spawn Egg", + "item.minecraft.cauldron": "Cauldron", + "item.minecraft.cave_spider_spawn_egg": "Cave Spider Spawn Egg", + "item.minecraft.chainmail_boots": "Chainmail Boots", + "item.minecraft.chainmail_chestplate": "Chainmail Chestplate", + "item.minecraft.chainmail_helmet": "Chainmail Helmet", + "item.minecraft.chainmail_leggings": "Chainmail Leggings", + "item.minecraft.charcoal": "Charcoal", + "item.minecraft.cherry_boat": "Cherry Boat", + "item.minecraft.cherry_chest_boat": "Cherry Boat with Chest", + "item.minecraft.chest_minecart": "Minecart with Chest", + "item.minecraft.chicken": "Raw Chicken", + "item.minecraft.chicken_spawn_egg": "Chicken Spawn Egg", + "item.minecraft.chorus_fruit": "Chorus Fruit", + "item.minecraft.clay_ball": "Clay Ball", + "item.minecraft.clock": "Clock", + "item.minecraft.coal": "Coal", + "item.minecraft.coast_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.cocoa_beans": "Cocoa Beans", + "item.minecraft.cod": "Raw Cod", + "item.minecraft.cod_bucket": "Bucket of Cod", + "item.minecraft.cod_spawn_egg": "Cod Spawn Egg", + "item.minecraft.command_block_minecart": "Minecart with Command Block", + "item.minecraft.compass": "Compass", + "item.minecraft.cooked_beef": "Steak", + "item.minecraft.cooked_chicken": "Cooked Chicken", + "item.minecraft.cooked_cod": "Cooked Cod", + "item.minecraft.cooked_mutton": "Cooked Mutton", + "item.minecraft.cooked_porkchop": "Cooked Porkchop", + "item.minecraft.cooked_rabbit": "Cooked Rabbit", + "item.minecraft.cooked_salmon": "Cooked Salmon", + "item.minecraft.cookie": "Cookie", + "item.minecraft.copper_ingot": "Copper Ingot", + "item.minecraft.cow_spawn_egg": "Cow Spawn Egg", + "item.minecraft.creeper_banner_pattern": "Banner Pattern", + "item.minecraft.creeper_banner_pattern.desc": "Creeper Charge", + "item.minecraft.creeper_spawn_egg": "Creeper Spawn Egg", + "item.minecraft.crossbow": "Crossbow", + "item.minecraft.crossbow.projectile": "Projectile:", + "item.minecraft.cyan_dye": "Cyan Dye", + "item.minecraft.danger_pottery_shard": "Danger Pottery Shard", + "item.minecraft.danger_pottery_sherd": "Danger Pottery Sherd", + "item.minecraft.dark_oak_boat": "Dark Oak Boat", + "item.minecraft.dark_oak_chest_boat": "Dark Oak Boat with Chest", + "item.minecraft.debug_stick": "Debug Stick", + "item.minecraft.debug_stick.empty": "%s has no properties", + "item.minecraft.debug_stick.select": "selected \"%s\" (%s)", + "item.minecraft.debug_stick.update": "\"%s\" to %s", + "item.minecraft.diamond": "Diamond", + "item.minecraft.diamond_axe": "Diamond Axe", + "item.minecraft.diamond_boots": "Diamond Boots", + "item.minecraft.diamond_chestplate": "Diamond Chestplate", + "item.minecraft.diamond_helmet": "Diamond Helmet", + "item.minecraft.diamond_hoe": "Diamond Hoe", + "item.minecraft.diamond_horse_armor": "Diamond Horse Armor", + "item.minecraft.diamond_leggings": "Diamond Leggings", + "item.minecraft.diamond_pickaxe": "Diamond Pickaxe", + "item.minecraft.diamond_shovel": "Diamond Shovel", + "item.minecraft.diamond_sword": "Diamond Sword", + "item.minecraft.disc_fragment_5": "Disc Fragment", + "item.minecraft.disc_fragment_5.desc": "Music Disc - 5", + "item.minecraft.dolphin_spawn_egg": "Dolphin Spawn Egg", + "item.minecraft.donkey_spawn_egg": "Donkey Spawn Egg", + "item.minecraft.dragon_breath": "Dragon's Breath", + "item.minecraft.dried_kelp": "Dried Kelp", + "item.minecraft.drowned_spawn_egg": "Drowned Spawn Egg", + "item.minecraft.dune_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.echo_shard": "Echo Shard", + "item.minecraft.egg": "Egg", + "item.minecraft.elder_guardian_spawn_egg": "Elder Guardian Spawn Egg", + "item.minecraft.elytra": "Elytra", + "item.minecraft.emerald": "Emerald", + "item.minecraft.enchanted_book": "Enchanted Book", + "item.minecraft.enchanted_golden_apple": "Enchanted Golden Apple", + "item.minecraft.end_crystal": "End Crystal", + "item.minecraft.ender_dragon_spawn_egg": "Ender Dragon Spawn Egg", + "item.minecraft.ender_eye": "Eye of Ender", + "item.minecraft.ender_pearl": "Ender Pearl", + "item.minecraft.enderman_spawn_egg": "Enderman Spawn Egg", + "item.minecraft.endermite_spawn_egg": "Endermite Spawn Egg", + "item.minecraft.evoker_spawn_egg": "Evoker Spawn Egg", + "item.minecraft.experience_bottle": "Bottle o' Enchanting", + "item.minecraft.explorer_pottery_shard": "Explorer Pottery Shard", + "item.minecraft.explorer_pottery_sherd": "Explorer Pottery Sherd", + "item.minecraft.eye_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.feather": "Feather", + "item.minecraft.fermented_spider_eye": "Fermented Spider Eye", + "item.minecraft.filled_map": "Map", + "item.minecraft.fire_charge": "Fire Charge", + "item.minecraft.firework_rocket": "Firework Rocket", + "item.minecraft.firework_rocket.flight": "Flight Duration:", + "item.minecraft.firework_star": "Firework Star", + "item.minecraft.firework_star.black": "Black", + "item.minecraft.firework_star.blue": "Blue", + "item.minecraft.firework_star.brown": "Brown", + "item.minecraft.firework_star.custom_color": "Custom", + "item.minecraft.firework_star.cyan": "Cyan", + "item.minecraft.firework_star.fade_to": "Fade to", + "item.minecraft.firework_star.flicker": "Twinkle", + "item.minecraft.firework_star.gray": "Gray", + "item.minecraft.firework_star.green": "Green", + "item.minecraft.firework_star.light_blue": "Light Blue", + "item.minecraft.firework_star.light_gray": "Light Gray", + "item.minecraft.firework_star.lime": "Lime", + "item.minecraft.firework_star.magenta": "Magenta", + "item.minecraft.firework_star.orange": "Orange", + "item.minecraft.firework_star.pink": "Pink", + "item.minecraft.firework_star.purple": "Purple", + "item.minecraft.firework_star.red": "Red", + "item.minecraft.firework_star.shape": "Unknown Shape", + "item.minecraft.firework_star.shape.burst": "Burst", + "item.minecraft.firework_star.shape.creeper": "Creeper-shaped", + "item.minecraft.firework_star.shape.large_ball": "Large Ball", + "item.minecraft.firework_star.shape.small_ball": "Small Ball", + "item.minecraft.firework_star.shape.star": "Star-shaped", + "item.minecraft.firework_star.trail": "Trail", + "item.minecraft.firework_star.white": "White", + "item.minecraft.firework_star.yellow": "Yellow", + "item.minecraft.fishing_rod": "Fishing Rod", + "item.minecraft.flint": "Flint", + "item.minecraft.flint_and_steel": "Flint and Steel", + "item.minecraft.flow_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.flow_banner_pattern": "Banner Pattern", + "item.minecraft.flow_banner_pattern.desc": "Flow", + "item.minecraft.flow_pottery_sherd": "Flow Pottery Sherd", + "item.minecraft.flower_banner_pattern": "Banner Pattern", + "item.minecraft.flower_banner_pattern.desc": "Flower Charge", + "item.minecraft.flower_pot": "Flower Pot", + "item.minecraft.fox_spawn_egg": "Fox Spawn Egg", + "item.minecraft.friend_pottery_shard": "Friend Pottery Shard", + "item.minecraft.friend_pottery_sherd": "Friend Pottery Sherd", + "item.minecraft.frog_spawn_egg": "Frog Spawn Egg", + "item.minecraft.furnace_minecart": "Minecart with Furnace", + "item.minecraft.ghast_spawn_egg": "Ghast Spawn Egg", + "item.minecraft.ghast_tear": "Ghast Tear", + "item.minecraft.glass_bottle": "Glass Bottle", + "item.minecraft.glistering_melon_slice": "Glistering Melon Slice", + "item.minecraft.globe_banner_pattern": "Banner Pattern", + "item.minecraft.globe_banner_pattern.desc": "Globe", + "item.minecraft.glow_berries": "Glow Berries", + "item.minecraft.glow_ink_sac": "Glow Ink Sac", + "item.minecraft.glow_item_frame": "Glow Item Frame", + "item.minecraft.glow_squid_spawn_egg": "Glow Squid Spawn Egg", + "item.minecraft.glowstone_dust": "Glowstone Dust", + "item.minecraft.goat_horn": "Goat Horn", + "item.minecraft.goat_spawn_egg": "Goat Spawn Egg", + "item.minecraft.gold_ingot": "Gold Ingot", + "item.minecraft.gold_nugget": "Gold Nugget", + "item.minecraft.golden_apple": "Golden Apple", + "item.minecraft.golden_axe": "Golden Axe", + "item.minecraft.golden_boots": "Golden Boots", + "item.minecraft.golden_carrot": "Golden Carrot", + "item.minecraft.golden_chestplate": "Golden Chestplate", + "item.minecraft.golden_helmet": "Golden Helmet", + "item.minecraft.golden_hoe": "Golden Hoe", + "item.minecraft.golden_horse_armor": "Golden Horse Armor", + "item.minecraft.golden_leggings": "Golden Leggings", + "item.minecraft.golden_pickaxe": "Golden Pickaxe", + "item.minecraft.golden_shovel": "Golden Shovel", + "item.minecraft.golden_sword": "Golden Sword", + "item.minecraft.gray_dye": "Gray Dye", + "item.minecraft.green_dye": "Green Dye", + "item.minecraft.guardian_spawn_egg": "Guardian Spawn Egg", + "item.minecraft.gunpowder": "Gunpowder", + "item.minecraft.guster_banner_pattern": "Banner Pattern", + "item.minecraft.guster_banner_pattern.desc": "Guster", + "item.minecraft.guster_pottery_sherd": "Guster Pottery Sherd", + "item.minecraft.heart_of_the_sea": "Heart of the Sea", + "item.minecraft.heart_pottery_shard": "Heart Pottery Shard", + "item.minecraft.heart_pottery_sherd": "Heart Pottery Sherd", + "item.minecraft.heartbreak_pottery_shard": "Heartbreak Pottery Shard", + "item.minecraft.heartbreak_pottery_sherd": "Heartbreak Pottery Sherd", + "item.minecraft.hoglin_spawn_egg": "Hoglin Spawn Egg", + "item.minecraft.honey_bottle": "Honey Bottle", + "item.minecraft.honeycomb": "Honeycomb", + "item.minecraft.hopper_minecart": "Minecart with Hopper", + "item.minecraft.horse_spawn_egg": "Horse Spawn Egg", + "item.minecraft.host_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.howl_pottery_shard": "Howl Pottery Shard", + "item.minecraft.howl_pottery_sherd": "Howl Pottery Sherd", + "item.minecraft.husk_spawn_egg": "Husk Spawn Egg", + "item.minecraft.ink_sac": "Ink Sac", + "item.minecraft.iron_axe": "Iron Axe", + "item.minecraft.iron_boots": "Iron Boots", + "item.minecraft.iron_chestplate": "Iron Chestplate", + "item.minecraft.iron_golem_spawn_egg": "Iron Golem Spawn Egg", + "item.minecraft.iron_helmet": "Iron Helmet", + "item.minecraft.iron_hoe": "Iron Hoe", + "item.minecraft.iron_horse_armor": "Iron Horse Armor", + "item.minecraft.iron_ingot": "Iron Ingot", + "item.minecraft.iron_leggings": "Iron Leggings", + "item.minecraft.iron_nugget": "Iron Nugget", + "item.minecraft.iron_pickaxe": "Iron Pickaxe", + "item.minecraft.iron_shovel": "Iron Shovel", + "item.minecraft.iron_sword": "Iron Sword", + "item.minecraft.item_frame": "Item Frame", + "item.minecraft.jungle_boat": "Jungle Boat", + "item.minecraft.jungle_chest_boat": "Jungle Boat with Chest", + "item.minecraft.knowledge_book": "Knowledge Book", + "item.minecraft.lapis_lazuli": "Lapis Lazuli", + "item.minecraft.lava_bucket": "Lava Bucket", + "item.minecraft.lead": "Lead", + "item.minecraft.leather": "Leather", + "item.minecraft.leather_boots": "Leather Boots", + "item.minecraft.leather_chestplate": "Leather Tunic", + "item.minecraft.leather_helmet": "Leather Cap", + "item.minecraft.leather_horse_armor": "Leather Horse Armor", + "item.minecraft.leather_leggings": "Leather Pants", + "item.minecraft.light_blue_dye": "Light Blue Dye", + "item.minecraft.light_gray_dye": "Light Gray Dye", + "item.minecraft.lime_dye": "Lime Dye", + "item.minecraft.lingering_potion": "Lingering Potion", + "item.minecraft.lingering_potion.effect.awkward": "Awkward Lingering Potion", + "item.minecraft.lingering_potion.effect.empty": "Lingering Uncraftable Potion", + "item.minecraft.lingering_potion.effect.fire_resistance": "Lingering Potion of Fire Resistance", + "item.minecraft.lingering_potion.effect.harming": "Lingering Potion of Harming", + "item.minecraft.lingering_potion.effect.healing": "Lingering Potion of Healing", + "item.minecraft.lingering_potion.effect.infested": "Lingering Potion of Infestation", + "item.minecraft.lingering_potion.effect.invisibility": "Lingering Potion of Invisibility", + "item.minecraft.lingering_potion.effect.leaping": "Lingering Potion of Leaping", + "item.minecraft.lingering_potion.effect.levitation": "Lingering Potion of Levitation", + "item.minecraft.lingering_potion.effect.luck": "Lingering Potion of Luck", + "item.minecraft.lingering_potion.effect.mundane": "Mundane Lingering Potion", + "item.minecraft.lingering_potion.effect.night_vision": "Lingering Potion of Night Vision", + "item.minecraft.lingering_potion.effect.oozing": "Lingering Potion of Oozing", + "item.minecraft.lingering_potion.effect.poison": "Lingering Potion of Poison", + "item.minecraft.lingering_potion.effect.regeneration": "Lingering Potion of Regeneration", + "item.minecraft.lingering_potion.effect.slow_falling": "Lingering Potion of Slow Falling", + "item.minecraft.lingering_potion.effect.slowness": "Lingering Potion of Slowness", + "item.minecraft.lingering_potion.effect.strength": "Lingering Potion of Strength", + "item.minecraft.lingering_potion.effect.swiftness": "Lingering Potion of Swiftness", + "item.minecraft.lingering_potion.effect.thick": "Thick Lingering Potion", + "item.minecraft.lingering_potion.effect.turtle_master": "Lingering Potion of the Turtle Master", + "item.minecraft.lingering_potion.effect.water": "Lingering Water Bottle", + "item.minecraft.lingering_potion.effect.water_breathing": "Lingering Potion of Water Breathing", + "item.minecraft.lingering_potion.effect.weakness": "Lingering Potion of Weakness", + "item.minecraft.lingering_potion.effect.weaving": "Lingering Potion of Weaving", + "item.minecraft.lingering_potion.effect.wind_charged": "Lingering Potion of Wind Charging", + "item.minecraft.llama_spawn_egg": "Llama Spawn Egg", + "item.minecraft.lodestone_compass": "Lodestone Compass", + "item.minecraft.mace": "Mace", + "item.minecraft.magenta_dye": "Magenta Dye", + "item.minecraft.magma_cream": "Magma Cream", + "item.minecraft.magma_cube_spawn_egg": "Magma Cube Spawn Egg", + "item.minecraft.mangrove_boat": "Mangrove Boat", + "item.minecraft.mangrove_chest_boat": "Mangrove Boat with Chest", + "item.minecraft.map": "Empty Map", + "item.minecraft.melon_seeds": "Melon Seeds", + "item.minecraft.melon_slice": "Melon Slice", + "item.minecraft.milk_bucket": "Milk Bucket", + "item.minecraft.minecart": "Minecart", + "item.minecraft.miner_pottery_shard": "Miner Pottery Shard", + "item.minecraft.miner_pottery_sherd": "Miner Pottery Sherd", + "item.minecraft.mojang_banner_pattern": "Banner Pattern", + "item.minecraft.mojang_banner_pattern.desc": "Thing", + "item.minecraft.mooshroom_spawn_egg": "Mooshroom Spawn Egg", + "item.minecraft.mourner_pottery_shard": "Mourner Pottery Shard", + "item.minecraft.mourner_pottery_sherd": "Mourner Pottery Sherd", + "item.minecraft.mule_spawn_egg": "Mule Spawn Egg", + "item.minecraft.mushroom_stew": "Mushroom Stew", + "item.minecraft.music_disc_5": "Music Disc", + "item.minecraft.music_disc_5.desc": "Samuel Åberg - 5", + "item.minecraft.music_disc_11": "Music Disc", + "item.minecraft.music_disc_11.desc": "C418 - 11", + "item.minecraft.music_disc_13": "Music Disc", + "item.minecraft.music_disc_13.desc": "C418 - 13", + "item.minecraft.music_disc_blocks": "Music Disc", + "item.minecraft.music_disc_blocks.desc": "C418 - blocks", + "item.minecraft.music_disc_cat": "Music Disc", + "item.minecraft.music_disc_cat.desc": "C418 - cat", + "item.minecraft.music_disc_chirp": "Music Disc", + "item.minecraft.music_disc_chirp.desc": "C418 - chirp", + "item.minecraft.music_disc_creator": "Music Disc", + "item.minecraft.music_disc_creator_music_box": "Music Disc", + "item.minecraft.music_disc_creator_music_box.desc": "Lena Raine - Creator (Music Box)", + "item.minecraft.music_disc_creator.desc": "Lena Raine - Creator", + "item.minecraft.music_disc_far": "Music Disc", + "item.minecraft.music_disc_far.desc": "C418 - far", + "item.minecraft.music_disc_mall": "Music Disc", + "item.minecraft.music_disc_mall.desc": "C418 - mall", + "item.minecraft.music_disc_mellohi": "Music Disc", + "item.minecraft.music_disc_mellohi.desc": "C418 - mellohi", + "item.minecraft.music_disc_otherside": "Music Disc", + "item.minecraft.music_disc_otherside.desc": "Lena Raine - otherside", + "item.minecraft.music_disc_pigstep": "Music Disc", + "item.minecraft.music_disc_pigstep.desc": "Lena Raine - Pigstep", + "item.minecraft.music_disc_precipice": "Music Disc", + "item.minecraft.music_disc_precipice.desc": "Aaron Cherof - Precipice", + "item.minecraft.music_disc_relic": "Music Disc", + "item.minecraft.music_disc_relic.desc": "Aaron Cherof - Relic", + "item.minecraft.music_disc_stal": "Music Disc", + "item.minecraft.music_disc_stal.desc": "C418 - stal", + "item.minecraft.music_disc_strad": "Music Disc", + "item.minecraft.music_disc_strad.desc": "C418 - strad", + "item.minecraft.music_disc_wait": "Music Disc", + "item.minecraft.music_disc_wait.desc": "C418 - wait", + "item.minecraft.music_disc_ward": "Music Disc", + "item.minecraft.music_disc_ward.desc": "C418 - ward", + "item.minecraft.mutton": "Raw Mutton", + "item.minecraft.name_tag": "Name Tag", + "item.minecraft.nautilus_shell": "Nautilus Shell", + "item.minecraft.nether_brick": "Nether Brick", + "item.minecraft.nether_star": "Nether Star", + "item.minecraft.nether_wart": "Nether Wart", + "item.minecraft.netherite_axe": "Netherite Axe", + "item.minecraft.netherite_boots": "Netherite Boots", + "item.minecraft.netherite_chestplate": "Netherite Chestplate", + "item.minecraft.netherite_helmet": "Netherite Helmet", + "item.minecraft.netherite_hoe": "Netherite Hoe", + "item.minecraft.netherite_ingot": "Netherite Ingot", + "item.minecraft.netherite_leggings": "Netherite Leggings", + "item.minecraft.netherite_pickaxe": "Netherite Pickaxe", + "item.minecraft.netherite_scrap": "Netherite Scrap", + "item.minecraft.netherite_shovel": "Netherite Shovel", + "item.minecraft.netherite_sword": "Netherite Sword", + "item.minecraft.netherite_upgrade_smithing_template": "Smithing Template", + "item.minecraft.oak_boat": "Oak Boat", + "item.minecraft.oak_chest_boat": "Oak Boat with Chest", + "item.minecraft.ocelot_spawn_egg": "Ocelot Spawn Egg", + "item.minecraft.ominous_bottle": "Ominous Bottle", + "item.minecraft.ominous_trial_key": "Ominous Trial Key", + "item.minecraft.orange_dye": "Orange Dye", + "item.minecraft.painting": "Painting", + "item.minecraft.panda_spawn_egg": "Panda Spawn Egg", + "item.minecraft.paper": "Paper", + "item.minecraft.parrot_spawn_egg": "Parrot Spawn Egg", + "item.minecraft.phantom_membrane": "Phantom Membrane", + "item.minecraft.phantom_spawn_egg": "Phantom Spawn Egg", + "item.minecraft.pig_spawn_egg": "Pig Spawn Egg", + "item.minecraft.piglin_banner_pattern": "Banner Pattern", + "item.minecraft.piglin_banner_pattern.desc": "Snout", + "item.minecraft.piglin_brute_spawn_egg": "Piglin Brute Spawn Egg", + "item.minecraft.piglin_spawn_egg": "Piglin Spawn Egg", + "item.minecraft.pillager_spawn_egg": "Pillager Spawn Egg", + "item.minecraft.pink_dye": "Pink Dye", + "item.minecraft.pitcher_plant": "Pitcher Plant", + "item.minecraft.pitcher_pod": "Pitcher Pod", + "item.minecraft.plenty_pottery_shard": "Plenty Pottery Shard", + "item.minecraft.plenty_pottery_sherd": "Plenty Pottery Sherd", + "item.minecraft.poisonous_potato": "Poisonous Potato", + "item.minecraft.polar_bear_spawn_egg": "Polar Bear Spawn Egg", + "item.minecraft.popped_chorus_fruit": "Popped Chorus Fruit", + "item.minecraft.porkchop": "Raw Porkchop", + "item.minecraft.potato": "Potato", + "item.minecraft.potion": "Potion", + "item.minecraft.potion.effect.awkward": "Awkward Potion", + "item.minecraft.potion.effect.empty": "Uncraftable Potion", + "item.minecraft.potion.effect.fire_resistance": "Potion of Fire Resistance", + "item.minecraft.potion.effect.harming": "Potion of Harming", + "item.minecraft.potion.effect.healing": "Potion of Healing", + "item.minecraft.potion.effect.infested": "Potion of Infestation", + "item.minecraft.potion.effect.invisibility": "Potion of Invisibility", + "item.minecraft.potion.effect.leaping": "Potion of Leaping", + "item.minecraft.potion.effect.levitation": "Potion of Levitation", + "item.minecraft.potion.effect.luck": "Potion of Luck", + "item.minecraft.potion.effect.mundane": "Mundane Potion", + "item.minecraft.potion.effect.night_vision": "Potion of Night Vision", + "item.minecraft.potion.effect.oozing": "Potion of Oozing", + "item.minecraft.potion.effect.poison": "Potion of Poison", + "item.minecraft.potion.effect.regeneration": "Potion of Regeneration", + "item.minecraft.potion.effect.slow_falling": "Potion of Slow Falling", + "item.minecraft.potion.effect.slowness": "Potion of Slowness", + "item.minecraft.potion.effect.strength": "Potion of Strength", + "item.minecraft.potion.effect.swiftness": "Potion of Swiftness", + "item.minecraft.potion.effect.thick": "Thick Potion", + "item.minecraft.potion.effect.turtle_master": "Potion of the Turtle Master", + "item.minecraft.potion.effect.water": "Water Bottle", + "item.minecraft.potion.effect.water_breathing": "Potion of Water Breathing", + "item.minecraft.potion.effect.weakness": "Potion of Weakness", + "item.minecraft.potion.effect.weaving": "Potion of Weaving", + "item.minecraft.potion.effect.wind_charged": "Potion of Wind Charging", + "item.minecraft.pottery_shard_archer": "Archer Pottery Shard", + "item.minecraft.pottery_shard_arms_up": "Arms Up Pottery Shard", + "item.minecraft.pottery_shard_prize": "Prize Pottery Shard", + "item.minecraft.pottery_shard_skull": "Skull Pottery Shard", + "item.minecraft.powder_snow_bucket": "Powder Snow Bucket", + "item.minecraft.prismarine_crystals": "Prismarine Crystals", + "item.minecraft.prismarine_shard": "Prismarine Shard", + "item.minecraft.prize_pottery_shard": "Prize Pottery Shard", + "item.minecraft.prize_pottery_sherd": "Prize Pottery Sherd", + "item.minecraft.pufferfish": "Pufferfish", + "item.minecraft.pufferfish_bucket": "Bucket of Pufferfish", + "item.minecraft.pufferfish_spawn_egg": "Pufferfish Spawn Egg", + "item.minecraft.pumpkin_pie": "Pumpkin Pie", + "item.minecraft.pumpkin_seeds": "Pumpkin Seeds", + "item.minecraft.purple_dye": "Purple Dye", + "item.minecraft.quartz": "Nether Quartz", + "item.minecraft.rabbit": "Raw Rabbit", + "item.minecraft.rabbit_foot": "Rabbit's Foot", + "item.minecraft.rabbit_hide": "Rabbit Hide", + "item.minecraft.rabbit_spawn_egg": "Rabbit Spawn Egg", + "item.minecraft.rabbit_stew": "Rabbit Stew", + "item.minecraft.raiser_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.ravager_spawn_egg": "Ravager Spawn Egg", + "item.minecraft.raw_copper": "Raw Copper", + "item.minecraft.raw_gold": "Raw Gold", + "item.minecraft.raw_iron": "Raw Iron", + "item.minecraft.recovery_compass": "Recovery Compass", + "item.minecraft.red_dye": "Red Dye", + "item.minecraft.redstone": "Redstone Dust", + "item.minecraft.rib_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.rotten_flesh": "Rotten Flesh", + "item.minecraft.saddle": "Saddle", + "item.minecraft.salmon": "Raw Salmon", + "item.minecraft.salmon_bucket": "Bucket of Salmon", + "item.minecraft.salmon_spawn_egg": "Salmon Spawn Egg", + "item.minecraft.scrape_pottery_sherd": "Scrape Pottery Sherd", + "item.minecraft.scute": "Scute", + "item.minecraft.sentry_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.shaper_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.sheaf_pottery_shard": "Sheaf Pottery Shard", + "item.minecraft.sheaf_pottery_sherd": "Sheaf Pottery Sherd", + "item.minecraft.shears": "Shears", + "item.minecraft.sheep_spawn_egg": "Sheep Spawn Egg", + "item.minecraft.shelter_pottery_shard": "Shelter Pottery Shard", + "item.minecraft.shelter_pottery_sherd": "Shelter Pottery Sherd", + "item.minecraft.shield": "Shield", + "item.minecraft.shield.black": "Black Shield", + "item.minecraft.shield.blue": "Blue Shield", + "item.minecraft.shield.brown": "Brown Shield", + "item.minecraft.shield.cyan": "Cyan Shield", + "item.minecraft.shield.gray": "Gray Shield", + "item.minecraft.shield.green": "Green Shield", + "item.minecraft.shield.light_blue": "Light Blue Shield", + "item.minecraft.shield.light_gray": "Light Gray Shield", + "item.minecraft.shield.lime": "Lime Shield", + "item.minecraft.shield.magenta": "Magenta Shield", + "item.minecraft.shield.orange": "Orange Shield", + "item.minecraft.shield.pink": "Pink Shield", + "item.minecraft.shield.purple": "Purple Shield", + "item.minecraft.shield.red": "Red Shield", + "item.minecraft.shield.white": "White Shield", + "item.minecraft.shield.yellow": "Yellow Shield", + "item.minecraft.shulker_shell": "Shulker Shell", + "item.minecraft.shulker_spawn_egg": "Shulker Spawn Egg", + "item.minecraft.sign": "Sign", + "item.minecraft.silence_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.silverfish_spawn_egg": "Silverfish Spawn Egg", + "item.minecraft.skeleton_horse_spawn_egg": "Skeleton Horse Spawn Egg", + "item.minecraft.skeleton_spawn_egg": "Skeleton Spawn Egg", + "item.minecraft.skull_banner_pattern": "Banner Pattern", + "item.minecraft.skull_banner_pattern.desc": "Skull Charge", + "item.minecraft.skull_pottery_shard": "Skull Pottery Shard", + "item.minecraft.skull_pottery_sherd": "Skull Pottery Sherd", + "item.minecraft.slime_ball": "Slimeball", + "item.minecraft.slime_spawn_egg": "Slime Spawn Egg", + "item.minecraft.smithing_template": "Smithing Template", + "item.minecraft.smithing_template.applies_to": "Applies to:", + "item.minecraft.smithing_template.armor_trim.additions_slot_description": "Add ingot or crystal", + "item.minecraft.smithing_template.armor_trim.applies_to": "Armor", + "item.minecraft.smithing_template.armor_trim.base_slot_description": "Add a piece of armor", + "item.minecraft.smithing_template.armor_trim.ingredients": "Ingots & Crystals", + "item.minecraft.smithing_template.ingredients": "Ingredients:", + "item.minecraft.smithing_template.netherite_upgrade.additions_slot_description": "Add Netherite Ingot", + "item.minecraft.smithing_template.netherite_upgrade.applies_to": "Diamond Equipment", + "item.minecraft.smithing_template.netherite_upgrade.base_slot_description": "Add diamond armor, weapon, or tool", + "item.minecraft.smithing_template.netherite_upgrade.ingredients": "Netherite Ingot", + "item.minecraft.smithing_template.upgrade": "Upgrade: ", + "item.minecraft.sniffer_spawn_egg": "Sniffer Spawn Egg", + "item.minecraft.snort_pottery_shard": "Snort Pottery Shard", + "item.minecraft.snort_pottery_sherd": "Snort Pottery Sherd", + "item.minecraft.snout_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.snow_golem_spawn_egg": "Snow Golem Spawn Egg", + "item.minecraft.snowball": "Snowball", + "item.minecraft.spectral_arrow": "Spectral Arrow", + "item.minecraft.spider_eye": "Spider Eye", + "item.minecraft.spider_spawn_egg": "Spider Spawn Egg", + "item.minecraft.spire_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.splash_potion": "Splash Potion", + "item.minecraft.splash_potion.effect.awkward": "Awkward Splash Potion", + "item.minecraft.splash_potion.effect.empty": "Splash Uncraftable Potion", + "item.minecraft.splash_potion.effect.fire_resistance": "Splash Potion of Fire Resistance", + "item.minecraft.splash_potion.effect.harming": "Splash Potion of Harming", + "item.minecraft.splash_potion.effect.healing": "Splash Potion of Healing", + "item.minecraft.splash_potion.effect.infested": "Splash Potion of Infestation", + "item.minecraft.splash_potion.effect.invisibility": "Splash Potion of Invisibility", + "item.minecraft.splash_potion.effect.leaping": "Splash Potion of Leaping", + "item.minecraft.splash_potion.effect.levitation": "Splash Potion of Levitation", + "item.minecraft.splash_potion.effect.luck": "Splash Potion of Luck", + "item.minecraft.splash_potion.effect.mundane": "Mundane Splash Potion", + "item.minecraft.splash_potion.effect.night_vision": "Splash Potion of Night Vision", + "item.minecraft.splash_potion.effect.oozing": "Splash Potion of Oozing", + "item.minecraft.splash_potion.effect.poison": "Splash Potion of Poison", + "item.minecraft.splash_potion.effect.regeneration": "Splash Potion of Regeneration", + "item.minecraft.splash_potion.effect.slow_falling": "Splash Potion of Slow Falling", + "item.minecraft.splash_potion.effect.slowness": "Splash Potion of Slowness", + "item.minecraft.splash_potion.effect.strength": "Splash Potion of Strength", + "item.minecraft.splash_potion.effect.swiftness": "Splash Potion of Swiftness", + "item.minecraft.splash_potion.effect.thick": "Thick Splash Potion", + "item.minecraft.splash_potion.effect.turtle_master": "Splash Potion of the Turtle Master", + "item.minecraft.splash_potion.effect.water": "Splash Water Bottle", + "item.minecraft.splash_potion.effect.water_breathing": "Splash Potion of Water Breathing", + "item.minecraft.splash_potion.effect.weakness": "Splash Potion of Weakness", + "item.minecraft.splash_potion.effect.weaving": "Splash Potion of Weaving", + "item.minecraft.splash_potion.effect.wind_charged": "Splash Potion of Wind Charging", + "item.minecraft.spruce_boat": "Spruce Boat", + "item.minecraft.spruce_chest_boat": "Spruce Boat with Chest", + "item.minecraft.spyglass": "Spyglass", + "item.minecraft.squid_spawn_egg": "Squid Spawn Egg", + "item.minecraft.stick": "Stick", + "item.minecraft.stone_axe": "Stone Axe", + "item.minecraft.stone_hoe": "Stone Hoe", + "item.minecraft.stone_pickaxe": "Stone Pickaxe", + "item.minecraft.stone_shovel": "Stone Shovel", + "item.minecraft.stone_sword": "Stone Sword", + "item.minecraft.stray_spawn_egg": "Stray Spawn Egg", + "item.minecraft.strider_spawn_egg": "Strider Spawn Egg", + "item.minecraft.string": "String", + "item.minecraft.sugar": "Sugar", + "item.minecraft.suspicious_stew": "Suspicious Stew", + "item.minecraft.sweet_berries": "Sweet Berries", + "item.minecraft.tadpole_bucket": "Bucket of Tadpole", + "item.minecraft.tadpole_spawn_egg": "Tadpole Spawn Egg", + "item.minecraft.tide_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.tipped_arrow": "Tipped Arrow", + "item.minecraft.tipped_arrow.effect.awkward": "Tipped Arrow", + "item.minecraft.tipped_arrow.effect.empty": "Uncraftable Tipped Arrow", + "item.minecraft.tipped_arrow.effect.fire_resistance": "Arrow of Fire Resistance", + "item.minecraft.tipped_arrow.effect.harming": "Arrow of Harming", + "item.minecraft.tipped_arrow.effect.healing": "Arrow of Healing", + "item.minecraft.tipped_arrow.effect.infested": "Arrow of Infestation", + "item.minecraft.tipped_arrow.effect.invisibility": "Arrow of Invisibility", + "item.minecraft.tipped_arrow.effect.leaping": "Arrow of Leaping", + "item.minecraft.tipped_arrow.effect.levitation": "Arrow of Levitation", + "item.minecraft.tipped_arrow.effect.luck": "Arrow of Luck", + "item.minecraft.tipped_arrow.effect.mundane": "Tipped Arrow", + "item.minecraft.tipped_arrow.effect.night_vision": "Arrow of Night Vision", + "item.minecraft.tipped_arrow.effect.oozing": "Arrow of Oozing", + "item.minecraft.tipped_arrow.effect.poison": "Arrow of Poison", + "item.minecraft.tipped_arrow.effect.regeneration": "Arrow of Regeneration", + "item.minecraft.tipped_arrow.effect.slow_falling": "Arrow of Slow Falling", + "item.minecraft.tipped_arrow.effect.slowness": "Arrow of Slowness", + "item.minecraft.tipped_arrow.effect.strength": "Arrow of Strength", + "item.minecraft.tipped_arrow.effect.swiftness": "Arrow of Swiftness", + "item.minecraft.tipped_arrow.effect.thick": "Tipped Arrow", + "item.minecraft.tipped_arrow.effect.turtle_master": "Arrow of the Turtle Master", + "item.minecraft.tipped_arrow.effect.water": "Arrow of Splashing", + "item.minecraft.tipped_arrow.effect.water_breathing": "Arrow of Water Breathing", + "item.minecraft.tipped_arrow.effect.weakness": "Arrow of Weakness", + "item.minecraft.tipped_arrow.effect.weaving": "Arrow of Weaving", + "item.minecraft.tipped_arrow.effect.wind_charged": "Arrow of Wind Charging", + "item.minecraft.tnt_minecart": "Minecart with TNT", + "item.minecraft.torchflower_seeds": "Torchflower Seeds", + "item.minecraft.totem_of_undying": "Totem of Undying", + "item.minecraft.trader_llama_spawn_egg": "Trader Llama Spawn Egg", + "item.minecraft.trial_key": "Trial Key", + "item.minecraft.trident": "Trident", + "item.minecraft.tropical_fish": "Tropical Fish", + "item.minecraft.tropical_fish_bucket": "Bucket of Tropical Fish", + "item.minecraft.tropical_fish_spawn_egg": "Tropical Fish Spawn Egg", + "item.minecraft.turtle_helmet": "Turtle Shell", + "item.minecraft.turtle_scute": "Turtle Scute", + "item.minecraft.turtle_spawn_egg": "Turtle Spawn Egg", + "item.minecraft.vex_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.vex_spawn_egg": "Vex Spawn Egg", + "item.minecraft.villager_spawn_egg": "Villager Spawn Egg", + "item.minecraft.vindicator_spawn_egg": "Vindicator Spawn Egg", + "item.minecraft.wandering_trader_spawn_egg": "Wandering Trader Spawn Egg", + "item.minecraft.ward_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.warden_spawn_egg": "Warden Spawn Egg", + "item.minecraft.warped_fungus_on_a_stick": "Warped Fungus on a Stick", + "item.minecraft.water_bucket": "Water Bucket", + "item.minecraft.wayfinder_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.wheat": "Wheat", + "item.minecraft.wheat_seeds": "Wheat Seeds", + "item.minecraft.white_dye": "White Dye", + "item.minecraft.wild_armor_trim_smithing_template": "Smithing Template", + "item.minecraft.wind_charge": "Wind Charge", + "item.minecraft.witch_spawn_egg": "Witch Spawn Egg", + "item.minecraft.wither_skeleton_spawn_egg": "Wither Skeleton Spawn Egg", + "item.minecraft.wither_spawn_egg": "Wither Spawn Egg", + "item.minecraft.wolf_armor": "Wolf Armor", + "item.minecraft.wolf_spawn_egg": "Wolf Spawn Egg", + "item.minecraft.wooden_axe": "Wooden Axe", + "item.minecraft.wooden_hoe": "Wooden Hoe", + "item.minecraft.wooden_pickaxe": "Wooden Pickaxe", + "item.minecraft.wooden_shovel": "Wooden Shovel", + "item.minecraft.wooden_sword": "Wooden Sword", + "item.minecraft.writable_book": "Book and Quill", + "item.minecraft.written_book": "Written Book", + "item.minecraft.yellow_dye": "Yellow Dye", + "item.minecraft.zoglin_spawn_egg": "Zoglin Spawn Egg", + "item.minecraft.zombie_horse_spawn_egg": "Zombie Horse Spawn Egg", + "item.minecraft.zombie_spawn_egg": "Zombie Spawn Egg", + "item.minecraft.zombie_villager_spawn_egg": "Zombie Villager Spawn Egg", + "item.minecraft.zombified_piglin_spawn_egg": "Zombified Piglin Spawn Egg", + "item.modifiers.any": "When equipped:", + "item.modifiers.armor": "When worn:", + "item.modifiers.body": "When equipped:", + "item.modifiers.chest": "When on Body:", + "item.modifiers.feet": "When on Feet:", + "item.modifiers.hand": "When held:", + "item.modifiers.head": "When on Head:", + "item.modifiers.legs": "When on Legs:", + "item.modifiers.mainhand": "When in Main Hand:", + "item.modifiers.offhand": "When in Off Hand:", + "item.nbt_tags": "NBT: %s tag(s)", + "item.unbreakable": "Unbreakable", + "itemGroup.buildingBlocks": "Building Blocks", + "itemGroup.coloredBlocks": "Colored Blocks", + "itemGroup.combat": "Combat", + "itemGroup.consumables": "Consumables", + "itemGroup.crafting": "Crafting", + "itemGroup.foodAndDrink": "Food & Drinks", + "itemGroup.functional": "Functional Blocks", + "itemGroup.hotbar": "Saved Hotbars", + "itemGroup.ingredients": "Ingredients", + "itemGroup.inventory": "Survival Inventory", + "itemGroup.natural": "Natural Blocks", + "itemGroup.op": "Operator Utilities", + "itemGroup.redstone": "Redstone Blocks", + "itemGroup.search": "Search Items", + "itemGroup.spawnEggs": "Spawn Eggs", + "itemGroup.tools": "Tools & Utilities", + "jigsaw_block.final_state": "Turns into:", + "jigsaw_block.generate": "Generate", + "jigsaw_block.joint_label": "Joint Type:", + "jigsaw_block.joint.aligned": "Aligned", + "jigsaw_block.joint.rollable": "Rollable", + "jigsaw_block.keep_jigsaws": "Keep Jigsaws", + "jigsaw_block.levels": "Levels: %s", + "jigsaw_block.name": "Name:", + "jigsaw_block.placement_priority": "Placement Priority:", + "jigsaw_block.placement_priority.tooltip": "When this Jigsaw block connects to a piece, this is the order in which that piece is processed for connections in the wider structure.\n\nPieces will be processed in descending priority with insertion order breaking ties.", + "jigsaw_block.pool": "Target Pool:", + "jigsaw_block.selection_priority": "Selection Priority:", + "jigsaw_block.selection_priority.tooltip": "When the parent piece is being processed for connections, this is the order in which this Jigsaw block attempts to connect to its target piece.\n\nJigsaws will be processed in descending priority with random ordering breaking ties.", + "jigsaw_block.target": "Target Name:", + "jukebox_song.minecraft.5": "Samuel Åberg - 5", + "jukebox_song.minecraft.11": "C418 - 11", + "jukebox_song.minecraft.13": "C418 - 13", + "jukebox_song.minecraft.blocks": "C418 - blocks", + "jukebox_song.minecraft.cat": "C418 - cat", + "jukebox_song.minecraft.chirp": "C418 - chirp", + "jukebox_song.minecraft.creator": "Lena Raine - Creator", + "jukebox_song.minecraft.creator_music_box": "Lena Raine - Creator (Music Box)", + "jukebox_song.minecraft.far": "C418 - far", + "jukebox_song.minecraft.mall": "C418 - mall", + "jukebox_song.minecraft.mellohi": "C418 - mellohi", + "jukebox_song.minecraft.otherside": "Lena Raine - otherside", + "jukebox_song.minecraft.pigstep": "Lena Raine - Pigstep", + "jukebox_song.minecraft.precipice": "Aaron Cherof - Precipice", + "jukebox_song.minecraft.relic": "Aaron Cherof - Relic", + "jukebox_song.minecraft.stal": "C418 - stal", + "jukebox_song.minecraft.strad": "C418 - strad", + "jukebox_song.minecraft.wait": "C418 - wait", + "jukebox_song.minecraft.ward": "C418 - ward", + "key.advancements": "Advancements", + "key.attack": "Attack/Destroy", + "key.back": "Walk Backwards", + "key.categories.creative": "Creative Mode", + "key.categories.gameplay": "Gameplay", + "key.categories.inventory": "Inventory", + "key.categories.misc": "Miscellaneous", + "key.categories.movement": "Movement", + "key.categories.multiplayer": "Multiplayer", + "key.categories.ui": "Game Interface", + "key.chat": "Open Chat", + "key.command": "Open Command", + "key.drop": "Drop Selected Item", + "key.forward": "Walk Forwards", + "key.fullscreen": "Toggle Fullscreen", + "key.hotbar.1": "Hotbar Slot 1", + "key.hotbar.2": "Hotbar Slot 2", + "key.hotbar.3": "Hotbar Slot 3", + "key.hotbar.4": "Hotbar Slot 4", + "key.hotbar.5": "Hotbar Slot 5", + "key.hotbar.6": "Hotbar Slot 6", + "key.hotbar.7": "Hotbar Slot 7", + "key.hotbar.8": "Hotbar Slot 8", + "key.hotbar.9": "Hotbar Slot 9", + "key.inventory": "Open/Close Inventory", + "key.jump": "Jump", + "key.keyboard.apostrophe": "'", + "key.keyboard.backslash": "\\", + "key.keyboard.backspace": "Backspace", + "key.keyboard.caps.lock": "Caps Lock", + "key.keyboard.comma": ",", + "key.keyboard.delete": "Delete", + "key.keyboard.down": "Down Arrow", + "key.keyboard.end": "End", + "key.keyboard.enter": "Enter", + "key.keyboard.equal": "=", + "key.keyboard.escape": "Escape", + "key.keyboard.f1": "F1", + "key.keyboard.f2": "F2", + "key.keyboard.f3": "F3", + "key.keyboard.f4": "F4", + "key.keyboard.f5": "F5", + "key.keyboard.f6": "F6", + "key.keyboard.f7": "F7", + "key.keyboard.f8": "F8", + "key.keyboard.f9": "F9", + "key.keyboard.f10": "F10", + "key.keyboard.f11": "F11", + "key.keyboard.f12": "F12", + "key.keyboard.f13": "F13", + "key.keyboard.f14": "F14", + "key.keyboard.f15": "F15", + "key.keyboard.f16": "F16", + "key.keyboard.f17": "F17", + "key.keyboard.f18": "F18", + "key.keyboard.f19": "F19", + "key.keyboard.f20": "F20", + "key.keyboard.f21": "F21", + "key.keyboard.f22": "F22", + "key.keyboard.f23": "F23", + "key.keyboard.f24": "F24", + "key.keyboard.f25": "F25", + "key.keyboard.grave.accent": "`", + "key.keyboard.home": "Home", + "key.keyboard.insert": "Insert", + "key.keyboard.keypad.0": "Keypad 0", + "key.keyboard.keypad.1": "Keypad 1", + "key.keyboard.keypad.2": "Keypad 2", + "key.keyboard.keypad.3": "Keypad 3", + "key.keyboard.keypad.4": "Keypad 4", + "key.keyboard.keypad.5": "Keypad 5", + "key.keyboard.keypad.6": "Keypad 6", + "key.keyboard.keypad.7": "Keypad 7", + "key.keyboard.keypad.8": "Keypad 8", + "key.keyboard.keypad.9": "Keypad 9", + "key.keyboard.keypad.add": "Keypad +", + "key.keyboard.keypad.decimal": "Keypad Decimal", + "key.keyboard.keypad.divide": "Keypad /", + "key.keyboard.keypad.enter": "Keypad Enter", + "key.keyboard.keypad.equal": "Keypad =", + "key.keyboard.keypad.multiply": "Keypad *", + "key.keyboard.keypad.subtract": "Keypad -", + "key.keyboard.left": "Left Arrow", + "key.keyboard.left.alt": "Left Alt", + "key.keyboard.left.bracket": "[", + "key.keyboard.left.control": "Left Control", + "key.keyboard.left.shift": "Left Shift", + "key.keyboard.left.win": "Left Win", + "key.keyboard.menu": "Menu", + "key.keyboard.minus": "-", + "key.keyboard.num.lock": "Num Lock", + "key.keyboard.page.down": "Page Down", + "key.keyboard.page.up": "Page Up", + "key.keyboard.pause": "Pause", + "key.keyboard.period": ".", + "key.keyboard.print.screen": "Print Screen", + "key.keyboard.right": "Right Arrow", + "key.keyboard.right.alt": "Right Alt", + "key.keyboard.right.bracket": "]", + "key.keyboard.right.control": "Right Control", + "key.keyboard.right.shift": "Right Shift", + "key.keyboard.right.win": "Right Win", + "key.keyboard.scroll.lock": "Scroll Lock", + "key.keyboard.semicolon": ";", + "key.keyboard.slash": "/", + "key.keyboard.space": "Space", + "key.keyboard.tab": "Tab", + "key.keyboard.unknown": "Not Bound", + "key.keyboard.up": "Up Arrow", + "key.keyboard.world.1": "World 1", + "key.keyboard.world.2": "World 2", + "key.left": "Strafe Left", + "key.loadToolbarActivator": "Load Hotbar Activator", + "key.mouse": "Button %1$s", + "key.mouse.left": "Left Button", + "key.mouse.middle": "Middle Button", + "key.mouse.right": "Right Button", + "key.pickItem": "Pick Block", + "key.playerlist": "List Players", + "key.right": "Strafe Right", + "key.saveToolbarActivator": "Save Hotbar Activator", + "key.screenshot": "Take Screenshot", + "key.smoothCamera": "Toggle Cinematic Camera", + "key.sneak": "Sneak", + "key.socialInteractions": "Social Interactions Screen", + "key.spectatorOutlines": "Highlight Players (Spectators)", + "key.sprint": "Sprint", + "key.swapOffhand": "Swap Item With Off Hand", + "key.togglePerspective": "Toggle Perspective", + "key.use": "Use Item/Place Block", + "known_server_link.announcements": "Announcements", + "known_server_link.community": "Community", + "known_server_link.community_guidelines": "Community Guidelines", + "known_server_link.feedback": "Feedback", + "known_server_link.forums": "Forums", + "known_server_link.news": "News", + "known_server_link.report_bug": "Report Server Bug", + "known_server_link.status": "Status", + "known_server_link.support": "Support", + "known_server_link.website": "Website", + "language.code": "en_us", + "language.name": "English", + "language.region": "United States", + "lanServer.otherPlayers": "Settings for Other Players", + "lanServer.port": "Port Number", + "lanServer.port.invalid": "Not a valid port.\nLeave the edit box empty or enter a number between 1024 and 65535.", + "lanServer.port.invalid.new": "Not a valid port.\nLeave the edit box empty or enter a number between %s and %s.", + "lanServer.port.unavailable": "Port not available.\nLeave the edit box empty or enter a different number between 1024 and 65535.", + "lanServer.port.unavailable.new": "Port not available.\nLeave the edit box empty or enter a different number between %s and %s.", + "lanServer.scanning": "Scanning for games on your local network", + "lanServer.start": "Start LAN World", + "lanServer.title": "LAN World", + "lectern.take_book": "Take Book", + "loading.progress": "%s%%", + "mco.account.privacy.info": "Read more about Mojang and privacy laws", + "mco.account.privacy.info.button": "Read more about GDPR", + "mco.account.privacy.information": "Mojang implements certain procedures to help protect children and their privacy including complying with the Children’s Online Privacy Protection Act (COPPA) and General Data Protection Regulation (GDPR).\n\nYou may need to obtain parental consent before accessing your Realms account.", + "mco.account.privacyinfo": "Mojang implements certain procedures to help protect children and their privacy including complying with the Children’s Online Privacy Protection Act (COPPA) and General Data Protection Regulation (GDPR).\n\nYou may need to obtain parental consent before accessing your Realms account.\n\nIf you have an older Minecraft account (you log in with your username), you need to migrate the account to a Mojang account in order to access Realms.", + "mco.account.update": "Update account", + "mco.activity.noactivity": "No activity for the past %s day(s)", + "mco.activity.title": "Player activity", + "mco.backup.button.download": "Download Latest", + "mco.backup.button.reset": "Reset World", + "mco.backup.button.restore": "Restore", + "mco.backup.button.upload": "Upload World", + "mco.backup.changes.tooltip": "Changes", + "mco.backup.entry": "Backup (%s)", + "mco.backup.entry.description": "Description", + "mco.backup.entry.enabledPack": "Enabled Pack(s)", + "mco.backup.entry.gameDifficulty": "Game Difficulty", + "mco.backup.entry.gameMode": "Game Mode", + "mco.backup.entry.gameServerVersion": "Game Server Version", + "mco.backup.entry.name": "Name", + "mco.backup.entry.seed": "Seed", + "mco.backup.entry.templateName": "Template Name", + "mco.backup.entry.undefined": "Undefined Change", + "mco.backup.entry.uploaded": "Uploaded", + "mco.backup.entry.worldType": "World Type", + "mco.backup.generate.world": "Generate world", + "mco.backup.info.title": "Changes From Last Backup", + "mco.backup.narration": "Backup from %s", + "mco.backup.nobackups": "This realm doesn't have any backups currently.", + "mco.backup.restoring": "Restoring your realm", + "mco.backup.unknown": "UNKNOWN", + "mco.brokenworld.download": "Download", + "mco.brokenworld.downloaded": "Downloaded", + "mco.brokenworld.message.line1": "Please reset or select another world.", + "mco.brokenworld.message.line2": "You can also choose to download the world to singleplayer.", + "mco.brokenworld.minigame.title": "This minigame is no longer supported", + "mco.brokenworld.nonowner.error": "Please wait for the realm owner to reset the world", + "mco.brokenworld.nonowner.title": "World is out of date", + "mco.brokenworld.play": "Play", + "mco.brokenworld.reset": "Reset", + "mco.brokenworld.title": "Your current world is no longer supported", + "mco.client.incompatible.msg.line1": "Your client is not compatible with Realms.", + "mco.client.incompatible.msg.line2": "Please use the most recent version of Minecraft.", + "mco.client.incompatible.msg.line3": "Realms is not compatible with snapshot versions.", + "mco.client.incompatible.title": "Client incompatible!", + "mco.client.outdated.stable.version": "Your client version (%s) is not compatible with Realms.\n\nPlease use the most recent version of Minecraft.", + "mco.client.unsupported.snapshot.version": "Your client version (%s) is not compatible with Realms.\n\nRealms is not available for this snapshot version.", + "mco.compatibility.downgrade": "Downgrade", + "mco.compatibility.downgrade.description": "This world was last played in version %s; you are on version %s. Downgrading a world could cause corruption - we cannot guarantee that it will load or work.\n\nA backup of your world will be saved under \"World Backups\". Please restore your world if needed.", + "mco.compatibility.incompatible.popup.title": "Incompatible version", + "mco.compatibility.incompatible.releaseType.popup.message": "The world you are trying to join is incompatible with the version you are on.", + "mco.compatibility.incompatible.series.popup.message": "This world was last played in version %s; you are on version %s.\n\nThese series are not compatible with each other. A new world is needed to play on this version.", + "mco.compatibility.unverifiable.message": "The version this world was last played in could not be verified. If the world gets upgraded or downgraded, a backup will be automatically created and saved under \"World Backups\".", + "mco.compatibility.unverifiable.title": "Compatibility not verifiable", + "mco.compatibility.upgrade": "Upgrade", + "mco.compatibility.upgrade.description": "This world was last played in version %s; you are on version %s.\n\nA backup of your world will be saved under \"World Backups\".\n\nPlease restore your world if needed.", + "mco.compatibility.upgrade.friend.description": "This world was last played in version %s; you are on version %s.\n\nA backup of the world will be saved under \"World Backups\".\n\nThe owner of the Realm can restore the world if needed.", + "mco.compatibility.upgrade.title": "Do you really want to upgrade this world?", + "mco.configure.current.minigame": "Current", + "mco.configure.world.activityfeed.disabled": "Player feed temporarily disabled", + "mco.configure.world.backup": "World Backups", + "mco.configure.world.buttons.activity": "Player activity", + "mco.configure.world.buttons.close": "Close Realm", + "mco.configure.world.buttons.delete": "Delete", + "mco.configure.world.buttons.done": "Done", + "mco.configure.world.buttons.edit": "Settings", + "mco.configure.world.buttons.invite": "Invite Player", + "mco.configure.world.buttons.moreoptions": "More options", + "mco.configure.world.buttons.open": "Open Realm", + "mco.configure.world.buttons.options": "World Options", + "mco.configure.world.buttons.players": "Players", + "mco.configure.world.buttons.resetworld": "Reset World", + "mco.configure.world.buttons.settings": "Settings", + "mco.configure.world.buttons.subscription": "Subscription", + "mco.configure.world.buttons.switchminigame": "Switch Minigame", + "mco.configure.world.close.question.line1": "Your realm will become unavailable.", + "mco.configure.world.close.question.line2": "Are you sure you want to continue?", + "mco.configure.world.closing": "Closing the realm...", + "mco.configure.world.commandBlocks": "Command Blocks", + "mco.configure.world.delete.button": "Delete Realm", + "mco.configure.world.delete.question.line1": "Your realm will be permanently deleted", + "mco.configure.world.delete.question.line2": "Are you sure you want to continue?", + "mco.configure.world.description": "Realm Description", + "mco.configure.world.edit.slot.name": "World Name", + "mco.configure.world.edit.subscreen.adventuremap": "Some settings are disabled since your current world is an adventure", + "mco.configure.world.edit.subscreen.experience": "Some settings are disabled since your current world is an experience", + "mco.configure.world.edit.subscreen.inspiration": "Some settings are disabled since your current world is an inspiration", + "mco.configure.world.forceGameMode": "Force Game Mode", + "mco.configure.world.invite.narration": "You have %s new invite(s)", + "mco.configure.world.invite.profile.name": "Name", + "mco.configure.world.invited": "Invited", + "mco.configure.world.invited.number": "Invited (%s)", + "mco.configure.world.invites.normal.tooltip": "Normal User", + "mco.configure.world.invites.ops.tooltip": "Operator", + "mco.configure.world.invites.remove.tooltip": "Remove", + "mco.configure.world.leave.question.line1": "If you leave this realm you won't see it unless you are invited again", + "mco.configure.world.leave.question.line2": "Are you sure you want to continue?", + "mco.configure.world.location": "Location", + "mco.configure.world.minigame": "Current: %s", + "mco.configure.world.name": "Realm Name", + "mco.configure.world.opening": "Opening the realm...", + "mco.configure.world.players.error": "A player with the provided name does not exist", + "mco.configure.world.players.inviting": "Inviting player...", + "mco.configure.world.players.title": "Players", + "mco.configure.world.pvp": "PVP", + "mco.configure.world.reset.question.line1": "Your world will be regenerated and your current world will be lost", + "mco.configure.world.reset.question.line2": "Are you sure you want to continue?", + "mco.configure.world.resourcepack.question": "You need a custom resource pack to play on this realm\n\nDo you want to download it and play?", + "mco.configure.world.resourcepack.question.line1": "You need a custom resource pack to play on this realm", + "mco.configure.world.resourcepack.question.line2": "Do you want to download it and play?", + "mco.configure.world.restore.download.question.line1": "The world will be downloaded and added to your single player worlds.", + "mco.configure.world.restore.download.question.line2": "Do you want to continue?", + "mco.configure.world.restore.question.line1": "Your world will be restored to date '%s' (%s)", + "mco.configure.world.restore.question.line2": "Are you sure you want to continue?", + "mco.configure.world.settings.title": "Settings", + "mco.configure.world.slot": "World %s", + "mco.configure.world.slot.empty": "Empty", + "mco.configure.world.slot.switch.question.line1": "Your realm will be switched to another world", + "mco.configure.world.slot.switch.question.line2": "Are you sure you want to continue?", + "mco.configure.world.slot.tooltip": "Switch to world", + "mco.configure.world.slot.tooltip.active": "Join", + "mco.configure.world.slot.tooltip.minigame": "Switch to minigame", + "mco.configure.world.spawn_toggle.message": "Turning this option off will remove all existing entities of that type", + "mco.configure.world.spawn_toggle.message.npc": "Turning this option off will remove all existing entities of that type, like Villagers", + "mco.configure.world.spawn_toggle.title": "Warning!", + "mco.configure.world.spawnAnimals": "Spawn Animals", + "mco.configure.world.spawnMonsters": "Spawn Monsters", + "mco.configure.world.spawnNPCs": "Spawn NPCs", + "mco.configure.world.spawnProtection": "Spawn Protection", + "mco.configure.world.status": "Status", + "mco.configure.world.subscription.day": "day", + "mco.configure.world.subscription.days": "days", + "mco.configure.world.subscription.expired": "Expired", + "mco.configure.world.subscription.extend": "Extend Subscription", + "mco.configure.world.subscription.less_than_a_day": "Less than a day", + "mco.configure.world.subscription.month": "month", + "mco.configure.world.subscription.months": "months", + "mco.configure.world.subscription.recurring.daysleft": "Renewed automatically in", + "mco.configure.world.subscription.recurring.info": "Changes made to your Realms subscription such as stacking time or turning off recurring billing will not be reflected until your next bill date.", + "mco.configure.world.subscription.remaining.days": "%1$s day(s)", + "mco.configure.world.subscription.remaining.months": "%1$s month(s)", + "mco.configure.world.subscription.remaining.months.days": "%1$s month(s), %2$s day(s)", + "mco.configure.world.subscription.start": "Start Date", + "mco.configure.world.subscription.timeleft": "Time Left", + "mco.configure.world.subscription.title": "Your Subscription", + "mco.configure.world.subscription.unknown": "Unknown", + "mco.configure.world.switch.slot": "Create World", + "mco.configure.world.switch.slot.subtitle": "This world is empty, choose how to create your world", + "mco.configure.world.title": "Configure Realm:", + "mco.configure.world.uninvite.player": "Are you sure that you want to uninvite '%s'?", + "mco.configure.world.uninvite.question": "Are you sure that you want to uninvite", + "mco.configure.worlds.title": "Worlds", + "mco.connect.authorizing": "Logging in...", + "mco.connect.connecting": "Connecting to the realm...", + "mco.connect.failed": "Failed to connect to the realm", + "mco.connect.success": "Done", + "mco.create.world": "Create", + "mco.create.world.error": "You must enter a name!", + "mco.create.world.reset.title": "Creating world...", + "mco.create.world.skip": "Skip", + "mco.create.world.subtitle": "Optionally, select what world to put on your new realm", + "mco.create.world.wait": "Creating the realm...", + "mco.download.cancelled": "Download cancelled", + "mco.download.confirmation.line1": "The world you are going to download is larger than %s", + "mco.download.confirmation.line2": "You won't be able to upload this world to your realm again", + "mco.download.confirmation.oversized": "The world you are going to download is larger than %s\n\nYou won't be able to upload this world to your realm again", + "mco.download.done": "Download done", + "mco.download.downloading": "Downloading", + "mco.download.extracting": "Extracting", + "mco.download.failed": "Download failed", + "mco.download.percent": "%s %%", + "mco.download.preparing": "Preparing download", + "mco.download.resourcePack.fail": "Failed to download resource pack!", + "mco.download.speed": "(%s/s)", + "mco.download.speed.narration": "%s/s", + "mco.download.title": "Downloading Latest World", + "mco.error.invalid.session.message": "Please try restarting Minecraft", + "mco.error.invalid.session.title": "Invalid Session", + "mco.errorMessage.6001": "Client outdated", + "mco.errorMessage.6002": "Terms of service not accepted", + "mco.errorMessage.6003": "Download limit reached", + "mco.errorMessage.6004": "Upload limit reached", + "mco.errorMessage.6005": "World locked", + "mco.errorMessage.6006": "World is out of date", + "mco.errorMessage.6007": "User in too many Realms", + "mco.errorMessage.6008": "Invalid Realm name", + "mco.errorMessage.6009": "Invalid Realm description", + "mco.errorMessage.connectionFailure": "An error occurred, please try again later.", + "mco.errorMessage.generic": "An error occurred: ", + "mco.errorMessage.noDetails": "No error details provided", + "mco.errorMessage.realmsService": "An error occurred (%s):", + "mco.errorMessage.realmsService.connectivity": "Could not connect to Realms: %s", + "mco.errorMessage.realmsService.realmsError": "Realms (%s):", + "mco.errorMessage.realmsService.unknownCompatibility": "Could not check compatible version, got response: %s", + "mco.errorMessage.retry": "Retry operation", + "mco.errorMessage.serviceBusy": "Realms is busy at the moment.\nPlease try connecting to your Realm again in a couple of minutes.", + "mco.gui.button": "Button", + "mco.gui.ok": "Ok", + "mco.info": "Info!", + "mco.invited.player.narration": "Invited player %s", + "mco.invites.button.accept": "Accept", + "mco.invites.button.reject": "Reject", + "mco.invites.nopending": "No pending invites!", + "mco.invites.pending": "New invite(s)!", + "mco.invites.title": "Pending Invites", + "mco.minigame.world.changeButton": "Select Another Minigame", + "mco.minigame.world.info.line1": "This will temporarily replace your world with a minigame!", + "mco.minigame.world.info.line2": "You can later return to your original world without losing anything.", + "mco.minigame.world.noSelection": "Please make a selection", + "mco.minigame.world.restore": "Ending Minigame...", + "mco.minigame.world.restore.question.line1": "The minigame will end and your realm will be restored.", + "mco.minigame.world.restore.question.line2": "Are you sure you want to continue?", + "mco.minigame.world.selected": "Selected Minigame:", + "mco.minigame.world.slot.screen.title": "Switching World...", + "mco.minigame.world.startButton": "Switch", + "mco.minigame.world.starting.screen.title": "Starting Minigame...", + "mco.minigame.world.stopButton": "End Minigame", + "mco.minigame.world.switch.new": "Select another minigame?", + "mco.minigame.world.switch.title": "Switch Minigame", + "mco.minigame.world.title": "Switch Realm to Minigame", + "mco.news": "Realms news", + "mco.notification.dismiss": "Dismiss", + "mco.notification.transferSubscription.buttonText": "Transfer Now", + "mco.notification.transferSubscription.message": "Java Realms subscriptions are moving to the Microsoft Store. Do not let your subscription expire!\nTransfer now and get 30 days of Realms for free.\nGo to Profile on minecraft.net to transfer your subscription.", + "mco.notification.visitUrl.buttonText.default": "Open Link", + "mco.notification.visitUrl.message.default": "Please visit the link below", + "mco.onlinePlayers": "Online Players", + "mco.question": "Question", + "mco.reset.world.adventure": "Adventures", + "mco.reset.world.experience": "Experiences", + "mco.reset.world.generate": "New World", + "mco.reset.world.inspiration": "Inspiration", + "mco.reset.world.resetting.screen.title": "Resetting world...", + "mco.reset.world.seed": "Seed (Optional)", + "mco.reset.world.template": "World Templates", + "mco.reset.world.title": "Reset World", + "mco.reset.world.upload": "Upload world", + "mco.reset.world.warning": "This will replace the current world of your realm", + "mco.selectServer.buy": "Buy a Realm!", + "mco.selectServer.close": "Close", + "mco.selectServer.closed": "Closed realm", + "mco.selectServer.closeserver": "Close realm", + "mco.selectServer.configure": "Configure", + "mco.selectServer.configureRealm": "Configure realm", + "mco.selectServer.create": "Create Realm", + "mco.selectServer.create.subtitle": "Select what world to put on your new realm", + "mco.selectServer.expired": "Expired realm", + "mco.selectServer.expiredList": "Your subscription has expired", + "mco.selectServer.expiredRenew": "Renew", + "mco.selectServer.expiredSubscribe": "Subscribe", + "mco.selectServer.expiredTrial": "Your trial has ended", + "mco.selectServer.expires.day": "Expires in a day", + "mco.selectServer.expires.days": "Expires in %s days", + "mco.selectServer.expires.soon": "Expires soon", + "mco.selectServer.leave": "Leave Realm", + "mco.selectServer.loading": "Loading Realms List", + "mco.selectServer.mapOnlySupportedForVersion": "This map is unsupported in %s", + "mco.selectServer.minigame": "Minigame:", + "mco.selectServer.minigameName": "Minigame: %s", + "mco.selectServer.minigameNotSupportedInVersion": "Can't play this minigame in %s", + "mco.selectServer.noRealms": "You don't seem to have a Realm. Add a Realm to play together with your friends.", + "mco.selectServer.note": "Note:", + "mco.selectServer.open": "Open realm", + "mco.selectServer.openserver": "Open realm", + "mco.selectServer.play": "Play", + "mco.selectServer.popup": "Realms is a safe, simple way to enjoy an online Minecraft world with up to ten friends at a time. It supports loads of minigames and plenty of custom worlds! Only the owner of the realm needs to pay.", + "mco.selectServer.purchase": "Add Realm", + "mco.selectServer.trial": "Get a Trial!", + "mco.selectServer.uninitialized": "Click to start your new realm!", + "mco.snapshot.createSnapshotPopup.text": "You are about to create a free Snapshot Realm that will be paired with your paid Realms subscription. This new Snapshot Realm will be accessible for as long as the paid subscription is active. Your paid Realm will not be affected.", + "mco.snapshot.createSnapshotPopup.title": "Create Snapshot Realm?", + "mco.snapshot.creating": "Creating Snapshot Realm...", + "mco.snapshot.description": "Paired with \"%s\"", + "mco.snapshot.friendsRealm.downgrade": "You need to be on version %s to join this Realm", + "mco.snapshot.friendsRealm.upgrade": "%s needs to upgrade their Realm before you can play from this version", + "mco.snapshot.paired": "This Snapshot Realm is paired with \"%s\"", + "mco.snapshot.parent.tooltip": "Use the latest release of Minecraft to play on this Realm", + "mco.snapshot.start": "Start free Snapshot Realm", + "mco.snapshot.subscription.info": "This is a Snapshot Realm that is paired to the subscription of your Realm '%s'. It will stay active for as long as its paired Realm is.", + "mco.snapshot.tooltip": "Use Snapshot Realms to get a sneak peek at upcoming versions of Minecraft, which might include new features and other changes.\n\nYou can find your normal Realms in the release version of the game.", + "mco.snapshotRealmsPopup.message": "Realms are now available in Snapshots starting with Snapshot 23w41a. Every Realms subscription comes with a free Snapshot Realm that is separate from your normal Java Realm!", + "mco.snapshotRealmsPopup.title": "Realms now available in Snapshots", + "mco.snapshotRealmsPopup.urlText": "Learn More", + "mco.template.button.publisher": "Publisher", + "mco.template.button.select": "Select", + "mco.template.button.trailer": "Trailer", + "mco.template.default.name": "World template", + "mco.template.info.tooltip": "Publisher website", + "mco.template.name": "Template", + "mco.template.select.failure": "We couldn't retrieve the list of content for this category.\nPlease check your internet connection, or try again later.", + "mco.template.select.narrate.authors": "Authors: %s", + "mco.template.select.narrate.version": "version %s", + "mco.template.select.none": "Oops, it looks like this content category is currently empty.\nPlease check back later for new content, or if you're a creator,\n%s.", + "mco.template.select.none.linkTitle": "consider submitting something yourself", + "mco.template.title": "World templates", + "mco.template.title.minigame": "Minigames", + "mco.template.trailer.tooltip": "Map trailer", + "mco.terms.buttons.agree": "Agree", + "mco.terms.buttons.disagree": "Don't agree", + "mco.terms.sentence.1": "I agree to the Minecraft Realms", + "mco.terms.sentence.2": "Terms of Service", + "mco.terms.title": "Realms Terms of Service", + "mco.time.daysAgo": "%1$s day(s) ago", + "mco.time.hoursAgo": "%1$s hour(s) ago", + "mco.time.minutesAgo": "%1$s minute(s) ago", + "mco.time.now": "right now", + "mco.time.secondsAgo": "%1$s second(s) ago", + "mco.trial.message.line1": "Want to get your own realm?", + "mco.trial.message.line2": "Click here for more info!", + "mco.upload.button.name": "Upload", + "mco.upload.cancelled": "Upload cancelled", + "mco.upload.close.failure": "Could not close your realm, please try again later", + "mco.upload.done": "Upload done", + "mco.upload.entry.cheats": "%1$s, %2$s", + "mco.upload.entry.commands": "%1$s, %2$s", + "mco.upload.entry.id": "%1$s (%2$s)", + "mco.upload.failed": "Upload failed! (%s)", + "mco.upload.hardcore": "Hardcore worlds can't be uploaded!", + "mco.upload.percent": "%s %%", + "mco.upload.preparing": "Preparing your world", + "mco.upload.select.world.none": "No singleplayer worlds found!", + "mco.upload.select.world.subtitle": "Please select a singleplayer world to upload", + "mco.upload.select.world.title": "Upload World", + "mco.upload.size.failure.line1": "'%s' is too big!", + "mco.upload.size.failure.line2": "It is %s. The maximum allowed size is %s.", + "mco.upload.uploading": "Uploading '%s'", + "mco.upload.verifying": "Verifying your world", + "mco.version": "Version: %s", + "mco.warning": "Warning!", + "mco.worldSlot.minigame": "Minigame", + "menu.convertingLevel": "Converting world", + "menu.disconnect": "Disconnect", + "menu.feedback": "Feedback...", + "menu.feedback.title": "Feedback", + "menu.game": "Game Menu", + "menu.generatingLevel": "Generating world", + "menu.generatingTerrain": "Building terrain", + "menu.loadingForcedChunks": "Loading forced chunks for dimension %s", + "menu.loadingLevel": "Loading world", + "menu.modded": " (Modded)", + "menu.multiplayer": "Multiplayer", + "menu.online": "Minecraft Realms", + "menu.options": "Options...", + "menu.paused": "Game Paused", + "menu.playdemo": "Play Demo World", + "menu.playerReporting": "Player Reporting", + "menu.preparingSpawn": "Preparing spawn area: %s%%", + "menu.quit": "Quit Game", + "menu.reportBugs": "Report Bugs", + "menu.resetdemo": "Reset Demo World", + "menu.respawning": "Respawning", + "menu.returnToGame": "Back to Game", + "menu.returnToMenu": "Save and Quit to Title", + "menu.savingChunks": "Saving chunks", + "menu.savingLevel": "Saving world", + "menu.sendFeedback": "Give Feedback", + "menu.server_links": "Server Links...", + "menu.server_links.title": "Server Links", + "menu.shareToLan": "Open to LAN", + "menu.singleplayer": "Singleplayer", + "menu.working": "Working...", + "merchant.current_level": "Trader's current level", + "merchant.deprecated": "Villagers restock up to two times per day.", + "merchant.level.1": "Novice", + "merchant.level.2": "Apprentice", + "merchant.level.3": "Journeyman", + "merchant.level.4": "Expert", + "merchant.level.5": "Master", + "merchant.next_level": "Trader's next level", + "merchant.title": "%s - %s", + "merchant.trades": "Trades", + "mirror.front_back": "↑ ↓", + "mirror.left_right": "← →", + "mirror.none": "|", + "mount.onboard": "Press %1$s to Dismount", + "multiplayer.applyingPack": "Applying resource pack", + "multiplayer.disconnect.authservers_down": "Authentication servers are down. Please try again later, sorry!", + "multiplayer.disconnect.banned": "You are banned from this server", + "multiplayer.disconnect.banned_ip.expiration": "\nYour ban will be removed on %s", + "multiplayer.disconnect.banned_ip.reason": "Your IP address is banned from this server.\nReason: %s", + "multiplayer.disconnect.banned.expiration": "\nYour ban will be removed on %s", + "multiplayer.disconnect.banned.reason": "You are banned from this server.\nReason: %s", + "multiplayer.disconnect.chat_validation_failed": "Chat message validation failure", + "multiplayer.disconnect.duplicate_login": "You logged in from another location", + "multiplayer.disconnect.expired_public_key": "Expired profile public key. Check that your system time is synchronized, and try restarting your game.", + "multiplayer.disconnect.flying": "Flying is not enabled on this server", + "multiplayer.disconnect.generic": "Disconnected", + "multiplayer.disconnect.idling": "You have been idle for too long!", + "multiplayer.disconnect.illegal_characters": "Illegal characters in chat", + "multiplayer.disconnect.incompatible": "Incompatible client! Please use %s", + "multiplayer.disconnect.invalid_entity_attacked": "Attempting to attack an invalid entity", + "multiplayer.disconnect.invalid_packet": "Server sent an invalid packet", + "multiplayer.disconnect.invalid_player_data": "Invalid player data", + "multiplayer.disconnect.invalid_player_movement": "Invalid move player packet received", + "multiplayer.disconnect.invalid_public_key_signature": "Invalid signature for profile public key.\nTry restarting your game.", + "multiplayer.disconnect.invalid_public_key_signature.new": "Invalid signature for profile public key.\nTry restarting your game.", + "multiplayer.disconnect.invalid_vehicle_movement": "Invalid move vehicle packet received", + "multiplayer.disconnect.ip_banned": "You have been IP banned from this server", + "multiplayer.disconnect.kicked": "Kicked by an operator", + "multiplayer.disconnect.missing_tags": "Incomplete set of tags received from server.\nPlease contact server operator.", + "multiplayer.disconnect.name_taken": "That name is already taken", + "multiplayer.disconnect.not_whitelisted": "You are not white-listed on this server!", + "multiplayer.disconnect.out_of_order_chat": "Out-of-order chat packet received. Did your system time change?", + "multiplayer.disconnect.outdated_client": "Incompatible client! Please use %s", + "multiplayer.disconnect.outdated_server": "Incompatible client! Please use %s", + "multiplayer.disconnect.server_full": "The server is full!", + "multiplayer.disconnect.server_shutdown": "Server closed", + "multiplayer.disconnect.slow_login": "Took too long to log in", + "multiplayer.disconnect.too_many_pending_chats": "Too many unacknowledged chat messages", + "multiplayer.disconnect.transfers_disabled": "Server does not accept transfers", + "multiplayer.disconnect.unexpected_query_response": "Unexpected custom data from client", + "multiplayer.disconnect.unsigned_chat": "Received chat packet with missing or invalid signature.", + "multiplayer.disconnect.unverified_username": "Failed to verify username!", + "multiplayer.downloadingStats": "Retrieving statistics...", + "multiplayer.downloadingTerrain": "Loading terrain...", + "multiplayer.lan.server_found": "New server found: %s", + "multiplayer.message_not_delivered": "Can't deliver chat message, check server logs: %s", + "multiplayer.player.joined": "%s joined the game", + "multiplayer.player.joined.renamed": "%s (formerly known as %s) joined the game", + "multiplayer.player.left": "%s left the game", + "multiplayer.player.list.hp": "%shp", + "multiplayer.player.list.narration": "Online players: %s", + "multiplayer.requiredTexturePrompt.disconnect": "Server requires a custom resource pack", + "multiplayer.requiredTexturePrompt.line1": "This server requires the use of a custom resource pack.", + "multiplayer.requiredTexturePrompt.line2": "Rejecting this custom resource pack will disconnect you from this server.", + "multiplayer.socialInteractions.not_available": "Social Interactions are only available in Multiplayer worlds", + "multiplayer.status.and_more": "... and %s more ...", + "multiplayer.status.cancelled": "Cancelled", + "multiplayer.status.cannot_connect": "Can't connect to server", + "multiplayer.status.cannot_resolve": "Can't resolve hostname", + "multiplayer.status.finished": "Finished", + "multiplayer.status.incompatible": "Incompatible version!", + "multiplayer.status.motd.narration": "Message of the day: %s", + "multiplayer.status.no_connection": "(no connection)", + "multiplayer.status.old": "Old", + "multiplayer.status.online": "Online", + "multiplayer.status.ping": "%s ms", + "multiplayer.status.ping.narration": "Ping %s milliseconds", + "multiplayer.status.pinging": "Pinging...", + "multiplayer.status.player_count": "%s/%s", + "multiplayer.status.player_count.narration": "%s out of %s players online", + "multiplayer.status.quitting": "Quitting", + "multiplayer.status.request_handled": "Status request has been handled", + "multiplayer.status.unknown": "???", + "multiplayer.status.unrequested": "Received unrequested status", + "multiplayer.status.version.narration": "Server version: %s", + "multiplayer.stopSleeping": "Leave Bed", + "multiplayer.texturePrompt.failure.line1": "Server resource pack couldn't be applied", + "multiplayer.texturePrompt.failure.line2": "Any functionality that requires custom resources might not work as expected", + "multiplayer.texturePrompt.line1": "This server recommends the use of a custom resource pack.", + "multiplayer.texturePrompt.line2": "Would you like to download and install it automagically?", + "multiplayer.texturePrompt.serverPrompt": "%s\n\nMessage from server:\n%s", + "multiplayer.title": "Play Multiplayer", + "multiplayer.unsecureserver.toast": "Messages sent on this server may be modified and might not reflect the original message", + "multiplayer.unsecureserver.toast.title": "Chat messages can't be verified", + "multiplayerWarning.check": "Do not show this screen again", + "multiplayerWarning.header": "Caution: Third-Party Online Play", + "multiplayerWarning.message": "Caution: Online play is offered by third-party servers that are not owned, operated, or supervised by Mojang Studios or Microsoft. During online play, you may be exposed to unmoderated chat messages or other types of user-generated content that may not be suitable for everyone.", + "narration.button": "Button: %s", + "narration.button.usage.focused": "Press Enter to activate", + "narration.button.usage.hovered": "Left click to activate", + "narration.checkbox": "Checkbox: %s", + "narration.checkbox.usage.focused": "Press Enter to toggle", + "narration.checkbox.usage.hovered": "Left click to toggle", + "narration.component_list.usage": "Press Tab to navigate to next element", + "narration.cycle_button.usage.focused": "Press Enter to switch to %s", + "narration.cycle_button.usage.hovered": "Left click to switch to %s", + "narration.edit_box": "Edit box: %s", + "narration.recipe": "Recipe for %s", + "narration.recipe.usage": "Left click to select", + "narration.recipe.usage.more": "Right click to show more recipes", + "narration.selection.usage": "Press up and down buttons to move to another entry", + "narration.slider.usage.focused": "Press left or right keyboard buttons to change value", + "narration.slider.usage.hovered": "Drag slider to change value", + "narration.suggestion": "Selected suggestion %d out of %d: %s", + "narration.suggestion.tooltip": "Selected suggestion %d out of %d: %s (%s)", + "narration.suggestion.usage.cycle.fixed": "Press Tab to cycle to the next suggestion", + "narration.suggestion.usage.cycle.hidable": "Press Tab to cycle to the next suggestion, or Escape to leave suggestions", + "narration.suggestion.usage.fill.fixed": "Press Tab to use suggestion", + "narration.suggestion.usage.fill.hidable": "Press Tab to use suggestion, or Escape to leave suggestions", + "narration.tab_navigation.usage": "Press Ctrl and Tab to switch between tabs", + "narrator.button.accessibility": "Accessibility", + "narrator.button.difficulty_lock": "Difficulty lock", + "narrator.button.difficulty_lock.locked": "Locked", + "narrator.button.difficulty_lock.unlocked": "Unlocked", + "narrator.button.language": "Language", + "narrator.controls.bound": "%s is bound to %s", + "narrator.controls.reset": "Reset %s button", + "narrator.controls.unbound": "%s is not bound", + "narrator.joining": "Joining", + "narrator.loading": "Loading: %s", + "narrator.loading.done": "Done", + "narrator.position.list": "Selected list row %s out of %s", + "narrator.position.object_list": "Selected row element %s out of %s", + "narrator.position.screen": "Screen element %s out of %s", + "narrator.position.tab": "Selected tab %s out of %s", + "narrator.ready_to_play": "Ready to play", + "narrator.screen.title": "Title Screen", + "narrator.screen.usage": "Use mouse cursor or Tab button to select element", + "narrator.select": "Selected: %s", + "narrator.select.world": "Selected %s, last played: %s, %s, %s, version: %s", + "narrator.select.world_info": "Selected %s, last played: %s, %s", + "narrator.toast.disabled": "Narrator Disabled", + "narrator.toast.enabled": "Narrator Enabled", + "optimizeWorld.confirm.description": "This will attempt to optimize your world by making sure all data is stored in the most recent game format. This can take a very long time, depending on your world. Once done, your world may play faster but will no longer be compatible with older versions of the game. Are you sure you wish to proceed?", + "optimizeWorld.confirm.title": "Optimize World", + "optimizeWorld.info.converted": "Upgraded chunks: %s", + "optimizeWorld.info.skipped": "Skipped chunks: %s", + "optimizeWorld.info.total": "Total chunks: %s", + "optimizeWorld.progress.counter": "%s / %s", + "optimizeWorld.progress.percentage": "%s%%", + "optimizeWorld.stage.counting": "Counting chunks...", + "optimizeWorld.stage.failed": "Failed! :(", + "optimizeWorld.stage.finished": "Finishing up...", + "optimizeWorld.stage.finished.chunks": "Finishing up upgrading chunks...", + "optimizeWorld.stage.finished.entities": "Finishing up upgrading entities...", + "optimizeWorld.stage.finished.poi": "Finishing up upgrading points of interest...", + "optimizeWorld.stage.upgrading": "Upgrading all chunks...", + "optimizeWorld.stage.upgrading.chunks": "Upgrading all chunks...", + "optimizeWorld.stage.upgrading.entities": "Upgrading all entities...", + "optimizeWorld.stage.upgrading.poi": "Upgrading all points of interest...", + "optimizeWorld.title": "Optimizing World '%s'", + "options.accessibility": "Accessibility Settings...", + "options.accessibility.high_contrast": "High Contrast", + "options.accessibility.high_contrast.error.tooltip": "High Contrast resource pack is not available.", + "options.accessibility.high_contrast.tooltip": "Enhances the contrast of UI elements.", + "options.accessibility.link": "Accessibility Guide", + "options.accessibility.menu_background_blurriness": "Menu Background Blur", + "options.accessibility.menu_background_blurriness.tooltip": "Changes the blurriness of menu backgrounds.", + "options.accessibility.narrator_hotkey": "Narrator Hotkey", + "options.accessibility.narrator_hotkey.mac.tooltip": "Allows the Narrator to be toggled on and off with 'Cmd+B'.", + "options.accessibility.narrator_hotkey.tooltip": "Allows the Narrator to be toggled on and off with 'Ctrl+B'.", + "options.accessibility.panorama_speed": "Panorama Scroll Speed", + "options.accessibility.text_background": "Text Background", + "options.accessibility.text_background_opacity": "Text Background Opacity", + "options.accessibility.text_background.chat": "Chat", + "options.accessibility.text_background.everywhere": "Everywhere", + "options.accessibility.title": "Accessibility Settings", + "options.allowServerListing": "Allow Server Listings", + "options.allowServerListing.tooltip": "Servers may list online players as part of their public status.\nWith this option off your name will not show up in such lists.", + "options.ao": "Smooth Lighting", + "options.ao.max": "Maximum", + "options.ao.min": "Minimum", + "options.ao.off": "OFF", + "options.attack.crosshair": "Crosshair", + "options.attack.hotbar": "Hotbar", + "options.attackIndicator": "Attack Indicator", + "options.audioDevice": "Device", + "options.audioDevice.default": "System Default", + "options.autoJump": "Auto-Jump", + "options.autosaveIndicator": "Autosave Indicator", + "options.autoSuggestCommands": "Command Suggestions", + "options.biomeBlendRadius": "Biome Blend", + "options.biomeBlendRadius.1": "OFF (Fastest)", + "options.biomeBlendRadius.3": "3x3 (Fast)", + "options.biomeBlendRadius.5": "5x5 (Normal)", + "options.biomeBlendRadius.7": "7x7 (High)", + "options.biomeBlendRadius.9": "9x9 (Very High)", + "options.biomeBlendRadius.11": "11x11 (Extreme)", + "options.biomeBlendRadius.13": "13x13 (Showoff)", + "options.biomeBlendRadius.15": "15x15 (Maximum)", + "options.chat": "Chat Settings...", + "options.chat.color": "Colors", + "options.chat.delay": "Chat Delay: %s seconds", + "options.chat.delay_none": "Chat Delay: None", + "options.chat.height.focused": "Focused Height", + "options.chat.height.unfocused": "Unfocused Height", + "options.chat.line_spacing": "Line Spacing", + "options.chat.links": "Web Links", + "options.chat.links.prompt": "Prompt on Links", + "options.chat.opacity": "Chat Text Opacity", + "options.chat.scale": "Chat Text Size", + "options.chat.title": "Chat Settings", + "options.chat.visibility": "Chat", + "options.chat.visibility.full": "Shown", + "options.chat.visibility.hidden": "Hidden", + "options.chat.visibility.system": "Commands Only", + "options.chat.width": "Width", + "options.chunks": "%s chunks", + "options.clouds.fancy": "Fancy", + "options.clouds.fast": "Fast", + "options.controls": "Controls...", + "options.credits_and_attribution": "Credits & Attribution...", + "options.customizeTitle": "Customize World Settings", + "options.damageTiltStrength": "Damage Tilt", + "options.damageTiltStrength.tooltip": "The amount of camera shake caused by being hurt.", + "options.darkMojangStudiosBackgroundColor": "Monochrome Logo", + "options.darkMojangStudiosBackgroundColor.tooltip": "Changes the Mojang Studios loading screen background color to black.", + "options.darknessEffectScale": "Darkness Pulsing", + "options.darknessEffectScale.tooltip": "Controls how much the Darkness effect pulses when a Warden or Sculk Shrieker gives it to you.", + "options.difficulty": "Difficulty", + "options.difficulty.easy": "Easy", + "options.difficulty.easy.info": "Hostile mobs spawn but deal less damage. Hunger bar depletes and drains health down to 5 hearts.", + "options.difficulty.hard": "Hard", + "options.difficulty.hard.info": "Hostile mobs spawn and deal more damage. Hunger bar depletes and drains all health.", + "options.difficulty.hardcore": "Hardcore", + "options.difficulty.normal": "Normal", + "options.difficulty.normal.info": "Hostile mobs spawn and deal standard damage. Hunger bar depletes and drains health down to half a heart.", + "options.difficulty.online": "Server Difficulty", + "options.difficulty.peaceful": "Peaceful", + "options.difficulty.peaceful.info": "No hostile mobs and only some neutral mobs spawn. Hunger bar doesn't deplete and health replenishes over time.", + "options.directionalAudio": "Directional Audio", + "options.directionalAudio.off.tooltip": "Classic Stereo sound.", + "options.directionalAudio.on.tooltip": "Uses HRTF-based directional audio to improve the simulation of 3D sound. Requires HRTF compatible audio hardware, and is best experienced with headphones.", + "options.discrete_mouse_scroll": "Discrete Scrolling", + "options.entityDistanceScaling": "Entity Distance", + "options.entityShadows": "Entity Shadows", + "options.font": "Font Settings...", + "options.font.title": "Font Settings", + "options.forceUnicodeFont": "Force Unicode Font", + "options.fov": "FOV", + "options.fov.max": "Quake Pro", + "options.fov.min": "Normal", + "options.fovEffectScale": "FOV Effects", + "options.fovEffectScale.tooltip": "Controls how much the field of view can change with gameplay effects.", + "options.framerate": "%s fps", + "options.framerateLimit": "Max Framerate", + "options.framerateLimit.max": "Unlimited", + "options.fullscreen": "Fullscreen", + "options.fullscreen.current": "Current", + "options.fullscreen.entry": "%sx%s@%s (%sbit)", + "options.fullscreen.resolution": "Fullscreen Resolution", + "options.fullscreen.unavailable": "Setting unavailable", + "options.gamma": "Brightness", + "options.gamma.default": "Default", + "options.gamma.max": "Bright", + "options.gamma.min": "Moody", + "options.generic_value": "%s: %s", + "options.glintSpeed": "Glint Speed", + "options.glintSpeed.tooltip": "Controls how fast the visual glint shimmers across enchanted items.", + "options.glintStrength": "Glint Strength", + "options.glintStrength.tooltip": "Controls how transparent the visual glint is on enchanted items.", + "options.graphics": "Graphics", + "options.graphics.fabulous": "Fabulous!", + "options.graphics.fabulous.tooltip": "%s graphics uses screen shaders for drawing weather, clouds, and particles behind translucent blocks and water.\nThis may severely impact performance for portable devices and 4K displays.", + "options.graphics.fancy": "Fancy", + "options.graphics.fancy.tooltip": "Fancy graphics balances performance and quality for the majority of machines.\nWeather, clouds, and particles may not appear behind translucent blocks or water.", + "options.graphics.fast": "Fast", + "options.graphics.fast.tooltip": "Fast graphics reduces the amount of visible rain and snow.\nTransparency effects are disabled for various blocks such as leaves.", + "options.graphics.warning.accept": "Continue Without Support", + "options.graphics.warning.cancel": "Take Me Back", + "options.graphics.warning.message": "Your graphics device is detected as unsupported for the %s graphics option.\n\nYou may ignore this and continue, however support will not be provided for your device if you choose to use %s graphics.", + "options.graphics.warning.renderer": "Renderer detected: [%s]", + "options.graphics.warning.title": "Graphics Device Unsupported", + "options.graphics.warning.vendor": "Vendor detected: [%s]", + "options.graphics.warning.version": "OpenGL Version detected: [%s]", + "options.guiScale": "GUI Scale", + "options.guiScale.auto": "Auto", + "options.hidden": "Hidden", + "options.hideLightningFlashes": "Hide Lightning Flashes", + "options.hideLightningFlashes.tooltip": "Prevents Lightning Bolts from making the sky flash. The bolts themselves will still be visible.", + "options.hideMatchedNames": "Hide Matched Names", + "options.hideMatchedNames.tooltip": "3rd-party Servers may send chat messages in non-standard formats.\nWith this option on, hidden players will be matched based on chat sender names.", + "options.hideSplashTexts": "Hide Splash Texts", + "options.hideSplashTexts.tooltip": "Hides the yellow splash text in the main menu.", + "options.invertMouse": "Invert Mouse", + "options.japaneseGlyphVariants": "Japanese Glyph Variants", + "options.japaneseGlyphVariants.tooltip": "Uses Japanese variants of CJK characters in the default font.", + "options.key.hold": "Hold", + "options.key.toggle": "Toggle", + "options.language": "Language...", + "options.language.title": "Language", + "options.languageAccuracyWarning": "(Language translations may not be 100%% accurate)", + "options.languageWarning": "Language translations may not be 100%% accurate", + "options.mainHand": "Main Hand", + "options.mainHand.left": "Left", + "options.mainHand.right": "Right", + "options.mipmapLevels": "Mipmap Levels", + "options.modelPart.cape": "Cape", + "options.modelPart.hat": "Hat", + "options.modelPart.jacket": "Jacket", + "options.modelPart.left_pants_leg": "Left Pant Leg", + "options.modelPart.left_sleeve": "Left Sleeve", + "options.modelPart.right_pants_leg": "Right Pant Leg", + "options.modelPart.right_sleeve": "Right Sleeve", + "options.mouse_settings": "Mouse Settings...", + "options.mouse_settings.title": "Mouse Settings", + "options.mouseWheelSensitivity": "Scroll Sensitivity", + "options.multiplayer.title": "Multiplayer Settings...", + "options.multiplier": "%sx", + "options.narrator": "Narrator", + "options.narrator.all": "Narrates All", + "options.narrator.chat": "Narrates Chat", + "options.narrator.notavailable": "Not Available", + "options.narrator.off": "OFF", + "options.narrator.system": "Narrates System", + "options.notifications.display_time": "Notification Time", + "options.notifications.display_time.tooltip": "Affects the length of time that all notifications stay visible on the screen.", + "options.off": "OFF", + "options.off.composed": "%s: OFF", + "options.on": "ON", + "options.on.composed": "%s: ON", + "options.online": "Online...", + "options.online.title": "Online Options", + "options.onlyShowSecureChat": "Only Show Secure Chat", + "options.onlyShowSecureChat.tooltip": "Only display messages from other players that can be verified to have been sent by that player, and have not been modified.", + "options.operatorItemsTab": "Operator Items Tab", + "options.particles": "Particles", + "options.particles.all": "All", + "options.particles.decreased": "Decreased", + "options.particles.minimal": "Minimal", + "options.percent_add_value": "%s: +%s%%", + "options.percent_value": "%s: %s%%", + "options.pixel_value": "%s: %spx", + "options.prioritizeChunkUpdates": "Chunk Builder", + "options.prioritizeChunkUpdates.byPlayer": "Semi Blocking", + "options.prioritizeChunkUpdates.byPlayer.tooltip": "Some actions within a chunk will recompile the chunk immediately. This includes block placing & destroying.", + "options.prioritizeChunkUpdates.nearby": "Fully Blocking", + "options.prioritizeChunkUpdates.nearby.tooltip": "Nearby chunks are always compiled immediately. This may impact game performance when blocks are placed or destroyed.", + "options.prioritizeChunkUpdates.none": "Threaded", + "options.prioritizeChunkUpdates.none.tooltip": "Nearby chunks are compiled in parallel threads. This may result in brief visual holes when blocks are destroyed.", + "options.rawMouseInput": "Raw Input", + "options.realmsNotifications": "Realms News & Invites", + "options.realmsNotifications.tooltip": "Fetches Realms news and invites in the title screen and displays their respective icon on the Realms button.", + "options.reducedDebugInfo": "Reduced Debug Info", + "options.renderClouds": "Clouds", + "options.renderDistance": "Render Distance", + "options.resourcepack": "Resource Packs...", + "options.screenEffectScale": "Distortion Effects", + "options.screenEffectScale.tooltip": "Strength of nausea and Nether portal screen distortion effects.\nAt lower values, the nausea effect is replaced with a green overlay.", + "options.sensitivity": "Sensitivity", + "options.sensitivity.max": "HYPERSPEED!!!", + "options.sensitivity.min": "*yawn*", + "options.showSubtitles": "Show Subtitles", + "options.simulationDistance": "Simulation Distance", + "options.skinCustomisation": "Skin Customization...", + "options.skinCustomisation.title": "Skin Customization", + "options.sounds": "Music & Sounds...", + "options.sounds.title": "Music & Sound Options", + "options.telemetry": "Telemetry Data...", + "options.telemetry.button": "Data Collection", + "options.telemetry.button.tooltip": "\"%s\" includes only the required data.\n\"%s\" includes optional, as well as the required data.", + "options.telemetry.disabled": "Telemetry is disabled.", + "options.telemetry.state.all": "All", + "options.telemetry.state.minimal": "Minimal", + "options.telemetry.state.none": "None", + "options.title": "Options", + "options.touchscreen": "Touchscreen Mode", + "options.video": "Video Settings...", + "options.videoTitle": "Video Settings", + "options.viewBobbing": "View Bobbing", + "options.visible": "Shown", + "options.vsync": "VSync", + "outOfMemory.message": "Minecraft has run out of memory.\n\nThis could be caused by a bug in the game or by the Java Virtual Machine not being allocated enough memory.\n\nTo prevent world corruption, the current game has quit. We've tried to free up enough memory to let you go back to the main menu and back to playing, but this may not have worked.\n\nPlease restart the game if you see this message again.", + "outOfMemory.title": "Out of memory!", + "pack.available.title": "Available", + "pack.copyFailure": "Failed to copy packs", + "pack.dropConfirm": "Do you want to add the following packs to Minecraft?", + "pack.dropInfo": "Drag and drop files into this window to add packs", + "pack.dropRejected.message": "The following entries were not valid packs and were not copied:\n %s", + "pack.dropRejected.title": "Non-pack entries", + "pack.folderInfo": "(Place pack files here)", + "pack.incompatible": "Incompatible", + "pack.incompatible.confirm.new": "This pack was made for a newer version of Minecraft and may not work correctly.", + "pack.incompatible.confirm.old": "This pack was made for an older version of Minecraft and may no longer work correctly.", + "pack.incompatible.confirm.title": "Are you sure you want to load this pack?", + "pack.incompatible.new": "(Made for a newer version of Minecraft)", + "pack.incompatible.old": "(Made for an older version of Minecraft)", + "pack.nameAndSource": "%s (%s)", + "pack.openFolder": "Open Pack Folder", + "pack.selected.title": "Selected", + "pack.source.builtin": "built-in", + "pack.source.feature": "feature", + "pack.source.local": "local", + "pack.source.server": "server", + "pack.source.world": "world", + "painting.dimensions": "%sx%s", + "painting.minecraft.alban.author": "Kristoffer Zetterstrand", + "painting.minecraft.alban.title": "Albanian", + "painting.minecraft.aztec.author": "Kristoffer Zetterstrand", + "painting.minecraft.aztec.title": "de_aztec", + "painting.minecraft.aztec2.author": "Kristoffer Zetterstrand", + "painting.minecraft.aztec2.title": "de_aztec", + "painting.minecraft.backyard.author": "Kristoffer Zetterstrand", + "painting.minecraft.backyard.title": "Backyard", + "painting.minecraft.baroque.author": "Sarah Boeving", + "painting.minecraft.baroque.title": "Baroque", + "painting.minecraft.bomb.author": "Kristoffer Zetterstrand", + "painting.minecraft.bomb.title": "Target Successfully Bombed", + "painting.minecraft.bouquet.author": "Kristoffer Zetterstrand", + "painting.minecraft.bouquet.title": "Bouquet", + "painting.minecraft.burning_skull.author": "Kristoffer Zetterstrand", + "painting.minecraft.burning_skull.title": "Skull On Fire", + "painting.minecraft.bust.author": "Kristoffer Zetterstrand", + "painting.minecraft.bust.title": "Bust", + "painting.minecraft.cavebird.author": "Kristoffer Zetterstrand", + "painting.minecraft.cavebird.title": "Cavebird", + "painting.minecraft.changing.author": "Kristoffer Zetterstrand", + "painting.minecraft.changing.title": "Changing", + "painting.minecraft.cotan.author": "Kristoffer Zetterstrand", + "painting.minecraft.cotan.title": "Cotán", + "painting.minecraft.courbet.author": "Kristoffer Zetterstrand", + "painting.minecraft.courbet.title": "Bonjour Monsieur Courbet", + "painting.minecraft.creebet.author": "Kristoffer Zetterstrand", + "painting.minecraft.creebet.title": "Creebet", + "painting.minecraft.donkey_kong.author": "Kristoffer Zetterstrand", + "painting.minecraft.donkey_kong.title": "Kong", + "painting.minecraft.earth.author": "Mojang", + "painting.minecraft.earth.title": "Earth", + "painting.minecraft.endboss.author": "Kristoffer Zetterstrand", + "painting.minecraft.endboss.title": "Endboss", + "painting.minecraft.fern.author": "Kristoffer Zetterstrand", + "painting.minecraft.fern.title": "Fern", + "painting.minecraft.fighters.author": "Kristoffer Zetterstrand", + "painting.minecraft.fighters.title": "Fighters", + "painting.minecraft.finding.author": "Kristoffer Zetterstrand", + "painting.minecraft.finding.title": "Finding", + "painting.minecraft.fire.author": "Mojang", + "painting.minecraft.fire.title": "Fire", + "painting.minecraft.graham.author": "Kristoffer Zetterstrand", + "painting.minecraft.graham.title": "Graham", + "painting.minecraft.humble.author": "Sarah Boeving", + "painting.minecraft.humble.title": "Humble", + "painting.minecraft.kebab.author": "Kristoffer Zetterstrand", + "painting.minecraft.kebab.title": "Kebab med tre pepperoni", + "painting.minecraft.lowmist.author": "Kristoffer Zetterstrand", + "painting.minecraft.lowmist.title": "Lowmist", + "painting.minecraft.match.author": "Kristoffer Zetterstrand", + "painting.minecraft.match.title": "Match", + "painting.minecraft.meditative.author": "Sarah Boeving", + "painting.minecraft.meditative.title": "Meditative", + "painting.minecraft.orb.author": "Kristoffer Zetterstrand", + "painting.minecraft.orb.title": "Orb", + "painting.minecraft.owlemons.author": "Kristoffer Zetterstrand", + "painting.minecraft.owlemons.title": "Owlemons", + "painting.minecraft.passage.author": "Kristoffer Zetterstrand", + "painting.minecraft.passage.title": "Passage", + "painting.minecraft.pigscene.author": "Kristoffer Zetterstrand", + "painting.minecraft.pigscene.title": "Pigscene", + "painting.minecraft.plant.author": "Kristoffer Zetterstrand", + "painting.minecraft.plant.title": "Paradisträd", + "painting.minecraft.pointer.author": "Kristoffer Zetterstrand", + "painting.minecraft.pointer.title": "Pointer", + "painting.minecraft.pond.author": "Kristoffer Zetterstrand", + "painting.minecraft.pond.title": "Pond", + "painting.minecraft.pool.author": "Kristoffer Zetterstrand", + "painting.minecraft.pool.title": "The Pool", + "painting.minecraft.prairie_ride.author": "Sarah Boeving", + "painting.minecraft.prairie_ride.title": "Prairie Ride", + "painting.minecraft.sea.author": "Kristoffer Zetterstrand", + "painting.minecraft.sea.title": "Seaside", + "painting.minecraft.skeleton.author": "Kristoffer Zetterstrand", + "painting.minecraft.skeleton.title": "Mortal Coil", + "painting.minecraft.skull_and_roses.author": "Kristoffer Zetterstrand", + "painting.minecraft.skull_and_roses.title": "Skull and Roses", + "painting.minecraft.stage.author": "Kristoffer Zetterstrand", + "painting.minecraft.stage.title": "The Stage Is Set", + "painting.minecraft.sunflowers.author": "Kristoffer Zetterstrand", + "painting.minecraft.sunflowers.title": "Sunflowers", + "painting.minecraft.sunset.author": "Kristoffer Zetterstrand", + "painting.minecraft.sunset.title": "sunset_dense", + "painting.minecraft.tides.author": "Kristoffer Zetterstrand", + "painting.minecraft.tides.title": "Tides", + "painting.minecraft.unpacked.author": "Sarah Boeving", + "painting.minecraft.unpacked.title": "Unpacked", + "painting.minecraft.void.author": "Kristoffer Zetterstrand", + "painting.minecraft.void.title": "The void", + "painting.minecraft.wanderer.author": "Kristoffer Zetterstrand", + "painting.minecraft.wanderer.title": "Wanderer", + "painting.minecraft.wasteland.author": "Kristoffer Zetterstrand", + "painting.minecraft.wasteland.title": "Wasteland", + "painting.minecraft.water.author": "Mojang", + "painting.minecraft.water.title": "Water", + "painting.minecraft.wind.author": "Mojang", + "painting.minecraft.wind.title": "Wind", + "painting.minecraft.wither.author": "Mojang", + "painting.minecraft.wither.title": "Wither", + "painting.random": "Random variant", + "parsing.bool.expected": "Expected boolean", + "parsing.bool.invalid": "Invalid boolean, expected 'true' or 'false' but found '%s'", + "parsing.double.expected": "Expected double", + "parsing.double.invalid": "Invalid double '%s'", + "parsing.expected": "Expected '%s'", + "parsing.float.expected": "Expected float", + "parsing.float.invalid": "Invalid float '%s'", + "parsing.int.expected": "Expected integer", + "parsing.int.invalid": "Invalid integer '%s'", + "parsing.long.expected": "Expected long", + "parsing.long.invalid": "Invalid long '%s'", + "parsing.quote.escape": "Invalid escape sequence '\\%s' in quoted string", + "parsing.quote.expected.end": "Unclosed quoted string", + "parsing.quote.expected.start": "Expected quote to start a string", + "particle.invalidOptions": "Can't parse particle options: %s", + "particle.notFound": "Unknown particle: %s", + "permissions.requires.entity": "An entity is required to run this command here", + "permissions.requires.player": "A player is required to run this command here", + "potion.potency.0": "", + "potion.potency.1": "II", + "potion.potency.2": "III", + "potion.potency.3": "IV", + "potion.potency.4": "V", + "potion.potency.5": "VI", + "potion.whenDrank": "When Applied:", + "potion.withAmplifier": "%s %s", + "potion.withDuration": "%s (%s)", + "predicate.unknown": "Unknown predicate: %s", + "quickplay.error.invalid_identifier": "Could not find world with the provided identifier", + "quickplay.error.realm_connect": "Could not connect to Realm", + "quickplay.error.realm_permission": "Lacking permission to connect to this Realm", + "quickplay.error.title": "Failed to Quick Play", + "realms.missing.module.error.text": "Realms could not be opened right now, please try again later", + "realms.missing.snapshot.error.text": "Realms is currently not supported in snapshots", + "recipe.notFound": "Unknown recipe: %s", + "recipe.toast.description": "Check your recipe book", + "recipe.toast.title": "New Recipes Unlocked!", + "record.nowPlaying": "Now Playing: %s", + "recover_world.bug_tracker": "Report a Bug", + "recover_world.button": "Attempt to Recover", + "recover_world.done.failed": "Failed to recover from previous state.", + "recover_world.done.success": "Recovery was successful!", + "recover_world.done.title": "Recovery done", + "recover_world.issue.missing_file": "Missing file", + "recover_world.issue.none": "No issues", + "recover_world.message": "The following issues occurred while trying to read world folder \"%s\".\nIt might be possible to restore the world from an older state or you can report this issue on the bug tracker.", + "recover_world.no_fallback": "No state to recover from available", + "recover_world.restore": "Attempt to Restore", + "recover_world.restoring": "Attempting to restore world...", + "recover_world.state_entry": "State from %s: ", + "recover_world.state_entry.unknown": "unknown", + "recover_world.title": "Failed to load world", + "recover_world.warning": "Failed to load world summary", + "resourcePack.broken_assets": "BROKEN ASSETS DETECTED", + "resourcepack.downloading": "Downloading Resource Pack", + "resourcePack.high_contrast.name": "High Contrast", + "resourcePack.load_fail": "Resource reload failed", + "resourcePack.programmer_art.name": "Programmer Art", + "resourcepack.progress": "Downloading file (%s MB)...", + "resourcepack.requesting": "Making Request...", + "resourcePack.server.name": "World Specific Resources", + "resourcePack.title": "Select Resource Packs", + "resourcePack.vanilla.description": "The default look and feel of Minecraft", + "resourcePack.vanilla.name": "Default", + "screenshot.failure": "Couldn't save screenshot: %s", + "screenshot.success": "Saved screenshot as %s", + "selectServer.add": "Add Server", + "selectServer.defaultName": "Minecraft Server", + "selectServer.delete": "Delete", + "selectServer.deleteButton": "Delete", + "selectServer.deleteQuestion": "Are you sure you want to remove this server?", + "selectServer.deleteWarning": "'%s' will be lost forever! (A long time!)", + "selectServer.direct": "Direct Connection", + "selectServer.edit": "Edit", + "selectServer.hiddenAddress": "(Hidden)", + "selectServer.refresh": "Refresh", + "selectServer.select": "Join Server", + "selectServer.title": "Select Server", + "selectWorld.access_failure": "Failed to access world", + "selectWorld.allowCommands": "Allow Cheats", + "selectWorld.allowCommands.info": "Commands like /gamemode, /experience", + "selectWorld.allowCommands.new": "Allow Commands", + "selectWorld.backupEraseCache": "Erase Cached Data", + "selectWorld.backupJoinConfirmButton": "Create Backup and Load", + "selectWorld.backupJoinSkipButton": "I know what I'm doing!", + "selectWorld.backupQuestion.customized": "Customized worlds are no longer supported", + "selectWorld.backupQuestion.downgrade": "Downgrading a world is not supported", + "selectWorld.backupQuestion.experimental": "Worlds using Experimental Settings are not supported", + "selectWorld.backupQuestion.snapshot": "Do you really want to load this world?", + "selectWorld.backupWarning.customized": "Unfortunately, we do not support customized worlds in this version of Minecraft. We can still load this world and keep everything the way it was, but any newly generated terrain will no longer be customized. We're sorry for the inconvenience!", + "selectWorld.backupWarning.downgrade": "This world was last played in version %s; you are on version %s. Downgrading a world could cause corruption - we cannot guarantee that it will load or work. If you still want to continue, please make a backup.", + "selectWorld.backupWarning.experimental": "This world uses experimental settings that could stop working at any time. We cannot guarantee it will load or work. Here be dragons!", + "selectWorld.backupWarning.snapshot": "This world was last played in version %s; you are on version %s. Please make a backup in case you experience world corruptions.", + "selectWorld.bonusItems": "Bonus Chest", + "selectWorld.cheats": "Cheats", + "selectWorld.commands": "Commands", + "selectWorld.conversion": "Must be converted!", + "selectWorld.conversion.tooltip": "This world must be opened in an older version (like 1.6.4) to be safely converted", + "selectWorld.create": "Create New World", + "selectWorld.createDemo": "Play New Demo World", + "selectWorld.customizeType": "Customize", + "selectWorld.data_read": "Reading world data...", + "selectWorld.dataPacks": "Data Packs", + "selectWorld.delete": "Delete", + "selectWorld.delete_failure": "Failed to delete world", + "selectWorld.deleteButton": "Delete", + "selectWorld.deleteQuestion": "Are you sure you want to delete this world?", + "selectWorld.deleteWarning": "'%s' will be lost forever! (A long time!)", + "selectWorld.edit": "Edit", + "selectWorld.edit.backup": "Make Backup", + "selectWorld.edit.backupCreated": "Backed up: %s", + "selectWorld.edit.backupFailed": "Backup failed", + "selectWorld.edit.backupFolder": "Open Backups Folder", + "selectWorld.edit.backupSize": "size: %s MB", + "selectWorld.edit.export_worldgen_settings": "Export World Generation Settings", + "selectWorld.edit.export_worldgen_settings.failure": "Export failed", + "selectWorld.edit.export_worldgen_settings.success": "Exported", + "selectWorld.edit.openFolder": "Open World Folder", + "selectWorld.edit.optimize": "Optimize World", + "selectWorld.edit.resetIcon": "Reset Icon", + "selectWorld.edit.save": "Save", + "selectWorld.edit.title": "Edit World", + "selectWorld.enterName": "World Name", + "selectWorld.enterSeed": "Seed for the world generator", + "selectWorld.experimental": "Experimental", + "selectWorld.experimental.details": "Details", + "selectWorld.experimental.details.entry": "Required experimental features: %s", + "selectWorld.experimental.details.title": "Experimental Feature Requirements", + "selectWorld.experimental.message": "Be careful!\nThis configuration requires features that are still under development. Your world might crash, break, or not work with future updates.", + "selectWorld.experimental.title": "Experimental Features Warning", + "selectWorld.experiments": "Experiments", + "selectWorld.experiments.info": "Experiments are potential new features. Be careful as things might break. Experiments can't be turned off after world creation.", + "selectWorld.futureworld.error.text": "Something went wrong while trying to load a world from a future version. This was a risky operation to begin with; sorry it didn't work.", + "selectWorld.futureworld.error.title": "An error occurred!", + "selectWorld.gameMode": "Game Mode", + "selectWorld.gameMode.adventure": "Adventure", + "selectWorld.gameMode.adventure.info": "Same as Survival Mode, but blocks can't be added or removed.", + "selectWorld.gameMode.adventure.line1": "Same as Survival Mode, but blocks can't", + "selectWorld.gameMode.adventure.line2": "be added or removed", + "selectWorld.gameMode.creative": "Creative", + "selectWorld.gameMode.creative.info": "Create, build, and explore without limits. You can fly, have endless materials, and can't be hurt by monsters.", + "selectWorld.gameMode.creative.line1": "Unlimited resources, free flying and", + "selectWorld.gameMode.creative.line2": "destroy blocks instantly", + "selectWorld.gameMode.hardcore": "Hardcore", + "selectWorld.gameMode.hardcore.info": "Survival Mode locked to 'Hard' difficulty. You can't respawn if you die.", + "selectWorld.gameMode.hardcore.line1": "Same as Survival Mode, locked at hardest", + "selectWorld.gameMode.hardcore.line2": "difficulty, and one life only", + "selectWorld.gameMode.spectator": "Spectator", + "selectWorld.gameMode.spectator.info": "You can look but don't touch.", + "selectWorld.gameMode.spectator.line1": "You can look but don't touch", + "selectWorld.gameMode.spectator.line2": "", + "selectWorld.gameMode.survival": "Survival", + "selectWorld.gameMode.survival.info": "Explore a mysterious world where you build, collect, craft, and fight monsters.", + "selectWorld.gameMode.survival.line1": "Search for resources, craft, gain", + "selectWorld.gameMode.survival.line2": "levels, health and hunger", + "selectWorld.gameRules": "Game Rules", + "selectWorld.import_worldgen_settings": "Import Settings", + "selectWorld.import_worldgen_settings.failure": "Error importing settings", + "selectWorld.import_worldgen_settings.select_file": "Select settings file (.json)", + "selectWorld.incompatible_series": "Created by an incompatible version", + "selectWorld.incompatible.description": "This world cannot be opened in this version.\nIt was last played in version %s.", + "selectWorld.incompatible.info": "Incompatible version: %s", + "selectWorld.incompatible.title": "Incompatible version", + "selectWorld.incompatible.tooltip": "This world cannot be opened because it was created by an incompatible version.", + "selectWorld.load_folder_access": "Unable to read or access folder where game worlds are saved!", + "selectWorld.loading_list": "Loading World List", + "selectWorld.locked": "Locked by another running instance of Minecraft", + "selectWorld.mapFeatures": "Generate Structures", + "selectWorld.mapFeatures.info": "Villages, Shipwrecks, etc.", + "selectWorld.mapType": "World Type", + "selectWorld.mapType.normal": "Normal", + "selectWorld.moreWorldOptions": "More World Options...", + "selectWorld.newWorld": "New World", + "selectWorld.recreate": "Re-Create", + "selectWorld.recreate.customized.text": "Customized worlds are no longer supported in this version of Minecraft. We can try to recreate it with the same seed and properties, but any terrain customizations will be lost. We're sorry for the inconvenience!", + "selectWorld.recreate.customized.title": "Customized worlds are no longer supported", + "selectWorld.recreate.error.text": "Something went wrong while trying to recreate a world.", + "selectWorld.recreate.error.title": "An error occurred!", + "selectWorld.resource_load": "Preparing Resources...", + "selectWorld.resultFolder": "Will be saved in:", + "selectWorld.search": "search for worlds", + "selectWorld.seedInfo": "Leave blank for a random seed", + "selectWorld.select": "Play Selected World", + "selectWorld.targetFolder": "Save folder: %s", + "selectWorld.title": "Select World", + "selectWorld.tooltip.fromNewerVersion1": "World was saved in a newer version,", + "selectWorld.tooltip.fromNewerVersion2": "loading this world could cause problems!", + "selectWorld.tooltip.snapshot1": "Don't forget to back up this world", + "selectWorld.tooltip.snapshot2": "before you load it in this snapshot.", + "selectWorld.unable_to_load": "Unable to load worlds", + "selectWorld.version": "Version:", + "selectWorld.versionJoinButton": "Load Anyway", + "selectWorld.versionQuestion": "Do you really want to load this world?", + "selectWorld.versionUnknown": "unknown", + "selectWorld.versionWarning": "This world was last played in version %s and loading it in this version could cause corruption!", + "selectWorld.warning.deprecated.question": "Some features used are deprecated and will stop working in the future. Do you wish to proceed?", + "selectWorld.warning.deprecated.title": "Warning! These settings are using deprecated features", + "selectWorld.warning.experimental.question": "These settings are experimental and could one day stop working. Do you wish to proceed?", + "selectWorld.warning.experimental.title": "Warning! These settings are using experimental features", + "selectWorld.warning.lowDiskSpace.description": "There is not much space left on your device.\nRunning out of disk space while in game can lead to your world being damaged.", + "selectWorld.warning.lowDiskSpace.title": "Warning! Low disk space!", + "selectWorld.world": "World", + "sign.edit": "Edit Sign Message", + "sleep.not_possible": "No amount of rest can pass this night", + "sleep.players_sleeping": "%s/%s players sleeping", + "sleep.skipping_night": "Sleeping through this night", + "slot.only_single_allowed": "Only single slots allowed, got '%s'", + "slot.unknown": "Unknown slot '%s'", + "soundCategory.ambient": "Ambient/Environment", + "soundCategory.block": "Blocks", + "soundCategory.hostile": "Hostile Creatures", + "soundCategory.master": "Master Volume", + "soundCategory.music": "Music", + "soundCategory.neutral": "Friendly Creatures", + "soundCategory.player": "Players", + "soundCategory.record": "Jukebox/Note Blocks", + "soundCategory.voice": "Voice/Speech", + "soundCategory.weather": "Weather", + "spectatorMenu.close": "Close Menu", + "spectatorMenu.next_page": "Next Page", + "spectatorMenu.previous_page": "Previous Page", + "spectatorMenu.root.prompt": "Press a key to select a command, and again to use it.", + "spectatorMenu.team_teleport": "Teleport to Team Member", + "spectatorMenu.team_teleport.prompt": "Select a team to teleport to", + "spectatorMenu.teleport": "Teleport to Player", + "spectatorMenu.teleport.prompt": "Select a player to teleport to", + "stat_type.minecraft.broken": "Times Broken", + "stat_type.minecraft.crafted": "Times Crafted", + "stat_type.minecraft.dropped": "Dropped", + "stat_type.minecraft.killed": "You killed %s %s", + "stat_type.minecraft.killed_by": "%s killed you %s time(s)", + "stat_type.minecraft.killed_by.none": "You have never been killed by %s", + "stat_type.minecraft.killed.none": "You have never killed %s", + "stat_type.minecraft.mined": "Times Mined", + "stat_type.minecraft.picked_up": "Picked Up", + "stat_type.minecraft.used": "Times Used", + "stat.generalButton": "General", + "stat.itemsButton": "Items", + "stat.minecraft.animals_bred": "Animals Bred", + "stat.minecraft.aviate_one_cm": "Distance by Elytra", + "stat.minecraft.bell_ring": "Bells Rung", + "stat.minecraft.boat_one_cm": "Distance by Boat", + "stat.minecraft.clean_armor": "Armor Pieces Cleaned", + "stat.minecraft.clean_banner": "Banners Cleaned", + "stat.minecraft.clean_shulker_box": "Shulker Boxes Cleaned", + "stat.minecraft.climb_one_cm": "Distance Climbed", + "stat.minecraft.crouch_one_cm": "Distance Crouched", + "stat.minecraft.damage_absorbed": "Damage Absorbed", + "stat.minecraft.damage_blocked_by_shield": "Damage Blocked by Shield", + "stat.minecraft.damage_dealt": "Damage Dealt", + "stat.minecraft.damage_dealt_absorbed": "Damage Dealt (Absorbed)", + "stat.minecraft.damage_dealt_resisted": "Damage Dealt (Resisted)", + "stat.minecraft.damage_resisted": "Damage Resisted", + "stat.minecraft.damage_taken": "Damage Taken", + "stat.minecraft.deaths": "Number of Deaths", + "stat.minecraft.drop": "Items Dropped", + "stat.minecraft.eat_cake_slice": "Cake Slices Eaten", + "stat.minecraft.enchant_item": "Items Enchanted", + "stat.minecraft.fall_one_cm": "Distance Fallen", + "stat.minecraft.fill_cauldron": "Cauldrons Filled", + "stat.minecraft.fish_caught": "Fish Caught", + "stat.minecraft.fly_one_cm": "Distance Flown", + "stat.minecraft.horse_one_cm": "Distance by Horse", + "stat.minecraft.inspect_dispenser": "Dispensers Searched", + "stat.minecraft.inspect_dropper": "Droppers Searched", + "stat.minecraft.inspect_hopper": "Hoppers Searched", + "stat.minecraft.interact_with_anvil": "Interactions with Anvil", + "stat.minecraft.interact_with_beacon": "Interactions with Beacon", + "stat.minecraft.interact_with_blast_furnace": "Interactions with Blast Furnace", + "stat.minecraft.interact_with_brewingstand": "Interactions with Brewing Stand", + "stat.minecraft.interact_with_campfire": "Interactions with Campfire", + "stat.minecraft.interact_with_cartography_table": "Interactions with Cartography Table", + "stat.minecraft.interact_with_crafting_table": "Interactions with Crafting Table", + "stat.minecraft.interact_with_furnace": "Interactions with Furnace", + "stat.minecraft.interact_with_grindstone": "Interactions with Grindstone", + "stat.minecraft.interact_with_lectern": "Interactions with Lectern", + "stat.minecraft.interact_with_loom": "Interactions with Loom", + "stat.minecraft.interact_with_smithing_table": "Interactions with Smithing Table", + "stat.minecraft.interact_with_smoker": "Interactions with Smoker", + "stat.minecraft.interact_with_stonecutter": "Interactions with Stonecutter", + "stat.minecraft.jump": "Jumps", + "stat.minecraft.junk_fished": "Junk Fished", + "stat.minecraft.leave_game": "Games Quit", + "stat.minecraft.minecart_one_cm": "Distance by Minecart", + "stat.minecraft.mob_kills": "Mob Kills", + "stat.minecraft.open_barrel": "Barrels Opened", + "stat.minecraft.open_chest": "Chests Opened", + "stat.minecraft.open_enderchest": "Ender Chests Opened", + "stat.minecraft.open_shulker_box": "Shulker Boxes Opened", + "stat.minecraft.pig_one_cm": "Distance by Pig", + "stat.minecraft.play_noteblock": "Note Blocks Played", + "stat.minecraft.play_record": "Music Discs Played", + "stat.minecraft.play_time": "Time Played", + "stat.minecraft.player_kills": "Player Kills", + "stat.minecraft.pot_flower": "Plants Potted", + "stat.minecraft.raid_trigger": "Raids Triggered", + "stat.minecraft.raid_win": "Raids Won", + "stat.minecraft.ring_bell": "Bells Rung", + "stat.minecraft.sleep_in_bed": "Times Slept in a Bed", + "stat.minecraft.sneak_time": "Sneak Time", + "stat.minecraft.sprint_one_cm": "Distance Sprinted", + "stat.minecraft.strider_one_cm": "Distance by Strider", + "stat.minecraft.swim_one_cm": "Distance Swum", + "stat.minecraft.talked_to_villager": "Talked to Villagers", + "stat.minecraft.target_hit": "Targets Hit", + "stat.minecraft.time_since_death": "Time Since Last Death", + "stat.minecraft.time_since_rest": "Time Since Last Rest", + "stat.minecraft.total_world_time": "Time with World Open", + "stat.minecraft.traded_with_villager": "Traded with Villagers", + "stat.minecraft.treasure_fished": "Treasure Fished", + "stat.minecraft.trigger_trapped_chest": "Trapped Chests Triggered", + "stat.minecraft.tune_noteblock": "Note Blocks Tuned", + "stat.minecraft.use_cauldron": "Water Taken from Cauldron", + "stat.minecraft.walk_on_water_one_cm": "Distance Walked on Water", + "stat.minecraft.walk_one_cm": "Distance Walked", + "stat.minecraft.walk_under_water_one_cm": "Distance Walked under Water", + "stat.mobsButton": "Mobs", + "stats.none": "-", + "stats.tooltip.type.statistic": "Statistic", + "structure_block.button.detect_size": "DETECT", + "structure_block.button.load": "LOAD", + "structure_block.button.save": "SAVE", + "structure_block.custom_data": "Custom Data Tag Name", + "structure_block.detect_size": "Detect Structure Size and Position:", + "structure_block.hover.corner": "Corner: %s", + "structure_block.hover.data": "Data: %s", + "structure_block.hover.load": "Load: %s", + "structure_block.hover.save": "Save: %s", + "structure_block.include_entities": "Include Entities:", + "structure_block.integrity": "Structure Integrity and Seed", + "structure_block.integrity.integrity": "Structure Integrity", + "structure_block.integrity.seed": "Structure Seed", + "structure_block.invalid_structure_name": "Invalid structure name '%s'", + "structure_block.load_not_found": "Structure '%s' is not available", + "structure_block.load_prepare": "Structure '%s' position prepared", + "structure_block.load_success": "Structure loaded from '%s'", + "structure_block.mode_info.corner": "Corner Mode - Placement and Size Marker", + "structure_block.mode_info.data": "Data Mode - Game Logic Marker", + "structure_block.mode_info.load": "Load Mode - Load from File", + "structure_block.mode_info.save": "Save Mode - Write to File", + "structure_block.mode.corner": "Corner", + "structure_block.mode.data": "Data", + "structure_block.mode.load": "Load", + "structure_block.mode.save": "Save", + "structure_block.position": "Relative Position", + "structure_block.position.x": "relative Position x", + "structure_block.position.y": "relative position y", + "structure_block.position.z": "relative position z", + "structure_block.save_failure": "Unable to save structure '%s'", + "structure_block.save_success": "Structure saved as '%s'", + "structure_block.show_air": "Show Invisible Blocks:", + "structure_block.show_boundingbox": "Show Bounding Box:", + "structure_block.size": "Structure Size", + "structure_block.size_failure": "Unable to detect structure size. Add corners with matching structure names", + "structure_block.size_success": "Size successfully detected for '%s'", + "structure_block.size.x": "structure size x", + "structure_block.size.y": "structure size y", + "structure_block.size.z": "structure size z", + "structure_block.structure_name": "Structure Name", + "subtitles.ambient.cave": "Eerie noise", + "subtitles.block.amethyst_block.chime": "Amethyst chimes", + "subtitles.block.amethyst_block.resonate": "Amethyst resonates", + "subtitles.block.anvil.destroy": "Anvil destroyed", + "subtitles.block.anvil.land": "Anvil landed", + "subtitles.block.anvil.use": "Anvil used", + "subtitles.block.barrel.close": "Barrel closes", + "subtitles.block.barrel.open": "Barrel opens", + "subtitles.block.beacon.activate": "Beacon activates", + "subtitles.block.beacon.ambient": "Beacon hums", + "subtitles.block.beacon.deactivate": "Beacon deactivates", + "subtitles.block.beacon.power_select": "Beacon power selected", + "subtitles.block.beehive.drip": "Honey drips", + "subtitles.block.beehive.enter": "Bee enters hive", + "subtitles.block.beehive.exit": "Bee leaves hive", + "subtitles.block.beehive.shear": "Shears scrape", + "subtitles.block.beehive.work": "Bees work", + "subtitles.block.bell.resonate": "Bell resonates", + "subtitles.block.bell.use": "Bell rings", + "subtitles.block.big_dripleaf.tilt_down": "Dripleaf tilts down", + "subtitles.block.big_dripleaf.tilt_up": "Dripleaf tilts up", + "subtitles.block.blastfurnace.fire_crackle": "Blast Furnace crackles", + "subtitles.block.brewing_stand.brew": "Brewing Stand bubbles", + "subtitles.block.bubble_column.bubble_pop": "Bubbles pop", + "subtitles.block.bubble_column.upwards_ambient": "Bubbles flow", + "subtitles.block.bubble_column.upwards_inside": "Bubbles woosh", + "subtitles.block.bubble_column.whirlpool_ambient": "Bubbles whirl", + "subtitles.block.bubble_column.whirlpool_inside": "Bubbles zoom", + "subtitles.block.button.click": "Button clicks", + "subtitles.block.cake.add_candle": "Cake squishes", + "subtitles.block.campfire.crackle": "Campfire crackles", + "subtitles.block.candle.crackle": "Candle crackles", + "subtitles.block.candle.extinguish": "Candle extinguishes", + "subtitles.block.chest.close": "Chest closes", + "subtitles.block.chest.locked": "Chest locked", + "subtitles.block.chest.open": "Chest opens", + "subtitles.block.chorus_flower.death": "Chorus Flower withers", + "subtitles.block.chorus_flower.grow": "Chorus Flower grows", + "subtitles.block.comparator.click": "Comparator clicks", + "subtitles.block.composter.empty": "Composter emptied", + "subtitles.block.composter.fill": "Composter filled", + "subtitles.block.composter.ready": "Composter composts", + "subtitles.block.conduit.activate": "Conduit activates", + "subtitles.block.conduit.ambient": "Conduit pulses", + "subtitles.block.conduit.attack.target": "Conduit attacks", + "subtitles.block.conduit.deactivate": "Conduit deactivates", + "subtitles.block.copper_bulb.turn_off": "Copper Bulb turns off", + "subtitles.block.copper_bulb.turn_on": "Copper Bulb turns on", + "subtitles.block.copper_trapdoor.close": "Trapdoor closes", + "subtitles.block.copper_trapdoor.open": "Trapdoor opens", + "subtitles.block.crafter.craft": "Crafter crafts", + "subtitles.block.crafter.fail": "Crafter fails crafting", + "subtitles.block.decorated_pot.insert": "Decorated Pot fills", + "subtitles.block.decorated_pot.insert_fail": "Decorated Pot wobbles", + "subtitles.block.decorated_pot.shatter": "Decorated Pot shatters", + "subtitles.block.dispenser.dispense": "Dispensed item", + "subtitles.block.dispenser.fail": "Dispenser failed", + "subtitles.block.door.toggle": "Door creaks", + "subtitles.block.enchantment_table.use": "Enchanting Table used", + "subtitles.block.end_portal_frame.fill": "Eye of Ender attaches", + "subtitles.block.end_portal.spawn": "End Portal opens", + "subtitles.block.fence_gate.toggle": "Fence Gate creaks", + "subtitles.block.fire.ambient": "Fire crackles", + "subtitles.block.fire.extinguish": "Fire extinguished", + "subtitles.block.frogspawn.hatch": "Tadpole hatches", + "subtitles.block.furnace.fire_crackle": "Furnace crackles", + "subtitles.block.generic.break": "Block broken", + "subtitles.block.generic.footsteps": "Footsteps", + "subtitles.block.generic.hit": "Block breaking", + "subtitles.block.generic.place": "Block placed", + "subtitles.block.grindstone.use": "Grindstone used", + "subtitles.block.growing_plant.crop": "Plant cropped", + "subtitles.block.hanging_sign.waxed_interact_fail": "Sign wobbles", + "subtitles.block.honey_block.slide": "Sliding down a honey block", + "subtitles.block.iron_trapdoor.close": "Trapdoor closes", + "subtitles.block.iron_trapdoor.open": "Trapdoor opens", + "subtitles.block.lava.ambient": "Lava pops", + "subtitles.block.lava.extinguish": "Lava hisses", + "subtitles.block.lever.click": "Lever clicks", + "subtitles.block.note_block.note": "Note Block plays", + "subtitles.block.piston.move": "Piston moves", + "subtitles.block.pointed_dripstone.drip_lava": "Lava drips", + "subtitles.block.pointed_dripstone.drip_lava_into_cauldron": "Lava drips into Cauldron", + "subtitles.block.pointed_dripstone.drip_water": "Water drips", + "subtitles.block.pointed_dripstone.drip_water_into_cauldron": "Water drips into Cauldron", + "subtitles.block.pointed_dripstone.land": "Stalactite crashes down", + "subtitles.block.portal.ambient": "Portal whooshes", + "subtitles.block.portal.travel": "Portal noise fades", + "subtitles.block.portal.trigger": "Portal noise intensifies", + "subtitles.block.pressure_plate.click": "Pressure Plate clicks", + "subtitles.block.pumpkin.carve": "Shears carve", + "subtitles.block.redstone_torch.burnout": "Torch fizzes", + "subtitles.block.respawn_anchor.ambient": "Respawn Anchor whooshes", + "subtitles.block.respawn_anchor.charge": "Respawn Anchor is charged", + "subtitles.block.respawn_anchor.deplete": "Respawn Anchor depletes", + "subtitles.block.respawn_anchor.set_spawn": "Respawn Anchor sets spawn", + "subtitles.block.sculk_catalyst.bloom": "Sculk Catalyst blooms", + "subtitles.block.sculk_sensor.clicking": "Sculk Sensor clicks", + "subtitles.block.sculk_sensor.clicking_stop": "Sculk Sensor stops clicking", + "subtitles.block.sculk_shrieker.shriek": "Sculk Shrieker shrieks", + "subtitles.block.sculk.charge": "Sculk bubbles", + "subtitles.block.sculk.spread": "Sculk spreads", + "subtitles.block.shulker_box.close": "Shulker closes", + "subtitles.block.shulker_box.open": "Shulker opens", + "subtitles.block.sign.waxed_interact_fail": "Sign wobbles", + "subtitles.block.smithing_table.use": "Smithing Table used", + "subtitles.block.smoker.smoke": "Smoker smokes", + "subtitles.block.sniffer_egg.crack": "Sniffer Egg cracks", + "subtitles.block.sniffer_egg.hatch": "Sniffer Egg hatches", + "subtitles.block.sniffer_egg.plop": "Sniffer plops", + "subtitles.block.sponge.absorb": "Sponge sucks", + "subtitles.block.sweet_berry_bush.pick_berries": "Berries pop", + "subtitles.block.trapdoor.toggle": "Trapdoor creaks", + "subtitles.block.trial_spawner.about_to_spawn_item": "Ominous item prepares", + "subtitles.block.trial_spawner.ambient": "Trial Spawner crackles", + "subtitles.block.trial_spawner.ambient_charged": "Ominous crackling", + "subtitles.block.trial_spawner.ambient_ominous": "Ominous crackling", + "subtitles.block.trial_spawner.charge_activate": "Omen engulfs Trial Spawner", + "subtitles.block.trial_spawner.close_shutter": "Trial Spawner closes", + "subtitles.block.trial_spawner.detect_player": "Trial Spawner charges up", + "subtitles.block.trial_spawner.eject_item": "Trial Spawner ejects items", + "subtitles.block.trial_spawner.ominous_activate": "Omen engulfs Trial Spawner", + "subtitles.block.trial_spawner.open_shutter": "Trial Spawner opens", + "subtitles.block.trial_spawner.spawn_item": "Ominous item drops", + "subtitles.block.trial_spawner.spawn_item_begin": "Ominous item appears", + "subtitles.block.trial_spawner.spawn_mob": "Trial Spawner spawns a mob", + "subtitles.block.tripwire.attach": "Tripwire attaches", + "subtitles.block.tripwire.click": "Tripwire clicks", + "subtitles.block.tripwire.detach": "Tripwire detaches", + "subtitles.block.vault.activate": "Vault ignites", + "subtitles.block.vault.ambient": "Vault crackles", + "subtitles.block.vault.close_shutter": "Vault closes", + "subtitles.block.vault.deactivate": "Vault extinguishes", + "subtitles.block.vault.eject_item": "Vault ejects item", + "subtitles.block.vault.insert_item": "Vault unlocks", + "subtitles.block.vault.insert_item_fail": "Vault rejects item", + "subtitles.block.vault.open_shutter": "Vault opens", + "subtitles.block.vault.reject_rewarded_player": "Vault rejects player", + "subtitles.block.water.ambient": "Water flows", + "subtitles.block.wet_sponge.dries": "Sponge dries", + "subtitles.chiseled_bookshelf.insert": "Book placed", + "subtitles.chiseled_bookshelf.insert_enchanted": "Enchanted Book placed", + "subtitles.chiseled_bookshelf.take": "Book taken", + "subtitles.chiseled_bookshelf.take_enchanted": "Enchanted Book taken", + "subtitles.enchant.thorns.hit": "Thorns prick", + "subtitles.entity.allay.ambient_with_item": "Allay seeks", + "subtitles.entity.allay.ambient_without_item": "Allay yearns", + "subtitles.entity.allay.death": "Allay dies", + "subtitles.entity.allay.hurt": "Allay hurts", + "subtitles.entity.allay.item_given": "Allay chortles", + "subtitles.entity.allay.item_taken": "Allay allays", + "subtitles.entity.allay.item_thrown": "Allay tosses", + "subtitles.entity.armadillo.ambient": "Armadillo grunts", + "subtitles.entity.armadillo.brush": "Scute is brushed off", + "subtitles.entity.armadillo.death": "Armadillo dies", + "subtitles.entity.armadillo.eat": "Armadillo eats", + "subtitles.entity.armadillo.hurt": "Armadillo hurts", + "subtitles.entity.armadillo.hurt_reduced": "Armadillo shields itself", + "subtitles.entity.armadillo.land": "Armadillo lands", + "subtitles.entity.armadillo.peek": "Armadillo peeks", + "subtitles.entity.armadillo.roll": "Armadillo rolls up", + "subtitles.entity.armadillo.scute_drop": "Armadillo sheds scute", + "subtitles.entity.armadillo.unroll_finish": "Armadillo unrolls", + "subtitles.entity.armadillo.unroll_start": "Armadillo peeks", + "subtitles.entity.armor_stand.fall": "Something fell", + "subtitles.entity.arrow.hit": "Arrow hits", + "subtitles.entity.arrow.hit_player": "Player hit", + "subtitles.entity.arrow.shoot": "Arrow fired", + "subtitles.entity.axolotl.attack": "Axolotl attacks", + "subtitles.entity.axolotl.death": "Axolotl dies", + "subtitles.entity.axolotl.hurt": "Axolotl hurts", + "subtitles.entity.axolotl.idle_air": "Axolotl chirps", + "subtitles.entity.axolotl.idle_water": "Axolotl chirps", + "subtitles.entity.axolotl.splash": "Axolotl splashes", + "subtitles.entity.axolotl.swim": "Axolotl swims", + "subtitles.entity.bat.ambient": "Bat screeches", + "subtitles.entity.bat.death": "Bat dies", + "subtitles.entity.bat.hurt": "Bat hurts", + "subtitles.entity.bat.takeoff": "Bat takes off", + "subtitles.entity.bee.ambient": "Bee buzzes", + "subtitles.entity.bee.death": "Bee dies", + "subtitles.entity.bee.hurt": "Bee hurts", + "subtitles.entity.bee.loop": "Bee buzzes", + "subtitles.entity.bee.loop_aggressive": "Bee buzzes angrily", + "subtitles.entity.bee.pollinate": "Bee buzzes happily", + "subtitles.entity.bee.sting": "Bee stings", + "subtitles.entity.blaze.ambient": "Blaze breathes", + "subtitles.entity.blaze.burn": "Blaze crackles", + "subtitles.entity.blaze.death": "Blaze dies", + "subtitles.entity.blaze.hurt": "Blaze hurts", + "subtitles.entity.blaze.shoot": "Blaze shoots", + "subtitles.entity.boat.paddle_land": "Rowing", + "subtitles.entity.boat.paddle_water": "Rowing", + "subtitles.entity.bogged.ambient": "Bogged rattles", + "subtitles.entity.bogged.death": "Bogged dies", + "subtitles.entity.bogged.hurt": "Bogged hurts", + "subtitles.entity.breeze.charge": "Breeze charges", + "subtitles.entity.breeze.death": "Breeze dies", + "subtitles.entity.breeze.deflect": "Breeze deflects", + "subtitles.entity.breeze.hurt": "Breeze hurts", + "subtitles.entity.breeze.idle_air": "Breeze flies", + "subtitles.entity.breeze.idle_ground": "Breeze whirs", + "subtitles.entity.breeze.inhale": "Breeze inhales", + "subtitles.entity.breeze.jump": "Breeze jumps", + "subtitles.entity.breeze.land": "Breeze lands", + "subtitles.entity.breeze.shoot": "Breeze shoots", + "subtitles.entity.breeze.slide": "Breeze slides", + "subtitles.entity.breeze.whirl": "Breeze whirls", + "subtitles.entity.breeze.wind_burst": "Wind Charge bursts", + "subtitles.entity.camel.ambient": "Camel grunts", + "subtitles.entity.camel.dash": "Camel yeets", + "subtitles.entity.camel.dash_ready": "Camel recovers", + "subtitles.entity.camel.death": "Camel dies", + "subtitles.entity.camel.eat": "Camel eats", + "subtitles.entity.camel.hurt": "Camel hurts", + "subtitles.entity.camel.saddle": "Saddle equips", + "subtitles.entity.camel.sit": "Camel sits down", + "subtitles.entity.camel.stand": "Camel stands up", + "subtitles.entity.camel.step": "Camel steps", + "subtitles.entity.camel.step_sand": "Camel sands", + "subtitles.entity.cat.ambient": "Cat meows", + "subtitles.entity.cat.beg_for_food": "Cat begs", + "subtitles.entity.cat.death": "Cat dies", + "subtitles.entity.cat.eat": "Cat eats", + "subtitles.entity.cat.hiss": "Cat hisses", + "subtitles.entity.cat.hurt": "Cat hurts", + "subtitles.entity.cat.purr": "Cat purrs", + "subtitles.entity.chicken.ambient": "Chicken clucks", + "subtitles.entity.chicken.death": "Chicken dies", + "subtitles.entity.chicken.egg": "Chicken plops", + "subtitles.entity.chicken.hurt": "Chicken hurts", + "subtitles.entity.cod.death": "Cod dies", + "subtitles.entity.cod.flop": "Cod flops", + "subtitles.entity.cod.hurt": "Cod hurts", + "subtitles.entity.cow.ambient": "Cow moos", + "subtitles.entity.cow.death": "Cow dies", + "subtitles.entity.cow.hurt": "Cow hurts", + "subtitles.entity.cow.milk": "Cow gets milked", + "subtitles.entity.creeper.death": "Creeper dies", + "subtitles.entity.creeper.hurt": "Creeper hurts", + "subtitles.entity.creeper.primed": "Creeper hisses", + "subtitles.entity.dolphin.ambient": "Dolphin chirps", + "subtitles.entity.dolphin.ambient_water": "Dolphin whistles", + "subtitles.entity.dolphin.attack": "Dolphin attacks", + "subtitles.entity.dolphin.death": "Dolphin dies", + "subtitles.entity.dolphin.eat": "Dolphin eats", + "subtitles.entity.dolphin.hurt": "Dolphin hurts", + "subtitles.entity.dolphin.jump": "Dolphin jumps", + "subtitles.entity.dolphin.play": "Dolphin plays", + "subtitles.entity.dolphin.splash": "Dolphin splashes", + "subtitles.entity.dolphin.swim": "Dolphin swims", + "subtitles.entity.donkey.ambient": "Donkey hee-haws", + "subtitles.entity.donkey.angry": "Donkey neighs", + "subtitles.entity.donkey.chest": "Donkey Chest equips", + "subtitles.entity.donkey.death": "Donkey dies", + "subtitles.entity.donkey.eat": "Donkey eats", + "subtitles.entity.donkey.hurt": "Donkey hurts", + "subtitles.entity.donkey.jump": "Donkey jumps", + "subtitles.entity.drowned.ambient": "Drowned gurgles", + "subtitles.entity.drowned.ambient_water": "Drowned gurgles", + "subtitles.entity.drowned.death": "Drowned dies", + "subtitles.entity.drowned.hurt": "Drowned hurts", + "subtitles.entity.drowned.shoot": "Drowned throws Trident", + "subtitles.entity.drowned.step": "Drowned steps", + "subtitles.entity.drowned.swim": "Drowned swims", + "subtitles.entity.egg.throw": "Egg flies", + "subtitles.entity.elder_guardian.ambient": "Elder Guardian moans", + "subtitles.entity.elder_guardian.ambient_land": "Elder Guardian flaps", + "subtitles.entity.elder_guardian.curse": "Elder Guardian curses", + "subtitles.entity.elder_guardian.death": "Elder Guardian dies", + "subtitles.entity.elder_guardian.flop": "Elder Guardian flops", + "subtitles.entity.elder_guardian.hurt": "Elder Guardian hurts", + "subtitles.entity.ender_dragon.ambient": "Dragon roars", + "subtitles.entity.ender_dragon.death": "Dragon dies", + "subtitles.entity.ender_dragon.flap": "Dragon flaps", + "subtitles.entity.ender_dragon.growl": "Dragon growls", + "subtitles.entity.ender_dragon.hurt": "Dragon hurts", + "subtitles.entity.ender_dragon.shoot": "Dragon shoots", + "subtitles.entity.ender_eye.death": "Eye of Ender falls", + "subtitles.entity.ender_eye.launch": "Eye of Ender shoots", + "subtitles.entity.ender_pearl.throw": "Ender Pearl flies", + "subtitles.entity.enderman.ambient": "Enderman vwoops", + "subtitles.entity.enderman.death": "Enderman dies", + "subtitles.entity.enderman.hurt": "Enderman hurts", + "subtitles.entity.enderman.scream": "Enderman screams", + "subtitles.entity.enderman.stare": "Enderman cries out", + "subtitles.entity.enderman.teleport": "Enderman teleports", + "subtitles.entity.endermite.ambient": "Endermite scuttles", + "subtitles.entity.endermite.death": "Endermite dies", + "subtitles.entity.endermite.hurt": "Endermite hurts", + "subtitles.entity.evoker_fangs.attack": "Fangs snap", + "subtitles.entity.evoker.ambient": "Evoker murmurs", + "subtitles.entity.evoker.cast_spell": "Evoker casts spell", + "subtitles.entity.evoker.celebrate": "Evoker cheers", + "subtitles.entity.evoker.death": "Evoker dies", + "subtitles.entity.evoker.hurt": "Evoker hurts", + "subtitles.entity.evoker.prepare_attack": "Evoker prepares attack", + "subtitles.entity.evoker.prepare_summon": "Evoker prepares summoning", + "subtitles.entity.evoker.prepare_wololo": "Evoker prepares charming", + "subtitles.entity.experience_orb.pickup": "Experience gained", + "subtitles.entity.firework_rocket.blast": "Firework blasts", + "subtitles.entity.firework_rocket.launch": "Firework launches", + "subtitles.entity.firework_rocket.twinkle": "Firework twinkles", + "subtitles.entity.fishing_bobber.retrieve": "Bobber retrieved", + "subtitles.entity.fishing_bobber.splash": "Fishing Bobber splashes", + "subtitles.entity.fishing_bobber.throw": "Bobber thrown", + "subtitles.entity.fox.aggro": "Fox angers", + "subtitles.entity.fox.ambient": "Fox squeaks", + "subtitles.entity.fox.bite": "Fox bites", + "subtitles.entity.fox.death": "Fox dies", + "subtitles.entity.fox.eat": "Fox eats", + "subtitles.entity.fox.hurt": "Fox hurts", + "subtitles.entity.fox.screech": "Fox screeches", + "subtitles.entity.fox.sleep": "Fox snores", + "subtitles.entity.fox.sniff": "Fox sniffs", + "subtitles.entity.fox.spit": "Fox spits", + "subtitles.entity.fox.teleport": "Fox teleports", + "subtitles.entity.frog.ambient": "Frog croaks", + "subtitles.entity.frog.death": "Frog dies", + "subtitles.entity.frog.eat": "Frog eats", + "subtitles.entity.frog.hurt": "Frog hurts", + "subtitles.entity.frog.lay_spawn": "Frog lays spawn", + "subtitles.entity.frog.long_jump": "Frog jumps", + "subtitles.entity.generic.big_fall": "Something fell", + "subtitles.entity.generic.burn": "Burning", + "subtitles.entity.generic.death": "Dying", + "subtitles.entity.generic.drink": "Sipping", + "subtitles.entity.generic.eat": "Eating", + "subtitles.entity.generic.explode": "Explosion", + "subtitles.entity.generic.extinguish_fire": "Fire extinguishes", + "subtitles.entity.generic.hurt": "Something hurts", + "subtitles.entity.generic.small_fall": "Something trips", + "subtitles.entity.generic.splash": "Splashing", + "subtitles.entity.generic.swim": "Swimming", + "subtitles.entity.generic.wind_burst": "Wind Charge bursts", + "subtitles.entity.ghast.ambient": "Ghast cries", + "subtitles.entity.ghast.death": "Ghast dies", + "subtitles.entity.ghast.hurt": "Ghast hurts", + "subtitles.entity.ghast.shoot": "Ghast shoots", + "subtitles.entity.glow_item_frame.add_item": "Glow Item Frame fills", + "subtitles.entity.glow_item_frame.break": "Glow Item Frame broken", + "subtitles.entity.glow_item_frame.place": "Glow Item Frame placed", + "subtitles.entity.glow_item_frame.remove_item": "Glow Item Frame empties", + "subtitles.entity.glow_item_frame.rotate_item": "Glow Item Frame clicks", + "subtitles.entity.glow_squid.ambient": "Glow Squid swims", + "subtitles.entity.glow_squid.death": "Glow Squid dies", + "subtitles.entity.glow_squid.hurt": "Glow Squid hurts", + "subtitles.entity.glow_squid.squirt": "Glow Squid shoots ink", + "subtitles.entity.goat.ambient": "Goat bleats", + "subtitles.entity.goat.death": "Goat dies", + "subtitles.entity.goat.eat": "Goat eats", + "subtitles.entity.goat.horn_break": "Goat Horn breaks off", + "subtitles.entity.goat.hurt": "Goat hurts", + "subtitles.entity.goat.long_jump": "Goat leaps", + "subtitles.entity.goat.milk": "Goat gets milked", + "subtitles.entity.goat.prepare_ram": "Goat stomps", + "subtitles.entity.goat.ram_impact": "Goat rams", + "subtitles.entity.goat.screaming.ambient": "Goat bellows", + "subtitles.entity.goat.step": "Goat steps", + "subtitles.entity.guardian.ambient": "Guardian moans", + "subtitles.entity.guardian.ambient_land": "Guardian flaps", + "subtitles.entity.guardian.attack": "Guardian shoots", + "subtitles.entity.guardian.death": "Guardian dies", + "subtitles.entity.guardian.flop": "Guardian flops", + "subtitles.entity.guardian.hurt": "Guardian hurts", + "subtitles.entity.hoglin.ambient": "Hoglin growls", + "subtitles.entity.hoglin.angry": "Hoglin growls angrily", + "subtitles.entity.hoglin.attack": "Hoglin attacks", + "subtitles.entity.hoglin.converted_to_zombified": "Hoglin converts to Zoglin", + "subtitles.entity.hoglin.death": "Hoglin dies", + "subtitles.entity.hoglin.hurt": "Hoglin hurts", + "subtitles.entity.hoglin.retreat": "Hoglin retreats", + "subtitles.entity.hoglin.step": "Hoglin steps", + "subtitles.entity.horse.ambient": "Horse neighs", + "subtitles.entity.horse.angry": "Horse neighs", + "subtitles.entity.horse.armor": "Horse armor equips", + "subtitles.entity.horse.breathe": "Horse breathes", + "subtitles.entity.horse.death": "Horse dies", + "subtitles.entity.horse.eat": "Horse eats", + "subtitles.entity.horse.gallop": "Horse gallops", + "subtitles.entity.horse.hurt": "Horse hurts", + "subtitles.entity.horse.jump": "Horse jumps", + "subtitles.entity.horse.saddle": "Saddle equips", + "subtitles.entity.husk.ambient": "Husk groans", + "subtitles.entity.husk.converted_to_zombie": "Husk converts to Zombie", + "subtitles.entity.husk.death": "Husk dies", + "subtitles.entity.husk.hurt": "Husk hurts", + "subtitles.entity.illusioner.ambient": "Illusioner murmurs", + "subtitles.entity.illusioner.cast_spell": "Illusioner casts spell", + "subtitles.entity.illusioner.death": "Illusioner dies", + "subtitles.entity.illusioner.hurt": "Illusioner hurts", + "subtitles.entity.illusioner.mirror_move": "Illusioner displaces", + "subtitles.entity.illusioner.prepare_blindness": "Illusioner prepares blindness", + "subtitles.entity.illusioner.prepare_mirror": "Illusioner prepares mirror image", + "subtitles.entity.iron_golem.attack": "Iron Golem attacks", + "subtitles.entity.iron_golem.damage": "Iron Golem breaks", + "subtitles.entity.iron_golem.death": "Iron Golem dies", + "subtitles.entity.iron_golem.hurt": "Iron Golem hurts", + "subtitles.entity.iron_golem.repair": "Iron Golem repaired", + "subtitles.entity.item_frame.add_item": "Item Frame fills", + "subtitles.entity.item_frame.break": "Item Frame broken", + "subtitles.entity.item_frame.place": "Item Frame placed", + "subtitles.entity.item_frame.remove_item": "Item Frame empties", + "subtitles.entity.item_frame.rotate_item": "Item Frame clicks", + "subtitles.entity.item.break": "Item breaks", + "subtitles.entity.item.pickup": "Item plops", + "subtitles.entity.leash_knot.break": "Leash Knot broken", + "subtitles.entity.leash_knot.place": "Leash Knot tied", + "subtitles.entity.lightning_bolt.impact": "Lightning strikes", + "subtitles.entity.lightning_bolt.thunder": "Thunder roars", + "subtitles.entity.llama.ambient": "Llama bleats", + "subtitles.entity.llama.angry": "Llama bleats angrily", + "subtitles.entity.llama.chest": "Llama Chest equips", + "subtitles.entity.llama.death": "Llama dies", + "subtitles.entity.llama.eat": "Llama eats", + "subtitles.entity.llama.hurt": "Llama hurts", + "subtitles.entity.llama.spit": "Llama spits", + "subtitles.entity.llama.step": "Llama steps", + "subtitles.entity.llama.swag": "Llama is decorated", + "subtitles.entity.magma_cube.death": "Magma Cube dies", + "subtitles.entity.magma_cube.hurt": "Magma Cube hurts", + "subtitles.entity.magma_cube.squish": "Magma Cube squishes", + "subtitles.entity.minecart.riding": "Minecart rolls", + "subtitles.entity.mooshroom.convert": "Mooshroom transforms", + "subtitles.entity.mooshroom.eat": "Mooshroom eats", + "subtitles.entity.mooshroom.milk": "Mooshroom gets milked", + "subtitles.entity.mooshroom.suspicious_milk": "Mooshroom gets milked suspiciously", + "subtitles.entity.mule.ambient": "Mule hee-haws", + "subtitles.entity.mule.angry": "Mule neighs", + "subtitles.entity.mule.chest": "Mule Chest equips", + "subtitles.entity.mule.death": "Mule dies", + "subtitles.entity.mule.eat": "Mule eats", + "subtitles.entity.mule.hurt": "Mule hurts", + "subtitles.entity.mule.jump": "Mule jumps", + "subtitles.entity.painting.break": "Painting broken", + "subtitles.entity.painting.place": "Painting placed", + "subtitles.entity.panda.aggressive_ambient": "Panda huffs", + "subtitles.entity.panda.ambient": "Panda pants", + "subtitles.entity.panda.bite": "Panda bites", + "subtitles.entity.panda.cant_breed": "Panda bleats", + "subtitles.entity.panda.death": "Panda dies", + "subtitles.entity.panda.eat": "Panda eats", + "subtitles.entity.panda.hurt": "Panda hurts", + "subtitles.entity.panda.pre_sneeze": "Panda's nose tickles", + "subtitles.entity.panda.sneeze": "Panda sneezes", + "subtitles.entity.panda.step": "Panda steps", + "subtitles.entity.panda.worried_ambient": "Panda whimpers", + "subtitles.entity.parrot.ambient": "Parrot talks", + "subtitles.entity.parrot.death": "Parrot dies", + "subtitles.entity.parrot.eats": "Parrot eats", + "subtitles.entity.parrot.fly": "Parrot flutters", + "subtitles.entity.parrot.hurts": "Parrot hurts", + "subtitles.entity.parrot.imitate.blaze": "Parrot breathes", + "subtitles.entity.parrot.imitate.bogged": "Parrot rattles", + "subtitles.entity.parrot.imitate.breeze": "Parrot whirs", + "subtitles.entity.parrot.imitate.creeper": "Parrot hisses", + "subtitles.entity.parrot.imitate.drowned": "Parrot gurgles", + "subtitles.entity.parrot.imitate.elder_guardian": "Parrot moans", + "subtitles.entity.parrot.imitate.ender_dragon": "Parrot roars", + "subtitles.entity.parrot.imitate.endermite": "Parrot scuttles", + "subtitles.entity.parrot.imitate.evoker": "Parrot murmurs", + "subtitles.entity.parrot.imitate.ghast": "Parrot cries", + "subtitles.entity.parrot.imitate.guardian": "Parrot moans", + "subtitles.entity.parrot.imitate.hoglin": "Parrot growls", + "subtitles.entity.parrot.imitate.husk": "Parrot groans", + "subtitles.entity.parrot.imitate.illusioner": "Parrot murmurs", + "subtitles.entity.parrot.imitate.magma_cube": "Parrot squishes", + "subtitles.entity.parrot.imitate.phantom": "Parrot screeches", + "subtitles.entity.parrot.imitate.piglin": "Parrot snorts", + "subtitles.entity.parrot.imitate.piglin_brute": "Parrot snorts", + "subtitles.entity.parrot.imitate.pillager": "Parrot murmurs", + "subtitles.entity.parrot.imitate.ravager": "Parrot grunts", + "subtitles.entity.parrot.imitate.shulker": "Parrot lurks", + "subtitles.entity.parrot.imitate.silverfish": "Parrot hisses", + "subtitles.entity.parrot.imitate.skeleton": "Parrot rattles", + "subtitles.entity.parrot.imitate.slime": "Parrot squishes", + "subtitles.entity.parrot.imitate.spider": "Parrot hisses", + "subtitles.entity.parrot.imitate.stray": "Parrot rattles", + "subtitles.entity.parrot.imitate.vex": "Parrot vexes", + "subtitles.entity.parrot.imitate.vindicator": "Parrot mutters", + "subtitles.entity.parrot.imitate.warden": "Parrot whines", + "subtitles.entity.parrot.imitate.witch": "Parrot giggles", + "subtitles.entity.parrot.imitate.wither": "Parrot angers", + "subtitles.entity.parrot.imitate.wither_skeleton": "Parrot rattles", + "subtitles.entity.parrot.imitate.zoglin": "Parrot growls", + "subtitles.entity.parrot.imitate.zombie": "Parrot groans", + "subtitles.entity.parrot.imitate.zombie_villager": "Parrot groans", + "subtitles.entity.phantom.ambient": "Phantom screeches", + "subtitles.entity.phantom.bite": "Phantom bites", + "subtitles.entity.phantom.death": "Phantom dies", + "subtitles.entity.phantom.flap": "Phantom flaps", + "subtitles.entity.phantom.hurt": "Phantom hurts", + "subtitles.entity.phantom.swoop": "Phantom swoops", + "subtitles.entity.pig.ambient": "Pig oinks", + "subtitles.entity.pig.death": "Pig dies", + "subtitles.entity.pig.hurt": "Pig hurts", + "subtitles.entity.pig.saddle": "Saddle equips", + "subtitles.entity.piglin_brute.ambient": "Piglin Brute snorts", + "subtitles.entity.piglin_brute.angry": "Piglin Brute snorts angrily", + "subtitles.entity.piglin_brute.converted_to_zombified": "Piglin Brute converts to Zombified Piglin", + "subtitles.entity.piglin_brute.death": "Piglin Brute dies", + "subtitles.entity.piglin_brute.hurt": "Piglin Brute hurts", + "subtitles.entity.piglin_brute.step": "Piglin Brute steps", + "subtitles.entity.piglin.admiring_item": "Piglin admires item", + "subtitles.entity.piglin.ambient": "Piglin snorts", + "subtitles.entity.piglin.angry": "Piglin snorts angrily", + "subtitles.entity.piglin.celebrate": "Piglin celebrates", + "subtitles.entity.piglin.converted_to_zombified": "Piglin converts to Zombified Piglin", + "subtitles.entity.piglin.death": "Piglin dies", + "subtitles.entity.piglin.hurt": "Piglin hurts", + "subtitles.entity.piglin.jealous": "Piglin snorts enviously", + "subtitles.entity.piglin.retreat": "Piglin retreats", + "subtitles.entity.piglin.step": "Piglin steps", + "subtitles.entity.pillager.ambient": "Pillager murmurs", + "subtitles.entity.pillager.celebrate": "Pillager cheers", + "subtitles.entity.pillager.death": "Pillager dies", + "subtitles.entity.pillager.hurt": "Pillager hurts", + "subtitles.entity.player.attack.crit": "Critical attack", + "subtitles.entity.player.attack.knockback": "Knockback attack", + "subtitles.entity.player.attack.strong": "Strong attack", + "subtitles.entity.player.attack.sweep": "Sweeping attack", + "subtitles.entity.player.attack.weak": "Weak attack", + "subtitles.entity.player.burp": "Burp", + "subtitles.entity.player.death": "Player dies", + "subtitles.entity.player.freeze_hurt": "Player freezes", + "subtitles.entity.player.hurt": "Player hurts", + "subtitles.entity.player.hurt_drown": "Player drowning", + "subtitles.entity.player.hurt_on_fire": "Player burns", + "subtitles.entity.player.levelup": "Player dings", + "subtitles.entity.player.teleport": "Player teleports", + "subtitles.entity.polar_bear.ambient": "Polar Bear groans", + "subtitles.entity.polar_bear.ambient_baby": "Baby Polar Bear hums", + "subtitles.entity.polar_bear.death": "Polar Bear dies", + "subtitles.entity.polar_bear.hurt": "Polar Bear hurts", + "subtitles.entity.polar_bear.warning": "Polar Bear roars", + "subtitles.entity.potion.splash": "Bottle smashes", + "subtitles.entity.potion.throw": "Bottle thrown", + "subtitles.entity.puffer_fish.blow_out": "Pufferfish deflates", + "subtitles.entity.puffer_fish.blow_up": "Pufferfish inflates", + "subtitles.entity.puffer_fish.death": "Pufferfish dies", + "subtitles.entity.puffer_fish.flop": "Pufferfish flops", + "subtitles.entity.puffer_fish.hurt": "Pufferfish hurts", + "subtitles.entity.puffer_fish.sting": "Pufferfish stings", + "subtitles.entity.rabbit.ambient": "Rabbit squeaks", + "subtitles.entity.rabbit.attack": "Rabbit attacks", + "subtitles.entity.rabbit.death": "Rabbit dies", + "subtitles.entity.rabbit.hurt": "Rabbit hurts", + "subtitles.entity.rabbit.jump": "Rabbit hops", + "subtitles.entity.ravager.ambient": "Ravager grunts", + "subtitles.entity.ravager.attack": "Ravager bites", + "subtitles.entity.ravager.celebrate": "Ravager cheers", + "subtitles.entity.ravager.death": "Ravager dies", + "subtitles.entity.ravager.hurt": "Ravager hurts", + "subtitles.entity.ravager.roar": "Ravager roars", + "subtitles.entity.ravager.step": "Ravager steps", + "subtitles.entity.ravager.stunned": "Ravager stunned", + "subtitles.entity.salmon.death": "Salmon dies", + "subtitles.entity.salmon.flop": "Salmon flops", + "subtitles.entity.salmon.hurt": "Salmon hurts", + "subtitles.entity.sheep.ambient": "Sheep baahs", + "subtitles.entity.sheep.death": "Sheep dies", + "subtitles.entity.sheep.hurt": "Sheep hurts", + "subtitles.entity.shulker_bullet.hit": "Shulker Bullet explodes", + "subtitles.entity.shulker_bullet.hurt": "Shulker Bullet breaks", + "subtitles.entity.shulker.ambient": "Shulker lurks", + "subtitles.entity.shulker.close": "Shulker closes", + "subtitles.entity.shulker.death": "Shulker dies", + "subtitles.entity.shulker.hurt": "Shulker hurts", + "subtitles.entity.shulker.open": "Shulker opens", + "subtitles.entity.shulker.shoot": "Shulker shoots", + "subtitles.entity.shulker.teleport": "Shulker teleports", + "subtitles.entity.silverfish.ambient": "Silverfish hisses", + "subtitles.entity.silverfish.death": "Silverfish dies", + "subtitles.entity.silverfish.hurt": "Silverfish hurts", + "subtitles.entity.skeleton_horse.ambient": "Skeleton Horse cries", + "subtitles.entity.skeleton_horse.death": "Skeleton Horse dies", + "subtitles.entity.skeleton_horse.hurt": "Skeleton Horse hurts", + "subtitles.entity.skeleton_horse.swim": "Skeleton Horse swims", + "subtitles.entity.skeleton.ambient": "Skeleton rattles", + "subtitles.entity.skeleton.converted_to_stray": "Skeleton converts to Stray", + "subtitles.entity.skeleton.death": "Skeleton dies", + "subtitles.entity.skeleton.hurt": "Skeleton hurts", + "subtitles.entity.skeleton.shoot": "Skeleton shoots", + "subtitles.entity.slime.attack": "Slime attacks", + "subtitles.entity.slime.death": "Slime dies", + "subtitles.entity.slime.hurt": "Slime hurts", + "subtitles.entity.slime.squish": "Slime squishes", + "subtitles.entity.sniffer.death": "Sniffer dies", + "subtitles.entity.sniffer.digging": "Sniffer digs", + "subtitles.entity.sniffer.digging_stop": "Sniffer stands up", + "subtitles.entity.sniffer.drop_seed": "Sniffer drops seed", + "subtitles.entity.sniffer.eat": "Sniffer eats", + "subtitles.entity.sniffer.egg_crack": "Sniffer Egg cracks", + "subtitles.entity.sniffer.egg_hatch": "Sniffer Egg hatches", + "subtitles.entity.sniffer.happy": "Sniffer delights", + "subtitles.entity.sniffer.hurt": "Sniffer hurts", + "subtitles.entity.sniffer.idle": "Sniffer grunts", + "subtitles.entity.sniffer.scenting": "Sniffer scents", + "subtitles.entity.sniffer.searching": "Sniffer searches", + "subtitles.entity.sniffer.sniffing": "Sniffer sniffs", + "subtitles.entity.sniffer.step": "Sniffer steps", + "subtitles.entity.snow_golem.death": "Snow Golem dies", + "subtitles.entity.snow_golem.hurt": "Snow Golem hurts", + "subtitles.entity.snowball.throw": "Snowball flies", + "subtitles.entity.spider.ambient": "Spider hisses", + "subtitles.entity.spider.death": "Spider dies", + "subtitles.entity.spider.hurt": "Spider hurts", + "subtitles.entity.squid.ambient": "Squid swims", + "subtitles.entity.squid.death": "Squid dies", + "subtitles.entity.squid.hurt": "Squid hurts", + "subtitles.entity.squid.squirt": "Squid shoots ink", + "subtitles.entity.stray.ambient": "Stray rattles", + "subtitles.entity.stray.death": "Stray dies", + "subtitles.entity.stray.hurt": "Stray hurts", + "subtitles.entity.strider.death": "Strider dies", + "subtitles.entity.strider.eat": "Strider eats", + "subtitles.entity.strider.happy": "Strider warbles", + "subtitles.entity.strider.hurt": "Strider hurts", + "subtitles.entity.strider.idle": "Strider chirps", + "subtitles.entity.strider.retreat": "Strider retreats", + "subtitles.entity.tadpole.death": "Tadpole dies", + "subtitles.entity.tadpole.flop": "Tadpole flops", + "subtitles.entity.tadpole.grow_up": "Tadpole grows up", + "subtitles.entity.tadpole.hurt": "Tadpole hurts", + "subtitles.entity.tnt.primed": "TNT fizzes", + "subtitles.entity.tropical_fish.death": "Tropical Fish dies", + "subtitles.entity.tropical_fish.flop": "Tropical Fish flops", + "subtitles.entity.tropical_fish.hurt": "Tropical Fish hurts", + "subtitles.entity.turtle.ambient_land": "Turtle chirps", + "subtitles.entity.turtle.death": "Turtle dies", + "subtitles.entity.turtle.death_baby": "Baby Turtle dies", + "subtitles.entity.turtle.egg_break": "Turtle Egg breaks", + "subtitles.entity.turtle.egg_crack": "Turtle Egg cracks", + "subtitles.entity.turtle.egg_hatch": "Turtle Egg hatches", + "subtitles.entity.turtle.hurt": "Turtle hurts", + "subtitles.entity.turtle.hurt_baby": "Baby Turtle hurts", + "subtitles.entity.turtle.lay_egg": "Turtle lays egg", + "subtitles.entity.turtle.shamble": "Turtle shambles", + "subtitles.entity.turtle.shamble_baby": "Baby Turtle shambles", + "subtitles.entity.turtle.swim": "Turtle swims", + "subtitles.entity.vex.ambient": "Vex vexes", + "subtitles.entity.vex.charge": "Vex shrieks", + "subtitles.entity.vex.death": "Vex dies", + "subtitles.entity.vex.hurt": "Vex hurts", + "subtitles.entity.villager.ambient": "Villager mumbles", + "subtitles.entity.villager.celebrate": "Villager cheers", + "subtitles.entity.villager.death": "Villager dies", + "subtitles.entity.villager.hurt": "Villager hurts", + "subtitles.entity.villager.no": "Villager disagrees", + "subtitles.entity.villager.trade": "Villager trades", + "subtitles.entity.villager.work_armorer": "Armorer works", + "subtitles.entity.villager.work_butcher": "Butcher works", + "subtitles.entity.villager.work_cartographer": "Cartographer works", + "subtitles.entity.villager.work_cleric": "Cleric works", + "subtitles.entity.villager.work_farmer": "Farmer works", + "subtitles.entity.villager.work_fisherman": "Fisherman works", + "subtitles.entity.villager.work_fletcher": "Fletcher works", + "subtitles.entity.villager.work_leatherworker": "Leatherworker works", + "subtitles.entity.villager.work_librarian": "Librarian works", + "subtitles.entity.villager.work_mason": "Mason works", + "subtitles.entity.villager.work_shepherd": "Shepherd works", + "subtitles.entity.villager.work_toolsmith": "Toolsmith works", + "subtitles.entity.villager.work_weaponsmith": "Weaponsmith works", + "subtitles.entity.villager.yes": "Villager agrees", + "subtitles.entity.vindicator.ambient": "Vindicator mutters", + "subtitles.entity.vindicator.celebrate": "Vindicator cheers", + "subtitles.entity.vindicator.death": "Vindicator dies", + "subtitles.entity.vindicator.hurt": "Vindicator hurts", + "subtitles.entity.wandering_trader.ambient": "Wandering Trader mumbles", + "subtitles.entity.wandering_trader.death": "Wandering Trader dies", + "subtitles.entity.wandering_trader.disappeared": "Wandering Trader disappears", + "subtitles.entity.wandering_trader.drink_milk": "Wandering Trader drinks milk", + "subtitles.entity.wandering_trader.drink_potion": "Wandering Trader drinks potion", + "subtitles.entity.wandering_trader.hurt": "Wandering Trader hurts", + "subtitles.entity.wandering_trader.no": "Wandering Trader disagrees", + "subtitles.entity.wandering_trader.reappeared": "Wandering Trader appears", + "subtitles.entity.wandering_trader.trade": "Wandering Trader trades", + "subtitles.entity.wandering_trader.yes": "Wandering Trader agrees", + "subtitles.entity.warden.agitated": "Warden groans angrily", + "subtitles.entity.warden.ambient": "Warden whines", + "subtitles.entity.warden.angry": "Warden rages", + "subtitles.entity.warden.attack_impact": "Warden lands hit", + "subtitles.entity.warden.death": "Warden dies", + "subtitles.entity.warden.dig": "Warden digs", + "subtitles.entity.warden.emerge": "Warden emerges", + "subtitles.entity.warden.heartbeat": "Warden's heart beats", + "subtitles.entity.warden.hurt": "Warden hurts", + "subtitles.entity.warden.listening": "Warden takes notice", + "subtitles.entity.warden.listening_angry": "Warden takes notice angrily", + "subtitles.entity.warden.nearby_close": "Warden approaches", + "subtitles.entity.warden.nearby_closer": "Warden advances", + "subtitles.entity.warden.nearby_closest": "Warden draws close", + "subtitles.entity.warden.roar": "Warden roars", + "subtitles.entity.warden.sniff": "Warden sniffs", + "subtitles.entity.warden.sonic_boom": "Warden booms", + "subtitles.entity.warden.sonic_charge": "Warden charges", + "subtitles.entity.warden.step": "Warden steps", + "subtitles.entity.warden.tendril_clicks": "Warden's tendrils click", + "subtitles.entity.wind_charge.throw": "Wind Charge flies", + "subtitles.entity.wind_charge.wind_burst": "Wind Charge bursts", + "subtitles.entity.witch.ambient": "Witch giggles", + "subtitles.entity.witch.celebrate": "Witch cheers", + "subtitles.entity.witch.death": "Witch dies", + "subtitles.entity.witch.drink": "Witch drinks", + "subtitles.entity.witch.hurt": "Witch hurts", + "subtitles.entity.witch.throw": "Witch throws", + "subtitles.entity.wither_skeleton.ambient": "Wither Skeleton rattles", + "subtitles.entity.wither_skeleton.death": "Wither Skeleton dies", + "subtitles.entity.wither_skeleton.hurt": "Wither Skeleton hurts", + "subtitles.entity.wither.ambient": "Wither angers", + "subtitles.entity.wither.death": "Wither dies", + "subtitles.entity.wither.hurt": "Wither hurts", + "subtitles.entity.wither.shoot": "Wither attacks", + "subtitles.entity.wither.spawn": "Wither released", + "subtitles.entity.wolf.ambient": "Wolf pants", + "subtitles.entity.wolf.death": "Wolf dies", + "subtitles.entity.wolf.growl": "Wolf growls", + "subtitles.entity.wolf.hurt": "Wolf hurts", + "subtitles.entity.wolf.shake": "Wolf shakes", + "subtitles.entity.zoglin.ambient": "Zoglin growls", + "subtitles.entity.zoglin.angry": "Zoglin growls angrily", + "subtitles.entity.zoglin.attack": "Zoglin attacks", + "subtitles.entity.zoglin.death": "Zoglin dies", + "subtitles.entity.zoglin.hurt": "Zoglin hurts", + "subtitles.entity.zoglin.step": "Zoglin steps", + "subtitles.entity.zombie_horse.ambient": "Zombie Horse cries", + "subtitles.entity.zombie_horse.death": "Zombie Horse dies", + "subtitles.entity.zombie_horse.hurt": "Zombie Horse hurts", + "subtitles.entity.zombie_villager.ambient": "Zombie Villager groans", + "subtitles.entity.zombie_villager.converted": "Zombie Villager vociferates", + "subtitles.entity.zombie_villager.cure": "Zombie Villager snuffles", + "subtitles.entity.zombie_villager.death": "Zombie Villager dies", + "subtitles.entity.zombie_villager.hurt": "Zombie Villager hurts", + "subtitles.entity.zombie.ambient": "Zombie groans", + "subtitles.entity.zombie.attack_wooden_door": "Door shakes", + "subtitles.entity.zombie.break_wooden_door": "Door breaks", + "subtitles.entity.zombie.converted_to_drowned": "Zombie converts to Drowned", + "subtitles.entity.zombie.death": "Zombie dies", + "subtitles.entity.zombie.destroy_egg": "Turtle Egg stomped", + "subtitles.entity.zombie.hurt": "Zombie hurts", + "subtitles.entity.zombie.infect": "Zombie infects", + "subtitles.entity.zombified_piglin.ambient": "Zombified Piglin grunts", + "subtitles.entity.zombified_piglin.angry": "Zombified Piglin grunts angrily", + "subtitles.entity.zombified_piglin.death": "Zombified Piglin dies", + "subtitles.entity.zombified_piglin.hurt": "Zombified Piglin hurts", + "subtitles.event.mob_effect.bad_omen": "Omen takes hold", + "subtitles.event.mob_effect.raid_omen": "Raid looms nearby", + "subtitles.event.mob_effect.trial_omen": "Ominous trial looms nearby", + "subtitles.event.raid.horn": "Ominous horn blares", + "subtitles.item.armor.equip": "Gear equips", + "subtitles.item.armor.equip_chain": "Chain armor jingles", + "subtitles.item.armor.equip_diamond": "Diamond armor clangs", + "subtitles.item.armor.equip_elytra": "Elytra rustle", + "subtitles.item.armor.equip_gold": "Gold armor clinks", + "subtitles.item.armor.equip_iron": "Iron armor clanks", + "subtitles.item.armor.equip_leather": "Leather armor rustles", + "subtitles.item.armor.equip_netherite": "Netherite armor clanks", + "subtitles.item.armor.equip_turtle": "Turtle Shell thunks", + "subtitles.item.armor.equip_wolf": "Wolf Armor is fastened", + "subtitles.item.armor.unequip_wolf": "Wolf Armor snips away", + "subtitles.item.axe.scrape": "Axe scrapes", + "subtitles.item.axe.strip": "Axe strips", + "subtitles.item.axe.wax_off": "Wax off", + "subtitles.item.bone_meal.use": "Bone Meal crinkles", + "subtitles.item.book.page_turn": "Page rustles", + "subtitles.item.book.put": "Book thumps", + "subtitles.item.bottle.empty": "Bottle empties", + "subtitles.item.bottle.fill": "Bottle fills", + "subtitles.item.brush.brushing.generic": "Brushing", + "subtitles.item.brush.brushing.gravel": "Brushing Gravel", + "subtitles.item.brush.brushing.gravel.complete": "Brushing Gravel completed", + "subtitles.item.brush.brushing.sand": "Brushing Sand", + "subtitles.item.brush.brushing.sand.complete": "Brushing Sand completed", + "subtitles.item.bucket.empty": "Bucket empties", + "subtitles.item.bucket.fill": "Bucket fills", + "subtitles.item.bucket.fill_axolotl": "Axolotl scooped", + "subtitles.item.bucket.fill_fish": "Fish captured", + "subtitles.item.bucket.fill_tadpole": "Tadpole captured", + "subtitles.item.bundle.drop_contents": "Bundle empties", + "subtitles.item.bundle.insert": "Item packed", + "subtitles.item.bundle.remove_one": "Item unpacked", + "subtitles.item.chorus_fruit.teleport": "Player teleports", + "subtitles.item.crop.plant": "Crop planted", + "subtitles.item.crossbow.charge": "Crossbow charges up", + "subtitles.item.crossbow.hit": "Arrow hits", + "subtitles.item.crossbow.load": "Crossbow loads", + "subtitles.item.crossbow.shoot": "Crossbow fires", + "subtitles.item.dye.use": "Dye stains", + "subtitles.item.firecharge.use": "Fireball whooshes", + "subtitles.item.flintandsteel.use": "Flint and Steel click", + "subtitles.item.glow_ink_sac.use": "Glow Ink Sac splotches", + "subtitles.item.goat_horn.play": "Goat Horn plays", + "subtitles.item.hoe.till": "Hoe tills", + "subtitles.item.honey_bottle.drink": "Gulping", + "subtitles.item.honeycomb.wax_on": "Wax on", + "subtitles.item.ink_sac.use": "Ink Sac splotches", + "subtitles.item.lodestone_compass.lock": "Lodestone Compass locks onto Lodestone", + "subtitles.item.mace.smash_air": "Mace smashes", + "subtitles.item.mace.smash_ground": "Mace smashes", + "subtitles.item.nether_wart.plant": "Crop planted", + "subtitles.item.ominous_bottle.dispose": "Bottle breaks", + "subtitles.item.shears.shear": "Shears click", + "subtitles.item.shield.block": "Shield blocks", + "subtitles.item.shovel.flatten": "Shovel flattens", + "subtitles.item.spyglass.stop_using": "Spyglass retracts", + "subtitles.item.spyglass.use": "Spyglass expands", + "subtitles.item.totem.use": "Totem activates", + "subtitles.item.trident.hit": "Trident stabs", + "subtitles.item.trident.hit_ground": "Trident vibrates", + "subtitles.item.trident.return": "Trident returns", + "subtitles.item.trident.riptide": "Trident zooms", + "subtitles.item.trident.throw": "Trident clangs", + "subtitles.item.trident.thunder": "Trident thunder cracks", + "subtitles.item.wolf_armor.break": "Wolf Armor breaks", + "subtitles.item.wolf_armor.crack": "Wolf Armor cracks", + "subtitles.item.wolf_armor.damage": "Wolf Armor takes damage", + "subtitles.item.wolf_armor.repair": "Wolf Armor is repaired", + "subtitles.particle.soul_escape": "Soul escapes", + "subtitles.ui.cartography_table.take_result": "Map drawn", + "subtitles.ui.loom.take_result": "Loom used", + "subtitles.ui.stonecutter.take_result": "Stonecutter used", + "subtitles.weather.rain": "Rain falls", + "symlink_warning.message": "Loading worlds from folders with symbolic links can be unsafe if you don't know exactly what you are doing. Please visit %s to learn more.", + "symlink_warning.message.pack": "Loading packs with symbolic links can be unsafe if you don't know exactly what you are doing. Please visit %s to learn more.", + "symlink_warning.message.world": "Loading worlds from folders with symbolic links can be unsafe if you don't know exactly what you are doing. Please visit %s to learn more.", + "symlink_warning.more_info": "More Information", + "symlink_warning.title": "World folder contains symbolic links", + "symlink_warning.title.pack": "Added pack(s) contain(s) symbolic links", + "symlink_warning.title.world": "The world folder contains symbolic links", + "team.collision.always": "Always", + "team.collision.never": "Never", + "team.collision.pushOtherTeams": "Push other teams", + "team.collision.pushOwnTeam": "Push own team", + "team.notFound": "Unknown team '%s'", + "team.visibility.always": "Always", + "team.visibility.hideForOtherTeams": "Hide for other teams", + "team.visibility.hideForOwnTeam": "Hide for own team", + "team.visibility.never": "Never", + "telemetry_info.button.give_feedback": "Give Feedback", + "telemetry_info.button.privacy_statement": "Privacy Statement", + "telemetry_info.button.show_data": "View My Data", + "telemetry_info.opt_in.description": "I consent to sending optional telemetry data", + "telemetry_info.property_title": "Included Data", + "telemetry_info.screen.description": "Collecting this data helps us improve Minecraft by guiding us in directions that are relevant to our players.\nYou can also send in additional feedback to help us keep improving Minecraft.", + "telemetry_info.screen.title": "Telemetry Data Collection", + "telemetry.event.advancement_made.description": "Understanding the context behind receiving an advancement can help us better understand and improve the progression of the game.", + "telemetry.event.advancement_made.title": "Advancement Made", + "telemetry.event.game_load_times.description": "This event can help us figure out where startup performance improvements are needed by measuring the execution times of the startup phases.", + "telemetry.event.game_load_times.title": "Game Load Times", + "telemetry.event.optional": "%s (Optional)", + "telemetry.event.optional.disabled": "%s (Optional) - Disabled", + "telemetry.event.performance_metrics.description": "Knowing the overall performance profile of Minecraft helps us tune and optimize the game for a wide range of machine specifications and operating systems. \nGame version is included to help us compare the performance profile for new versions of Minecraft.", + "telemetry.event.performance_metrics.title": "Performance Metrics", + "telemetry.event.required": "%s (Required)", + "telemetry.event.world_load_times.description": "It’s important for us to understand how long it takes to join a world, and how that changes over time. For example, when we add new features or do larger technical changes, we need to see what impact that had on load times.", + "telemetry.event.world_load_times.title": "World Load Times", + "telemetry.event.world_loaded.description": "Knowing how players play Minecraft (such as Game Mode, client or server modded, and game version) allows us to focus game updates to improve the areas that players care about most.\nThe World Loaded event is paired with the World Unloaded event to calculate how long the play session has lasted.", + "telemetry.event.world_loaded.title": "World Loaded", + "telemetry.event.world_unloaded.description": "This event is paired with the World Loaded event to calculate how long the world session has lasted.\nThe duration (in seconds and ticks) is measured when a world session has ended (quitting to title, disconnecting from a server).", + "telemetry.event.world_unloaded.title": "World Unloaded", + "telemetry.property.advancement_game_time.title": "Game Time (Ticks)", + "telemetry.property.advancement_id.title": "Advancement ID", + "telemetry.property.client_id.title": "Client ID", + "telemetry.property.client_modded.title": "Client Modded", + "telemetry.property.dedicated_memory_kb.title": "Dedicated Memory (kB)", + "telemetry.property.event_timestamp_utc.title": "Event Timestamp (UTC)", + "telemetry.property.frame_rate_samples.title": "Frame Rate Samples (FPS)", + "telemetry.property.game_mode.title": "Game Mode", + "telemetry.property.game_version.title": "Game Version", + "telemetry.property.launcher_name.title": "Launcher Name", + "telemetry.property.load_time_bootstrap_ms.title": "Bootstrap Time (Milliseconds)", + "telemetry.property.load_time_loading_overlay_ms.title": "Time in Loading Screen (Milliseconds)", + "telemetry.property.load_time_pre_window_ms.title": "Time Before Window Opens (Milliseconds)", + "telemetry.property.load_time_total_time_ms.title": "Total Load Time (Milliseconds)", + "telemetry.property.minecraft_session_id.title": "Minecraft Session ID", + "telemetry.property.new_world.title": "New World", + "telemetry.property.number_of_samples.title": "Sample Count", + "telemetry.property.operating_system.title": "Operating System", + "telemetry.property.opt_in.title": "Opt-In", + "telemetry.property.platform.title": "Platform", + "telemetry.property.realms_map_content.title": "Realms Map Content (Minigame Name)", + "telemetry.property.render_distance.title": "Render Distance", + "telemetry.property.render_time_samples.title": "Render Time Samples", + "telemetry.property.seconds_since_load.title": "Time Since Load (Seconds)", + "telemetry.property.server_modded.title": "Server Modded", + "telemetry.property.server_type.title": "Server Type", + "telemetry.property.ticks_since_load.title": "Time Since Load (Ticks)", + "telemetry.property.used_memory_samples.title": "Used Random Access Memory", + "telemetry.property.user_id.title": "User ID", + "telemetry.property.world_load_time_ms.title": "World Load Time (Milliseconds)", + "telemetry.property.world_session_id.title": "World Session ID", + "title.32bit.deprecation": "32-bit system detected: this may prevent you from playing in the future as a 64-bit system will be required!", + "title.32bit.deprecation.realms": "Minecraft will soon require a 64-bit system, which will prevent you from playing or using Realms on this device. You will need to manually cancel any Realms subscription.", + "title.32bit.deprecation.realms.check": "Do not show this screen again", + "title.32bit.deprecation.realms.header": "32-bit system detected", + "title.credits": "Copyright Mojang AB. Do not distribute!", + "title.multiplayer.disabled": "Multiplayer is disabled. Please check your Microsoft account settings.", + "title.multiplayer.disabled.banned.name": "You must change your name before you can play online", + "title.multiplayer.disabled.banned.permanent": "Your account is permanently suspended from online play", + "title.multiplayer.disabled.banned.temporary": "Your account is temporarily suspended from online play", + "title.multiplayer.lan": "Multiplayer (LAN)", + "title.multiplayer.other": "Multiplayer (3rd-party Server)", + "title.multiplayer.realms": "Multiplayer (Realms)", + "title.singleplayer": "Singleplayer", + "translation.test.args": "%s %s", + "translation.test.complex": "Prefix, %s%2$s again %s and %1$s lastly %s and also %1$s again!", + "translation.test.escape": "%%s %%%s %%%%s %%%%%s", + "translation.test.invalid": "hi %", + "translation.test.invalid2": "hi % s", + "translation.test.none": "Hello, world!", + "translation.test.world": "world", + "trim_material.minecraft.amethyst": "Amethyst Material", + "trim_material.minecraft.copper": "Copper Material", + "trim_material.minecraft.diamond": "Diamond Material", + "trim_material.minecraft.emerald": "Emerald Material", + "trim_material.minecraft.gold": "Gold Material", + "trim_material.minecraft.iron": "Iron Material", + "trim_material.minecraft.lapis": "Lapis Material", + "trim_material.minecraft.netherite": "Netherite Material", + "trim_material.minecraft.quartz": "Quartz Material", + "trim_material.minecraft.redstone": "Redstone Material", + "trim_pattern.minecraft.bolt": "Bolt Armor Trim", + "trim_pattern.minecraft.coast": "Coast Armor Trim", + "trim_pattern.minecraft.dune": "Dune Armor Trim", + "trim_pattern.minecraft.eye": "Eye Armor Trim", + "trim_pattern.minecraft.flow": "Flow Armor Trim", + "trim_pattern.minecraft.host": "Host Armor Trim", + "trim_pattern.minecraft.raiser": "Raiser Armor Trim", + "trim_pattern.minecraft.rib": "Rib Armor Trim", + "trim_pattern.minecraft.sentry": "Sentry Armor Trim", + "trim_pattern.minecraft.shaper": "Shaper Armor Trim", + "trim_pattern.minecraft.silence": "Silence Armor Trim", + "trim_pattern.minecraft.snout": "Snout Armor Trim", + "trim_pattern.minecraft.spire": "Spire Armor Trim", + "trim_pattern.minecraft.tide": "Tide Armor Trim", + "trim_pattern.minecraft.vex": "Vex Armor Trim", + "trim_pattern.minecraft.ward": "Ward Armor Trim", + "trim_pattern.minecraft.wayfinder": "Wayfinder Armor Trim", + "trim_pattern.minecraft.wild": "Wild Armor Trim", + "tutorial.bundleInsert.description": "Right Click to add items", + "tutorial.bundleInsert.title": "Use a Bundle", + "tutorial.craft_planks.description": "The recipe book can help", + "tutorial.craft_planks.title": "Craft wooden planks", + "tutorial.find_tree.description": "Punch it to collect wood", + "tutorial.find_tree.title": "Find a tree", + "tutorial.look.description": "Use your mouse to turn", + "tutorial.look.title": "Look around", + "tutorial.move.description": "Jump with %s", + "tutorial.move.title": "Move with %s, %s, %s and %s", + "tutorial.open_inventory.description": "Press %s", + "tutorial.open_inventory.title": "Open your inventory", + "tutorial.punch_tree.description": "Hold down %s", + "tutorial.punch_tree.title": "Destroy the tree", + "tutorial.socialInteractions.description": "Press %s to open", + "tutorial.socialInteractions.title": "Social Interactions", + "upgrade.minecraft.netherite_upgrade": "Netherite Upgrade" +} diff --git a/src/main/java/io/github/sakurawald/config/annotation/Comment.java b/src/main/java/io/github/sakurawald/config/annotation/Comment.java index 95e272c91..df15f15ca 100644 --- a/src/main/java/io/github/sakurawald/config/annotation/Comment.java +++ b/src/main/java/io/github/sakurawald/config/annotation/Comment.java @@ -3,7 +3,7 @@ import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) +@Target({ElementType.TYPE, ElementType.FIELD}) public @interface Comment { String value(); } \ No newline at end of file diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index 217669ba4..74bbe493f 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -5,6 +5,7 @@ import io.github.sakurawald.config.annotation.Comment; import io.github.sakurawald.module.initializer.command_alias.CommandAliasEntry; import io.github.sakurawald.module.initializer.command_rewrite.CommandRewriteEntry; +import net.minecraft.enchantment.Enchantment; import java.util.ArrayList; import java.util.HashMap; @@ -12,25 +13,55 @@ import java.util.Map; @SuppressWarnings("ALL") +@Comment(""" + Welcome to fuji-fabric 's offical documentation. + This page is the `source code` used to generate the default `config.json` file. + + You can press `CTRL + F` keys in your keyboard, and search any `option key` that you want to konw. + + All the text inside `@Comment` are the documentation text, which describe the following field. + """) public class ConfigModel { - @Comment("Global settings for fuji") public Common common = new Common(); - @Comment("A module means a standalone unit to provide a purpose.") public Modules modules = new Modules(); + @Comment(""" + Common options for fuji, which influce all modules. + """) public class Common { - @Comment("Fuji use quartz library as scheduler") public Quartz quartz = new Quartz(); + @Comment(""" + Fuji use quartz library as scheduler, all the timer are managed by quartz. + You can use quartz language to define when to trigger a job. + See: https://www.freeformatter.com/cron-expression-generator-quartz.html + """) public class Quartz { - @Comment("OFF/FATAL/ERROR/WARN/INFO/DEBUG/TRACE/ALL") + @Comment(""" + The fuji logger level. + Options: OFF/FATAL/ERROR/WARN/INFO/DEBUG/TRACE/ALL + + Set to `OFF` to supress all the messages from fuji. + Set to `ALL` to display all the messages from fuji. + """) public String logger_level = "WARN"; } } + @Comment(""" + A module means a standalone unit to provide a purpose. + + All the module can work standalone, you can enable or disable any modules if you like. + + Some modules can work together to achive more purpose. + e.g. A module can provides some placeholders for other modules to use. + + The following fields are used to define the structure of the configuration. + Go ahead, scroll the page down, and see more... + """) public class Modules { public ResourceWorld resource_world = new ResourceWorld(); public NewbieWelcome newbie_welcome = new NewbieWelcome(); @@ -87,16 +118,29 @@ public class Modules { public GrindStone grindstone = new GrindStone(); public StoneCutter stonecutter = new StoneCutter(); + @Comment(""" + This module adds another 3 worlds called `resource world`: resrouce_overworld, resource_nether, resource_the_end . + + Use-case: you have 3 permanent-world which is boundary-limited, and you want to provides infinite + resource for the newbie players, then you can use `resource world` while keeping the permanent-world. + """) public class ResourceWorld { public boolean enable = false; - - @Comment("What dimension type of resource worlds do you want ?") public ResourceWorlds resource_worlds = new ResourceWorlds(); + @Comment("When to auto reset resource worlds") public String auto_reset_cron = "0 0 20 * * ?"; - @Comment("The seed for overworld, also for the_nether and the_end") + + @Comment(""" + The seed for resource worlds: overworld, the_nether and the_end. + + You don't need to input this field, since the `seed` field will randomly generated and write every time resource worlds gets reset. + """) public long seed = 0L; + @Comment(""" + What dimension type of resource worlds do you want to add? + """) public class ResourceWorlds { public boolean enable_overworld = true; public boolean enable_the_nether = true; @@ -105,9 +149,15 @@ public class ResourceWorlds { } + @Comment(""" + This module customs your MOTD in server-list. + """) public class MOTD { public boolean enable = false; - @Comment("Fuji will randomly pick a motd each time the player refresh server list.") + + @Comment(""" + Fuji will randomly pick a motd each time the player refresh server list. + """) public List descriptions = new ArrayList<>() { { this.add("Pure Survival %version% / Up %uptime%H ❤ Discord Group PyzU7Q6unb%playtime%\uD83D\uDD25 %mined%⛏ %placed%\uD83D\uDD33 %killed%\uD83D\uDDE1 %moved%\uD83C\uDF0D"); @@ -115,11 +165,15 @@ public class MOTD { }; } + @Comment(""" + This module provides some jobs to trigger when a player is the first time to join the server. + """) public class NewbieWelcome { public boolean enable = false; - @Comment("Random teleport the newbie player, and set his bed location") + public RandomTeleport random_teleport = new RandomTeleport(); + @Comment("Random teleport the newbie player, and set his bed location.") public class RandomTeleport { public int max_try_times = 32; public int min_distance = 5000; @@ -127,45 +181,93 @@ public class RandomTeleport { } } + @Comment(""" + This module adds a warmup cooldown before player-teleporatation. + + The teleporatation will be cancelled if: + 1. the player runs to far. + 2. the player gets damage. + + """) public class TeleportWarmup { public boolean enable = false; - @Comment("The second to wait before the teleporation") + + @Comment("The second to wait before the teleportation.") public int warmup_second = 3; - @Comment("How far should we cancel the teleporatino") + + @Comment("How far should we cancel the teleportation.") public double interrupt_distance = 1d; } + @Comment(""" + Enable this module requires `carpet-fabric` mod installed. + + This module provides some management for `fake-player` and `/player` command. + """) public class FakePlayerManager { public boolean enable = false; - @Comment("How many fake-player can each player spawn? The tuple means (day_of_week, minutes_of_the_day, max_fake_player_per_player)." + - "The range of day_of_week is [1,7]. " + - "The range of minutes_of_the_day is [0, 1440]. " + - "For example: (1, 0, 2) means if the days_of_week >= 1, and minutes_of_the_day >= 0, then the max_fake_player_per_player now is 2." - + "Besides, you can add multi rules, the rules are check from up to down, and the first rule that matches current time will be used to decide the max_fake_player_per_player." - ) + @Comment(""" + How many fake-player can each player spawn (in different time)? + + The tuple means (day_of_week, minutes_of_the_day, max_fake_player_per_player). + The range of day_of_week is [1,7]. + The range of minutes_of_the_day is [0, 1440]. + + For example: (1, 0, 2) means if the days_of_week >= 1, and minutes_of_the_day >= 0, then the max_fake_player_per_player now is 2. + + Besides, you can add multi rules, the rules are checked from up to down. + The first rule that matches current time will be used to decide the max_fake_player_per_player. + """) public ArrayList> caps_limit_rule = new ArrayList<>() { { this.add(List.of(1, 0, 2)); } }; - @Comment("How long should we renew when issue /player renew") + @Comment(""" + How long should we renew when a player issue command `/player renew` + + The command `/player renew` allows the player to manually renew all of his `fake-player`. + + If a fake-player don't gets renew, then it will expired and get killed. + """) public int renew_duration_ms = 1000 * 60 * 60 * 12; - @Comment("Use to add prefix or suffix for fake-player") + + @Comment(""" + The rule to transform the name of fake-player. + + Use-case: add prefix or suffix for fake-player. + """) public String transform_name = "_fake_%name%"; - @Comment("Should we use local skin for fake-player? Enable this can prevent fetching skins from mojang official server each time the fake-player is spawned. This is mainly used in some network siatuation if your network to mojang official server is bad.") + + @Comment(""" + Should we use local skin for fake-player? + + Enable this can prevent fetching skins from mojang official server each time the fake-player is spawned. + This is mainly used in some network siatuation if your network to mojang official server is bad. + """) public boolean use_local_random_skins_for_fake_player = true; } + @Comment(""" + Adds nbt query and entity query for carpet command `/info`. + """) public class BetterInfo { - @Comment("Adds nbt query for carpet command /info, and adds entity query for /info") public boolean enable = false; } + @Comment(""" + This module provides a cooldown before each command the player issued. + """) public class CommandCooldown { public boolean enable = false; - @Comment("Use regex language to define issued command cooldown. The cooldown for each command is per-player, no globally.") + + @Comment(""" + Use `regex language` to define issued command cooldown. + + For each player, each command has its cooldown. + """) public HashMap command_regex_2_cooldown_ms = new HashMap<>() { { this.put("rw tp (overworld|the_nether|the_end)", 120 * 1000L); @@ -175,17 +277,36 @@ public class CommandCooldown { }; } + @Comment(""" + This module provides the `/chunks` command, which shows the `top laggy chunks` in the server. + + The output is a score list, each score means a chunk, and how laggy the chunk is. (Large score means more laggy) + """) public class TopChunks { public boolean enable = false; public int rows = 10; public int columns = 10; - @Comment("For a chunk, how far should we use as radius to search the nearest player around the chunk.") + + @Comment("For a chunk, how much the radius used to search `the nearest player` around the chunk.") public int nearest_distance = 128; - @Comment("Should we hide the chunk-position for a laggy-chunk?") + @Comment(""" + Should we hide the chunk-position for a laggy-chunk? + + Hide chunk location to avoid grief or privacy purpose. + """) public boolean hide_location = true; - @Comment("The dict to define how laggy a type(entity/entity_block) should be.") + + @Comment(""" + The dict to define how laggy a type(entity/entity_block) should be. + + For example, + `this.put("entity.minecraft.zombie", 4);` means there are 15 zombies inside a chunk, + then the chunk gets score 15 * 4 = 60 + + Any other types not inside the dict used the score defined for type `default` + """) public HashMap type2score = new HashMap<>() { { this.put("default", 1); @@ -248,13 +369,22 @@ public class TopChunks { }; } + @Comment(""" + This module provides chat custom. + """) public class Chat { public boolean enable = false; - @Comment("The server chat format") + + @Comment(""" + The server chat format for all players. + + You can use `minimessage language` to define complex format. + See: https://docs.advntr.dev/minimessage/format.html + + """) public String format = "<#B1B2FF>[%playtime%\uD83D\uDD25 %mined%⛏ %placed%\uD83D\uDD33 %killed%\uD83D\uDDE1 %moved%\uD83C\uDF0D] <Click to Message\">%player%> %message%"; public MentionPlayer mention_player = new MentionPlayer(); - public History history = new History(); public Display display = new Display(); @@ -263,6 +393,9 @@ public class History { public int cache_size = 50; } + @Comment(""" + If you insert `@Steve` in chat message, then the player named `Steve` will get audio mention. + """) public class MentionPlayer { public String sound = "entity.experience_orb.pickup"; public float volume = 100f; @@ -271,21 +404,30 @@ public class MentionPlayer { public int interval_ms = 1000; } + @Comment(""" + You can insert `item`, `inv` and `ender` in message to display something with other players. + """) public class Display { - @Comment("For a display data, how long should we save in the memory. Note that if a player shares its inventory items, then fuji will save a copy of his inventory data in the memory.") + @Comment(""" + For each display data, how long should we save in the memory. + Note that if a player shares its inventory items, then fuji will save a copy of his inventory data in the memory. + """) public int expiration_duration_s = 3600; } } + @Comment(""" + This module provides player skin management. + """) public class Skin { public boolean enable = false; - @Comment("The default server skin for player who has no skin set.") + @Comment("The `default skin` used for player who has no skin set.") public Property default_skin = new Property("textures", "eyJ0aW1lc3RhbXAiOjE1ODYzMjc4ODA1NjYsInByb2ZpbGVJZCI6ImI3MzY3YzA2MjYxYzRlYjBiN2Y3OGY3YzUxNzBiNzQ4IiwicHJvZmlsZU5hbWUiOiJFbXB0eUlyb255Iiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS84NWZmZjI1ZDY2NzIwNmYyZTQ2ZDQ0MmNmMzU4YjNmMWVjMzYxMzgzOTE3NTFiYTZlZGY5NjVmZmM4M2I4NjAzIiwibWV0YWRhdGEiOnsibW9kZWwiOiJzbGltIn19fX0=", "PoUf4TsNx6SVHTWZJ6Iwk3acWyiDk84VeKBVcOeqimaSBAGYKfeuXRTFV8c9IBE9cjsRAVaTGC/mwRfHlcD/rmxeDDOkhsFVidr8UL+91afIO8d+EnyoBghmnbZonqpcjCv+nkxQ5SP93qTDelD3jd8xF1FAU97BBvrx0yK+QNn5rPg2RUGGoUZUg75KlEJds1dNftpHc8IyAHz/FQIywlkohu26ghOqFStjok4WPHD3ok0z7Kwcjk7u58PYf67TkEGnGbmxTUDlNbLmxUqjxCr4NshS+e3y3jRfJN0nP82dbYh/NP2Fx8m7pSMsQtm/Ta2MN7JC0Pm2yvZB/APNoNHVSZZ2SOITbPF/yAkIdHrk+ieCKqDbeuc8TFs2n+6FktYdwPXcqrK266CzlSTPycVZQeyrgrOI+fqU1HwCz+MgdlcsAdAoyuFlFPaVqDesI46YPsSJzA3C3CNhjvuebOn357U9Po82eSFAPYbtBPVNjiNgiqn5l+1x8ZVHImwpGv/toa5/fUyfMmlxijwG/C9gQ4mE+buutMn9nfE1y/AisU/2DWeFBESw3eRAICcmVVi875N8kT+Wja8WsbpDCw+pV2wZC3x3nEdOceAdXtDEb0oy3bQPW3TSZ+Wnp68qwSxjI/aDosqVuyyqqlm+w/irUmNHGL+t7g/kD932g0Q="); - @Comment("Random skin for fake-player, if you enable the local skin for fake-player. See: BetterFakePlayerModule") + @Comment("Random skin for fake-player, if you enable the local skin for fake-player. See: FakePlayerManagerModule") public ArrayList random_skins = new ArrayList<>() { { this.add(new Property("textures", "eyJ0aW1lc3RhbXAiOjE1ODYzMjc4ODA1NjYsInByb2ZpbGVJZCI6ImI3MzY3YzA2MjYxYzRlYjBiN2Y3OGY3YzUxNzBiNzQ4IiwicHJvZmlsZU5hbWUiOiJFbXB0eUlyb255Iiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS84NWZmZjI1ZDY2NzIwNmYyZTQ2ZDQ0MmNmMzU4YjNmMWVjMzYxMzgzOTE3NTFiYTZlZGY5NjVmZmM4M2I4NjAzIiwibWV0YWRhdGEiOnsibW9kZWwiOiJzbGltIn19fX0=", "PoUf4TsNx6SVHTWZJ6Iwk3acWyiDk84VeKBVcOeqimaSBAGYKfeuXRTFV8c9IBE9cjsRAVaTGC/mwRfHlcD/rmxeDDOkhsFVidr8UL+91afIO8d+EnyoBghmnbZonqpcjCv+nkxQ5SP93qTDelD3jd8xF1FAU97BBvrx0yK+QNn5rPg2RUGGoUZUg75KlEJds1dNftpHc8IyAHz/FQIywlkohu26ghOqFStjok4WPHD3ok0z7Kwcjk7u58PYf67TkEGnGbmxTUDlNbLmxUqjxCr4NshS+e3y3jRfJN0nP82dbYh/NP2Fx8m7pSMsQtm/Ta2MN7JC0Pm2yvZB/APNoNHVSZZ2SOITbPF/yAkIdHrk+ieCKqDbeuc8TFs2n+6FktYdwPXcqrK266CzlSTPycVZQeyrgrOI+fqU1HwCz+MgdlcsAdAoyuFlFPaVqDesI46YPsSJzA3C3CNhjvuebOn357U9Po82eSFAPYbtBPVNjiNgiqn5l+1x8ZVHImwpGv/toa5/fUyfMmlxijwG/C9gQ4mE+buutMn9nfE1y/AisU/2DWeFBESw3eRAICcmVVi875N8kT+Wja8WsbpDCw+pV2wZC3x3nEdOceAdXtDEb0oy3bQPW3TSZ+Wnp68qwSxjI/aDosqVuyyqqlm+w/irUmNHGL+t7g/kD932g0Q=")); @@ -297,19 +439,36 @@ public class Skin { }; } + @Comment(""" + This module provides `/back` command. + """) public class Back { public boolean enable = false; - @Comment("If the player's teleporation destination is close enough, we ignore this teleporation.") + + @Comment("If the player's teleportation destination is close enough, we ignore this telepotation.") public double ignore_distance = 32d; } + @Comment(""" + This module provides `/tpa`, `/tpahere`, `/tpaacept` and `/tpadeny` commands. + """) public class Tpa { public boolean enable = false; + @Comment("Tpa request expiration duration. unit is second") public int timeout = 300; } + @Comment(""" + This module provides `/work` command. + + A `work` means a project (a building, a red-stone device ...) that crafted by a player. + + All `work` types: + 1. Non-production work: the project don't produce any resource (e.g. bone, string, coal). + 2. Production work: the project produce some resource. + """) public class Works { public boolean enable = false; @@ -321,13 +480,25 @@ public class Works { public int sample_counter_top_n = 20; } + @Comment(""" + This module provides `/download` command. + + This command allows to downlaod nearby chunks around a player. + + Use-case: if a player wants to download his buildings, or just want to download the redstone-structure + so that he can debug in his single-player world. + """) public class WorldDownloader { public boolean enable = false; + @Comment("The url format used to broadcast") public String url_format = "http://example.com:%port%%path%"; + public int port = 22222; + @Comment("Max download speed limit for each connection.") public int bytes_per_second_limit = 128 * 1000; + @Comment("Max download request allowed in the memory at the same time.") public int context_cache_size = 5; } @@ -336,28 +507,46 @@ public class BypassChatSpeed { public boolean enable = false; } + @Comment("Disable `moved too quickly` and `vehicle too quickly` check") public class BypassMoveSpeed { - @Comment("Disable `moved too quickly` and `vehicle too quickly` check") public boolean enable = false; } + @Comment(""" + Bypass the max players limit of the server. + """) public class BypassMaxPlayerLimit { public boolean enable = false; } + @Comment(""" + This module provides `/deathlog` command. + + Log player's inventory when he die, so that we can restore his inventory later. + + """) public class DeathLog { - @Comment("Log player's inventory when he's death, so that we can restore his inventory later.") public boolean enable = false; } + @Comment(""" + This module provides some useful stats, you can use the stats placeholder with ChatModule and MotdModule + """) public class MainStats { - @Comment("Adds some useful stats, you can use the stats placeholder with ChatModule and MotdModule") public boolean enable = false; } + @Comment(""" + In vanilla minecraft, each `ender-portal` links to `the only one obsidian platform`. + This module makes each `ender-portal` links to its own `obsidian platform`. + + Use-case: you want more `obsidian platform` for your redstone-struture. + """) public class MultiObsidianPlatform { public boolean enable = false; - @Comment("The coordination-convertion factor between overworld and the_end. In vanilla minecraft, the factor between overworld and the_nether is 8.") + @Comment(""" + The coordination-convertion factor between overworld and the_end. + In vanilla minecraft, the factor between overworld and the_nether is 8.""") public double factor = 4; } @@ -365,6 +554,9 @@ public class OpProtect { public boolean enable = false; } + @Comment(""" + This module provides `/pvp` command. + """) public class Pvp { public boolean enable = false; } @@ -382,11 +574,19 @@ public class CommandPermission { public boolean enable = false; } + @Comment(""" + This module provides `/head` command, so that players can buy custom-head. + """) public class Head { public boolean enable = false; } + @Comment(""" + Enable this module requires `spark` mod installed. + + This module provides `/profiler` command. + """) public class Profiler { public boolean enable = false; @@ -396,10 +596,15 @@ public class CommandSpy { public boolean enable = false; } + @Comment(""" + This module provides scheduler for auto-run jobs, and `/schudler_trigger` command. + + """) public class Scheduler { public boolean enable = false; } + @Comment("This module provides `/fuji reload` command, so that you can reload modules in game.") public class Config { public boolean enable = false; } @@ -409,26 +614,41 @@ public class Test { public boolean enable = false; } + @Comment("This module provides `/hat` command.") public class Hat { public boolean enable = false; } + @Comment("This module provides `/fly` command.") public class Fly { public boolean enable = false; } + @Comment("This module provides `/god` command.") public class God { public boolean enable = false; } + @Comment(""" + If this module is enabled, then `/fuji reload` command will reload the files inside `/config/fuji/lang`. + """) public class Language { public boolean enable = false; } + @Comment("This module provides `/reply` command.") public class Reply { public boolean enable = false; } + @Comment(""" + This module provides afk detection. + + If a player is idle long enough, he will be marked as afk state. + A afk player will display in `tab list`. + + A player can issue `/afk` command to afk manually. + """) public class Afk { public boolean enable = false; @@ -446,57 +666,83 @@ public class AfkChecker { } } + @Comment("This module provides `/suicide` command.") public class Suicide { public boolean enable = false; } + @Comment(""" + This module allows you to write commands in `sign block`. + + A sign-block contains 4 lines. + You can write commands in the sign-block. + + Each command starts with prefix `//` + e.g. Line 1 contains `Click me //back` will execute the command `/back` + + The placeholder `@u` means the user player name. + e.g. Line 1 contains `//kill @u` will execute the command `/kill {player_name}` + + """) public class CommandInteractive { public boolean enable = false; + @Comment("Should we log the command used by signs into the console ?") public boolean log_use = true; } + @Comment("This module provides `/heal` command.") public class Heal { public boolean enable = false; } + @Comment("This module provides `/feed` command.") public class Feed { public boolean enable = false; } + @Comment("This module provides `/repair` command.") public class Repair { public boolean enable = false; } + @Comment("This module provides `/seen` command.") public class Seen { public boolean enable = false; } + @Comment("This module provides `/more` command.") public class More { public boolean enable = false; } + @Comment("This module provides `/extinguish` command.") public class Extinguish { public boolean enable = false; } + @Comment("This module provides `/home` command.") public class Home { public boolean enable = false; public int max_homes = 3; } + @Comment("This module provides `/ping` command.") public class Ping { public boolean enable = false; } + @Comment(""" + This module allows you to custom every system-message defined by mojang in `./assets/minecraft/lang/en_us.json` + """) public class SystemMessage { public boolean enable = false; - @Comment("The language key in `lang/en_us.json` to hijack.") + @Comment("The language keys to hijack.") public Map key2value = new HashMap<>() { { this.put("multiplayer.player.joined", "+ %s"); @@ -521,10 +767,13 @@ public class Enchantment { @Comment("Should we override the power of proviers for the opened enchant table?") public OverridePower override_power = new OverridePower(); + public class OverridePower { public boolean enable = true; - @Comment("How many power providers for the opened enchant table. For a max level of enchant table, it requires 15 power providers.") + @Comment(""" + How many power providers for the opened enchant table. + For a max level of enchant table, it requires 15 power providers.""") public int power_provider_amount = 15; } @@ -572,13 +821,14 @@ public class CommandAlias { public List alias = new ArrayList<>() { { this.add(new CommandAliasEntry(List.of("r"), List.of("reply"))); - this.add(new CommandAliasEntry(List.of("i", "want", "to","modify","chat"), List.of("chat","format"))); + this.add(new CommandAliasEntry(List.of("i", "want", "to", "modify", "chat"), List.of("chat", "format"))); } }; } public CommandRewrite command_rewrite = new CommandRewrite(); - public class CommandRewrite { + + public class CommandRewrite { public boolean enable = false; public List rules = new ArrayList<>() { { From e2b939372161c49115575d2594020e15e2e87807 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 17:45:10 +0800 Subject: [PATCH 39/50] update: github wiki --- .../sakurawald/config/model/ConfigModel.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index 74bbe493f..570382037 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -738,6 +738,9 @@ public class Ping { @Comment(""" This module allows you to custom every system-message defined by mojang in `./assets/minecraft/lang/en_us.json` + + The mojang offical en_us.json file may looks like: [en_us.json for minecraft 1.21](https://github.com/sakurawald/fuji-fabric/blob/dev/.github/files/en_us.json) + """) public class SystemMessage { public boolean enable = false; @@ -753,14 +756,17 @@ public class SystemMessage { }; } + @Comment("This module provides `/enderchest` command.") public class EnderChest { public boolean enable = false; } + @Comment("This module provides `/workbench` command.") public class Workbench { public boolean enable = false; } + @Comment("This module provides `/enchantment` command.") public class Enchantment { public boolean enable = false; @@ -779,21 +785,25 @@ public class OverridePower { } + @Comment("This module provides `/anvil` command.") public class Anvil { public boolean enable = false; } + @Comment("This module provides `/grindstone` command.") public class GrindStone { public boolean enable = false; } + @Comment("This module provides `/stonecutter` command.") public class StoneCutter { public boolean enable = false; } + @Comment("This module provides `/bed` command, which teleports the player to his bed.") public Bed bed = new Bed(); public class Bed { @@ -801,6 +811,9 @@ public class Bed { public boolean enable = false; } + @Comment(""" + This module provides `/sit` command, and the ability to sit by right-click any chair. + """) public Sit sit = new Sit(); public class Sit { @@ -816,6 +829,12 @@ public class Sit { public CommandAlias command_alias = new CommandAlias(); + @Comment(""" + This module provides command alias. + + An alias means we redirect a command-node into another command-node. + The requirement of comamnd-node is extended. + """) public class CommandAlias { public boolean enable = false; public List alias = new ArrayList<>() { @@ -828,6 +847,9 @@ public class CommandAlias { public CommandRewrite command_rewrite = new CommandRewrite(); + @Comment(""" + This module provides command rewrite, so that you can rewrite the `command line` a player issued. + """) public class CommandRewrite { public boolean enable = false; public List rules = new ArrayList<>() { From e02707d723aa2783190f6c8bac57484dc6411d52 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 17:50:02 +0800 Subject: [PATCH 40/50] update: github wiki --- .../{Comment.java => Documentation.java} | 2 +- .../sakurawald/config/model/ConfigModel.java | 195 +++++++++--------- .../java/BuildConfigurationDocumentTest.java | 14 +- 3 files changed, 105 insertions(+), 106 deletions(-) rename src/main/java/io/github/sakurawald/config/annotation/{Comment.java => Documentation.java} (84%) diff --git a/src/main/java/io/github/sakurawald/config/annotation/Comment.java b/src/main/java/io/github/sakurawald/config/annotation/Documentation.java similarity index 84% rename from src/main/java/io/github/sakurawald/config/annotation/Comment.java rename to src/main/java/io/github/sakurawald/config/annotation/Documentation.java index df15f15ca..989790ec6 100644 --- a/src/main/java/io/github/sakurawald/config/annotation/Comment.java +++ b/src/main/java/io/github/sakurawald/config/annotation/Documentation.java @@ -4,6 +4,6 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.FIELD}) -public @interface Comment { +public @interface Documentation { String value(); } \ No newline at end of file diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index 570382037..7bbef6763 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -2,10 +2,9 @@ import com.mojang.authlib.properties.Property; -import io.github.sakurawald.config.annotation.Comment; +import io.github.sakurawald.config.annotation.Documentation; import io.github.sakurawald.module.initializer.command_alias.CommandAliasEntry; import io.github.sakurawald.module.initializer.command_rewrite.CommandRewriteEntry; -import net.minecraft.enchantment.Enchantment; import java.util.ArrayList; import java.util.HashMap; @@ -13,33 +12,33 @@ import java.util.Map; @SuppressWarnings("ALL") -@Comment(""" +@Documentation(""" Welcome to fuji-fabric 's offical documentation. This page is the `source code` used to generate the default `config.json` file. You can press `CTRL + F` keys in your keyboard, and search any `option key` that you want to konw. - All the text inside `@Comment` are the documentation text, which describe the following field. + All the text inside `@Documentation` are the documentation text, which describe the following field. """) public class ConfigModel { public Common common = new Common(); public Modules modules = new Modules(); - @Comment(""" + @Documentation(""" Common options for fuji, which influce all modules. """) public class Common { public Quartz quartz = new Quartz(); - @Comment(""" + @Documentation(""" Fuji use quartz library as scheduler, all the timer are managed by quartz. You can use quartz language to define when to trigger a job. See: https://www.freeformatter.com/cron-expression-generator-quartz.html """) public class Quartz { - @Comment(""" + @Documentation(""" The fuji logger level. Options: OFF/FATAL/ERROR/WARN/INFO/DEBUG/TRACE/ALL @@ -51,7 +50,7 @@ public class Quartz { } - @Comment(""" + @Documentation(""" A module means a standalone unit to provide a purpose. All the module can work standalone, you can enable or disable any modules if you like. @@ -118,7 +117,7 @@ public class Modules { public GrindStone grindstone = new GrindStone(); public StoneCutter stonecutter = new StoneCutter(); - @Comment(""" + @Documentation(""" This module adds another 3 worlds called `resource world`: resrouce_overworld, resource_nether, resource_the_end . Use-case: you have 3 permanent-world which is boundary-limited, and you want to provides infinite @@ -128,17 +127,17 @@ public class ResourceWorld { public boolean enable = false; public ResourceWorlds resource_worlds = new ResourceWorlds(); - @Comment("When to auto reset resource worlds") + @Documentation("When to auto reset resource worlds") public String auto_reset_cron = "0 0 20 * * ?"; - @Comment(""" + @Documentation(""" The seed for resource worlds: overworld, the_nether and the_end. You don't need to input this field, since the `seed` field will randomly generated and write every time resource worlds gets reset. """) public long seed = 0L; - @Comment(""" + @Documentation(""" What dimension type of resource worlds do you want to add? """) public class ResourceWorlds { @@ -149,13 +148,13 @@ public class ResourceWorlds { } - @Comment(""" + @Documentation(""" This module customs your MOTD in server-list. """) public class MOTD { public boolean enable = false; - @Comment(""" + @Documentation(""" Fuji will randomly pick a motd each time the player refresh server list. """) public List descriptions = new ArrayList<>() { @@ -165,7 +164,7 @@ public class MOTD { }; } - @Comment(""" + @Documentation(""" This module provides some jobs to trigger when a player is the first time to join the server. """) public class NewbieWelcome { @@ -173,7 +172,7 @@ public class NewbieWelcome { public RandomTeleport random_teleport = new RandomTeleport(); - @Comment("Random teleport the newbie player, and set his bed location.") + @Documentation("Random teleport the newbie player, and set his bed location.") public class RandomTeleport { public int max_try_times = 32; public int min_distance = 5000; @@ -181,7 +180,7 @@ public class RandomTeleport { } } - @Comment(""" + @Documentation(""" This module adds a warmup cooldown before player-teleporatation. The teleporatation will be cancelled if: @@ -192,14 +191,14 @@ public class RandomTeleport { public class TeleportWarmup { public boolean enable = false; - @Comment("The second to wait before the teleportation.") + @Documentation("The second to wait before the teleportation.") public int warmup_second = 3; - @Comment("How far should we cancel the teleportation.") + @Documentation("How far should we cancel the teleportation.") public double interrupt_distance = 1d; } - @Comment(""" + @Documentation(""" Enable this module requires `carpet-fabric` mod installed. This module provides some management for `fake-player` and `/player` command. @@ -207,7 +206,7 @@ public class TeleportWarmup { public class FakePlayerManager { public boolean enable = false; - @Comment(""" + @Documentation(""" How many fake-player can each player spawn (in different time)? The tuple means (day_of_week, minutes_of_the_day, max_fake_player_per_player). @@ -225,7 +224,7 @@ The tuple means (day_of_week, minutes_of_the_day, max_fake_player_per_player). } }; - @Comment(""" + @Documentation(""" How long should we renew when a player issue command `/player renew` The command `/player renew` allows the player to manually renew all of his `fake-player`. @@ -234,14 +233,14 @@ The tuple means (day_of_week, minutes_of_the_day, max_fake_player_per_player). """) public int renew_duration_ms = 1000 * 60 * 60 * 12; - @Comment(""" + @Documentation(""" The rule to transform the name of fake-player. Use-case: add prefix or suffix for fake-player. """) public String transform_name = "_fake_%name%"; - @Comment(""" + @Documentation(""" Should we use local skin for fake-player? Enable this can prevent fetching skins from mojang official server each time the fake-player is spawned. @@ -250,20 +249,20 @@ The tuple means (day_of_week, minutes_of_the_day, max_fake_player_per_player). public boolean use_local_random_skins_for_fake_player = true; } - @Comment(""" + @Documentation(""" Adds nbt query and entity query for carpet command `/info`. """) public class BetterInfo { public boolean enable = false; } - @Comment(""" + @Documentation(""" This module provides a cooldown before each command the player issued. """) public class CommandCooldown { public boolean enable = false; - @Comment(""" + @Documentation(""" Use `regex language` to define issued command cooldown. For each player, each command has its cooldown. @@ -277,7 +276,7 @@ public class CommandCooldown { }; } - @Comment(""" + @Documentation(""" This module provides the `/chunks` command, which shows the `top laggy chunks` in the server. The output is a score list, each score means a chunk, and how laggy the chunk is. (Large score means more laggy) @@ -288,17 +287,17 @@ public class TopChunks { public int rows = 10; public int columns = 10; - @Comment("For a chunk, how much the radius used to search `the nearest player` around the chunk.") + @Documentation("For a chunk, how much the radius used to search `the nearest player` around the chunk.") public int nearest_distance = 128; - @Comment(""" + @Documentation(""" Should we hide the chunk-position for a laggy-chunk? Hide chunk location to avoid grief or privacy purpose. """) public boolean hide_location = true; - @Comment(""" + @Documentation(""" The dict to define how laggy a type(entity/entity_block) should be. For example, @@ -369,13 +368,13 @@ The dict to define how laggy a type(entity/entity_block) should be. }; } - @Comment(""" + @Documentation(""" This module provides chat custom. """) public class Chat { public boolean enable = false; - @Comment(""" + @Documentation(""" The server chat format for all players. You can use `minimessage language` to define complex format. @@ -389,11 +388,11 @@ public class Chat { public Display display = new Display(); public class History { - @Comment("How many chat components should we save, so that we can send for a new-join player.") + @Documentation("How many chat components should we save, so that we can send for a new-join player.") public int cache_size = 50; } - @Comment(""" + @Documentation(""" If you insert `@Steve` in chat message, then the player named `Steve` will get audio mention. """) public class MentionPlayer { @@ -404,12 +403,12 @@ public class MentionPlayer { public int interval_ms = 1000; } - @Comment(""" + @Documentation(""" You can insert `item`, `inv` and `ender` in message to display something with other players. """) public class Display { - @Comment(""" + @Documentation(""" For each display data, how long should we save in the memory. Note that if a player shares its inventory items, then fuji will save a copy of his inventory data in the memory. """) @@ -417,17 +416,17 @@ public class Display { } } - @Comment(""" + @Documentation(""" This module provides player skin management. """) public class Skin { public boolean enable = false; - @Comment("The `default skin` used for player who has no skin set.") + @Documentation("The `default skin` used for player who has no skin set.") public Property default_skin = new Property("textures", "eyJ0aW1lc3RhbXAiOjE1ODYzMjc4ODA1NjYsInByb2ZpbGVJZCI6ImI3MzY3YzA2MjYxYzRlYjBiN2Y3OGY3YzUxNzBiNzQ4IiwicHJvZmlsZU5hbWUiOiJFbXB0eUlyb255Iiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS84NWZmZjI1ZDY2NzIwNmYyZTQ2ZDQ0MmNmMzU4YjNmMWVjMzYxMzgzOTE3NTFiYTZlZGY5NjVmZmM4M2I4NjAzIiwibWV0YWRhdGEiOnsibW9kZWwiOiJzbGltIn19fX0=", "PoUf4TsNx6SVHTWZJ6Iwk3acWyiDk84VeKBVcOeqimaSBAGYKfeuXRTFV8c9IBE9cjsRAVaTGC/mwRfHlcD/rmxeDDOkhsFVidr8UL+91afIO8d+EnyoBghmnbZonqpcjCv+nkxQ5SP93qTDelD3jd8xF1FAU97BBvrx0yK+QNn5rPg2RUGGoUZUg75KlEJds1dNftpHc8IyAHz/FQIywlkohu26ghOqFStjok4WPHD3ok0z7Kwcjk7u58PYf67TkEGnGbmxTUDlNbLmxUqjxCr4NshS+e3y3jRfJN0nP82dbYh/NP2Fx8m7pSMsQtm/Ta2MN7JC0Pm2yvZB/APNoNHVSZZ2SOITbPF/yAkIdHrk+ieCKqDbeuc8TFs2n+6FktYdwPXcqrK266CzlSTPycVZQeyrgrOI+fqU1HwCz+MgdlcsAdAoyuFlFPaVqDesI46YPsSJzA3C3CNhjvuebOn357U9Po82eSFAPYbtBPVNjiNgiqn5l+1x8ZVHImwpGv/toa5/fUyfMmlxijwG/C9gQ4mE+buutMn9nfE1y/AisU/2DWeFBESw3eRAICcmVVi875N8kT+Wja8WsbpDCw+pV2wZC3x3nEdOceAdXtDEb0oy3bQPW3TSZ+Wnp68qwSxjI/aDosqVuyyqqlm+w/irUmNHGL+t7g/kD932g0Q="); - @Comment("Random skin for fake-player, if you enable the local skin for fake-player. See: FakePlayerManagerModule") + @Documentation("Random skin for fake-player, if you enable the local skin for fake-player. See: FakePlayerManagerModule") public ArrayList random_skins = new ArrayList<>() { { this.add(new Property("textures", "eyJ0aW1lc3RhbXAiOjE1ODYzMjc4ODA1NjYsInByb2ZpbGVJZCI6ImI3MzY3YzA2MjYxYzRlYjBiN2Y3OGY3YzUxNzBiNzQ4IiwicHJvZmlsZU5hbWUiOiJFbXB0eUlyb255Iiwic2lnbmF0dXJlUmVxdWlyZWQiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS84NWZmZjI1ZDY2NzIwNmYyZTQ2ZDQ0MmNmMzU4YjNmMWVjMzYxMzgzOTE3NTFiYTZlZGY5NjVmZmM4M2I4NjAzIiwibWV0YWRhdGEiOnsibW9kZWwiOiJzbGltIn19fX0=", "PoUf4TsNx6SVHTWZJ6Iwk3acWyiDk84VeKBVcOeqimaSBAGYKfeuXRTFV8c9IBE9cjsRAVaTGC/mwRfHlcD/rmxeDDOkhsFVidr8UL+91afIO8d+EnyoBghmnbZonqpcjCv+nkxQ5SP93qTDelD3jd8xF1FAU97BBvrx0yK+QNn5rPg2RUGGoUZUg75KlEJds1dNftpHc8IyAHz/FQIywlkohu26ghOqFStjok4WPHD3ok0z7Kwcjk7u58PYf67TkEGnGbmxTUDlNbLmxUqjxCr4NshS+e3y3jRfJN0nP82dbYh/NP2Fx8m7pSMsQtm/Ta2MN7JC0Pm2yvZB/APNoNHVSZZ2SOITbPF/yAkIdHrk+ieCKqDbeuc8TFs2n+6FktYdwPXcqrK266CzlSTPycVZQeyrgrOI+fqU1HwCz+MgdlcsAdAoyuFlFPaVqDesI46YPsSJzA3C3CNhjvuebOn357U9Po82eSFAPYbtBPVNjiNgiqn5l+1x8ZVHImwpGv/toa5/fUyfMmlxijwG/C9gQ4mE+buutMn9nfE1y/AisU/2DWeFBESw3eRAICcmVVi875N8kT+Wja8WsbpDCw+pV2wZC3x3nEdOceAdXtDEb0oy3bQPW3TSZ+Wnp68qwSxjI/aDosqVuyyqqlm+w/irUmNHGL+t7g/kD932g0Q=")); @@ -439,28 +438,28 @@ public class Skin { }; } - @Comment(""" + @Documentation(""" This module provides `/back` command. """) public class Back { public boolean enable = false; - @Comment("If the player's teleportation destination is close enough, we ignore this telepotation.") + @Documentation("If the player's teleportation destination is close enough, we ignore this telepotation.") public double ignore_distance = 32d; } - @Comment(""" + @Documentation(""" This module provides `/tpa`, `/tpahere`, `/tpaacept` and `/tpadeny` commands. """) public class Tpa { public boolean enable = false; - @Comment("Tpa request expiration duration. unit is second") + @Documentation("Tpa request expiration duration. unit is second") public int timeout = 300; } - @Comment(""" + @Documentation(""" This module provides `/work` command. A `work` means a project (a building, a red-stone device ...) that crafted by a player. @@ -472,15 +471,15 @@ public class Tpa { public class Works { public boolean enable = false; - @Comment("For a production-work, how long should we sample it ?") + @Documentation("For a production-work, how long should we sample it ?") public int sample_time_ms = 60 * 1000 * 60; - @Comment("For a production-work, how large the radius should we considered as the work's production") + @Documentation("For a production-work, how large the radius should we considered as the work's production") public int sample_distance_limit = 512; - @Comment("For a production-work, we only display the topN output items") + @Documentation("For a production-work, we only display the topN output items") public int sample_counter_top_n = 20; } - @Comment(""" + @Documentation(""" This module provides `/download` command. This command allows to downlaod nearby chunks around a player. @@ -491,15 +490,15 @@ public class Works { public class WorldDownloader { public boolean enable = false; - @Comment("The url format used to broadcast") + @Documentation("The url format used to broadcast") public String url_format = "http://example.com:%port%%path%"; public int port = 22222; - @Comment("Max download speed limit for each connection.") + @Documentation("Max download speed limit for each connection.") public int bytes_per_second_limit = 128 * 1000; - @Comment("Max download request allowed in the memory at the same time.") + @Documentation("Max download request allowed in the memory at the same time.") public int context_cache_size = 5; } @@ -507,19 +506,19 @@ public class BypassChatSpeed { public boolean enable = false; } - @Comment("Disable `moved too quickly` and `vehicle too quickly` check") + @Documentation("Disable `moved too quickly` and `vehicle too quickly` check") public class BypassMoveSpeed { public boolean enable = false; } - @Comment(""" + @Documentation(""" Bypass the max players limit of the server. """) public class BypassMaxPlayerLimit { public boolean enable = false; } - @Comment(""" + @Documentation(""" This module provides `/deathlog` command. Log player's inventory when he die, so that we can restore his inventory later. @@ -529,14 +528,14 @@ public class DeathLog { public boolean enable = false; } - @Comment(""" + @Documentation(""" This module provides some useful stats, you can use the stats placeholder with ChatModule and MotdModule """) public class MainStats { public boolean enable = false; } - @Comment(""" + @Documentation(""" In vanilla minecraft, each `ender-portal` links to `the only one obsidian platform`. This module makes each `ender-portal` links to its own `obsidian platform`. @@ -544,7 +543,7 @@ public class MainStats { """) public class MultiObsidianPlatform { public boolean enable = false; - @Comment(""" + @Documentation(""" The coordination-convertion factor between overworld and the_end. In vanilla minecraft, the factor between overworld and the_nether is 8.""") public double factor = 4; @@ -554,7 +553,7 @@ public class OpProtect { public boolean enable = false; } - @Comment(""" + @Documentation(""" This module provides `/pvp` command. """) public class Pvp { @@ -574,7 +573,7 @@ public class CommandPermission { public boolean enable = false; } - @Comment(""" + @Documentation(""" This module provides `/head` command, so that players can buy custom-head. """) public class Head { @@ -582,7 +581,7 @@ public class Head { public boolean enable = false; } - @Comment(""" + @Documentation(""" Enable this module requires `spark` mod installed. This module provides `/profiler` command. @@ -596,7 +595,7 @@ public class CommandSpy { public boolean enable = false; } - @Comment(""" + @Documentation(""" This module provides scheduler for auto-run jobs, and `/schudler_trigger` command. """) @@ -604,7 +603,7 @@ public class Scheduler { public boolean enable = false; } - @Comment("This module provides `/fuji reload` command, so that you can reload modules in game.") + @Documentation("This module provides `/fuji reload` command, so that you can reload modules in game.") public class Config { public boolean enable = false; } @@ -614,34 +613,34 @@ public class Test { public boolean enable = false; } - @Comment("This module provides `/hat` command.") + @Documentation("This module provides `/hat` command.") public class Hat { public boolean enable = false; } - @Comment("This module provides `/fly` command.") + @Documentation("This module provides `/fly` command.") public class Fly { public boolean enable = false; } - @Comment("This module provides `/god` command.") + @Documentation("This module provides `/god` command.") public class God { public boolean enable = false; } - @Comment(""" + @Documentation(""" If this module is enabled, then `/fuji reload` command will reload the files inside `/config/fuji/lang`. """) public class Language { public boolean enable = false; } - @Comment("This module provides `/reply` command.") + @Documentation("This module provides `/reply` command.") public class Reply { public boolean enable = false; } - @Comment(""" + @Documentation(""" This module provides afk detection. If a player is idle long enough, he will be marked as afk state. @@ -652,27 +651,27 @@ public class Reply { public class Afk { public boolean enable = false; - @Comment("The tab-name format when a player is afk") + @Documentation("The tab-name format when a player is afk") public String format = "[AFK] %player_display_name%"; - @Comment("The afk checker is a timer to check and mark the player's recently active time.") + @Documentation("The afk checker is a timer to check and mark the player's recently active time.") public AfkChecker afk_checker = new AfkChecker(); public class AfkChecker { - @Comment("The cron to define how the afk_checker is triggered.") + @Documentation("The cron to define how the afk_checker is triggered.") public String cron = "0 0/5 * ? * *"; - @Comment("Should we kick a player if he is afk ?") + @Documentation("Should we kick a player if he is afk ?") public boolean kick_player = false; } } - @Comment("This module provides `/suicide` command.") + @Documentation("This module provides `/suicide` command.") public class Suicide { public boolean enable = false; } - @Comment(""" + @Documentation(""" This module allows you to write commands in `sign block`. A sign-block contains 4 lines. @@ -689,54 +688,54 @@ public class CommandInteractive { public boolean enable = false; - @Comment("Should we log the command used by signs into the console ?") + @Documentation("Should we log the command used by signs into the console ?") public boolean log_use = true; } - @Comment("This module provides `/heal` command.") + @Documentation("This module provides `/heal` command.") public class Heal { public boolean enable = false; } - @Comment("This module provides `/feed` command.") + @Documentation("This module provides `/feed` command.") public class Feed { public boolean enable = false; } - @Comment("This module provides `/repair` command.") + @Documentation("This module provides `/repair` command.") public class Repair { public boolean enable = false; } - @Comment("This module provides `/seen` command.") + @Documentation("This module provides `/seen` command.") public class Seen { public boolean enable = false; } - @Comment("This module provides `/more` command.") + @Documentation("This module provides `/more` command.") public class More { public boolean enable = false; } - @Comment("This module provides `/extinguish` command.") + @Documentation("This module provides `/extinguish` command.") public class Extinguish { public boolean enable = false; } - @Comment("This module provides `/home` command.") + @Documentation("This module provides `/home` command.") public class Home { public boolean enable = false; public int max_homes = 3; } - @Comment("This module provides `/ping` command.") + @Documentation("This module provides `/ping` command.") public class Ping { public boolean enable = false; } - @Comment(""" + @Documentation(""" This module allows you to custom every system-message defined by mojang in `./assets/minecraft/lang/en_us.json` The mojang offical en_us.json file may looks like: [en_us.json for minecraft 1.21](https://github.com/sakurawald/fuji-fabric/blob/dev/.github/files/en_us.json) @@ -745,7 +744,7 @@ public class Ping { public class SystemMessage { public boolean enable = false; - @Comment("The language keys to hijack.") + @Documentation("The language keys to hijack.") public Map key2value = new HashMap<>() { { this.put("multiplayer.player.joined", "+ %s"); @@ -756,28 +755,28 @@ public class SystemMessage { }; } - @Comment("This module provides `/enderchest` command.") + @Documentation("This module provides `/enderchest` command.") public class EnderChest { public boolean enable = false; } - @Comment("This module provides `/workbench` command.") + @Documentation("This module provides `/workbench` command.") public class Workbench { public boolean enable = false; } - @Comment("This module provides `/enchantment` command.") + @Documentation("This module provides `/enchantment` command.") public class Enchantment { public boolean enable = false; - @Comment("Should we override the power of proviers for the opened enchant table?") + @Documentation("Should we override the power of proviers for the opened enchant table?") public OverridePower override_power = new OverridePower(); public class OverridePower { public boolean enable = true; - @Comment(""" + @Documentation(""" How many power providers for the opened enchant table. For a max level of enchant table, it requires 15 power providers.""") public int power_provider_amount = 15; @@ -785,25 +784,25 @@ public class OverridePower { } - @Comment("This module provides `/anvil` command.") + @Documentation("This module provides `/anvil` command.") public class Anvil { public boolean enable = false; } - @Comment("This module provides `/grindstone` command.") + @Documentation("This module provides `/grindstone` command.") public class GrindStone { public boolean enable = false; } - @Comment("This module provides `/stonecutter` command.") + @Documentation("This module provides `/stonecutter` command.") public class StoneCutter { public boolean enable = false; } - @Comment("This module provides `/bed` command, which teleports the player to his bed.") + @Documentation("This module provides `/bed` command, which teleports the player to his bed.") public Bed bed = new Bed(); public class Bed { @@ -811,7 +810,7 @@ public class Bed { public boolean enable = false; } - @Comment(""" + @Documentation(""" This module provides `/sit` command, and the ability to sit by right-click any chair. """) public Sit sit = new Sit(); @@ -829,7 +828,7 @@ public class Sit { public CommandAlias command_alias = new CommandAlias(); - @Comment(""" + @Documentation(""" This module provides command alias. An alias means we redirect a command-node into another command-node. @@ -847,7 +846,7 @@ public class CommandAlias { public CommandRewrite command_rewrite = new CommandRewrite(); - @Comment(""" + @Documentation(""" This module provides command rewrite, so that you can rewrite the `command line` a player issued. """) public class CommandRewrite { diff --git a/src/test/java/BuildConfigurationDocumentTest.java b/src/test/java/BuildConfigurationDocumentTest.java index 5e0c531a9..361c37783 100644 --- a/src/test/java/BuildConfigurationDocumentTest.java +++ b/src/test/java/BuildConfigurationDocumentTest.java @@ -3,7 +3,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import io.github.sakurawald.config.model.ConfigModel; -import io.github.sakurawald.config.annotation.Comment; +import io.github.sakurawald.config.annotation.Documentation; import org.junit.jupiter.api.Test; import java.io.File; @@ -17,11 +17,11 @@ public class BuildConfigurationDocumentTest { private JsonObject buildJsonObjectWithComments(Object obj) { JsonObject jsonObject = new JsonObject(); - processFieldsWithComments(obj, jsonObject); + processFields(obj, jsonObject); return jsonObject; } - private void processFieldsWithComments(Object obj, JsonObject jsonObject) { + private void processFields(Object obj, JsonObject jsonObject) { Class clazz = obj.getClass(); for (Field field : clazz.getFields()) { try { @@ -29,9 +29,9 @@ private void processFieldsWithComments(Object obj, JsonObject jsonObject) { Object value = field.get(obj); /* insert related comment property */ - if (field.isAnnotationPresent(Comment.class)) { - Comment commentAnnotation = field.getAnnotation(Comment.class); - jsonObject.addProperty(fieldName + "@comment", commentAnnotation.value()); + if (field.isAnnotationPresent(Documentation.class)) { + Documentation documentationAnnotation = field.getAnnotation(Documentation.class); + jsonObject.addProperty(fieldName + "@documentation", documentationAnnotation.value()); } /* switch type */ @@ -57,7 +57,7 @@ private void processFieldsWithComments(Object obj, JsonObject jsonObject) { jsonObject.add(fieldName, mapJsonObject); } else { JsonObject nestedJsonObject = new JsonObject(); - processFieldsWithComments(value, nestedJsonObject); + processFields(value, nestedJsonObject); jsonObject.add(fieldName, nestedJsonObject); } } From e4b37e668e263f424261339deb36aef5834f3fd2 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 18:26:01 +0800 Subject: [PATCH 41/50] refactor: documentation generator --- fuji-fabric.wiki | 2 +- ...entTest.java => DocumentationGeneratorTest.java} | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) rename src/test/java/{BuildConfigurationDocumentTest.java => DocumentationGeneratorTest.java} (91%) diff --git a/fuji-fabric.wiki b/fuji-fabric.wiki index 9176c501f..4e53641db 160000 --- a/fuji-fabric.wiki +++ b/fuji-fabric.wiki @@ -1 +1 @@ -Subproject commit 9176c501f3704c90b22be152d18a60bc16edfb71 +Subproject commit 4e53641db4b70820cd611d9b916204649ee5860a diff --git a/src/test/java/BuildConfigurationDocumentTest.java b/src/test/java/DocumentationGeneratorTest.java similarity index 91% rename from src/test/java/BuildConfigurationDocumentTest.java rename to src/test/java/DocumentationGeneratorTest.java index 361c37783..003caa769 100644 --- a/src/test/java/BuildConfigurationDocumentTest.java +++ b/src/test/java/DocumentationGeneratorTest.java @@ -13,9 +13,9 @@ import java.util.List; import java.util.Map; -public class BuildConfigurationDocumentTest { +public class DocumentationGeneratorTest { - private JsonObject buildJsonObjectWithComments(Object obj) { + private JsonObject processJavaObject(Object obj) { JsonObject jsonObject = new JsonObject(); processFields(obj, jsonObject); return jsonObject; @@ -77,8 +77,9 @@ private boolean isPrimitiveOrWrapper(Class clazz) { private void writeToFile(String fileName, JsonObject content) { Gson gson = new GsonBuilder().setPrettyPrinting().create(); - String filePath = "./build/document/" + fileName; + String filePath = "./build/documentation/" + fileName; new File(filePath).getParentFile().mkdirs(); + try (FileWriter writer = new FileWriter(filePath)) { writer.write(gson.toJson(content)); System.out.println("File " + fileName + " has been written successfully."); @@ -88,7 +89,9 @@ private void writeToFile(String fileName, JsonObject content) { } @Test - void buildConfigurationDocument() { - writeToFile("config.json", buildJsonObjectWithComments(new ConfigModel())); + void buildConfigurationDocumentation() { + writeToFile("config.json", processJavaObject(new ConfigModel())); } + + // todo: a generator for Module.md } From 31cca1fba9ba4b7b043dc6d12f24a6870ef8e6d7 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 18:26:34 +0800 Subject: [PATCH 42/50] update: github wiki --- .../sakurawald/config/model/ConfigModel.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index 7bbef6763..fa4682f42 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -642,10 +642,10 @@ public class Reply { @Documentation(""" This module provides afk detection. - + If a player is idle long enough, he will be marked as afk state. A afk player will display in `tab list`. - + A player can issue `/afk` command to afk manually. """) public class Afk { @@ -673,13 +673,13 @@ public class Suicide { @Documentation(""" This module allows you to write commands in `sign block`. - + A sign-block contains 4 lines. You can write commands in the sign-block. - + Each command starts with prefix `//` e.g. Line 1 contains `Click me //back` will execute the command `/back` - + The placeholder `@u` means the user player name. e.g. Line 1 contains `//kill @u` will execute the command `/kill {player_name}` @@ -736,11 +736,11 @@ public class Ping { } @Documentation(""" - This module allows you to custom every system-message defined by mojang in `./assets/minecraft/lang/en_us.json` - - The mojang offical en_us.json file may looks like: [en_us.json for minecraft 1.21](https://github.com/sakurawald/fuji-fabric/blob/dev/.github/files/en_us.json) - - """) + This module allows you to custom every system-message defined by mojang in `./assets/minecraft/lang/en_us.json` + + The mojang offical en_us.json file may looks like: [en_us.json for minecraft 1.21](https://github.com/sakurawald/fuji-fabric/blob/dev/.github/files/en_us.json) + + """) public class SystemMessage { public boolean enable = false; @@ -830,7 +830,7 @@ public class Sit { @Documentation(""" This module provides command alias. - + An alias means we redirect a command-node into another command-node. The requirement of comamnd-node is extended. """) From 587b3babfb646c67026b33a5a82bfc38b599f6f9 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 19:14:21 +0800 Subject: [PATCH 43/50] add: auto run tests on modrinthSyncBody + add: ConfigurationDocumentationGeneratorTest --- build.gradle | 7 +- fuji-fabric.wiki | 2 +- .../sakurawald/config/model/ConfigModel.java | 86 ++++++++++++++++--- ...figurationDocumentationGeneratorTest.java} | 3 +- .../ModuleDocumentationGeneratorTest.java | 67 +++++++++++++++ 5 files changed, 150 insertions(+), 15 deletions(-) rename src/test/java/{DocumentationGeneratorTest.java => ConfigurationDocumentationGeneratorTest.java} (97%) create mode 100644 src/test/java/ModuleDocumentationGeneratorTest.java diff --git a/build.gradle b/build.gradle index ad52f4f36..d710051f1 100755 --- a/build.gradle +++ b/build.gradle @@ -139,4 +139,9 @@ tasks.modrinth.dependsOn(tasks.modrinthSyncBody) // test framework test { useJUnitPlatform() -} \ No newline at end of file + + filter { + includeTestsMatching 'ModuleDocumentationGeneratorTest.buildModuleDocumentation' + } +} +tasks.modrinthSyncBody.dependsOn(tasks.test) diff --git a/fuji-fabric.wiki b/fuji-fabric.wiki index 4e53641db..2e1744ebf 160000 --- a/fuji-fabric.wiki +++ b/fuji-fabric.wiki @@ -1 +1 @@ -Subproject commit 4e53641db4b70820cd611d9b916204649ee5860a +Subproject commit 2e1744ebf4883c445c7627c4a73e7de4f9cfb438 diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index fa4682f42..e12fb8a8f 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -5,6 +5,8 @@ import io.github.sakurawald.config.annotation.Documentation; import io.github.sakurawald.module.initializer.command_alias.CommandAliasEntry; import io.github.sakurawald.module.initializer.command_rewrite.CommandRewriteEntry; +import net.minecraft.client.realms.Ping; +import net.minecraft.enchantment.Enchantment; import java.util.ArrayList; import java.util.HashMap; @@ -120,6 +122,8 @@ public class Modules { @Documentation(""" This module adds another 3 worlds called `resource world`: resrouce_overworld, resource_nether, resource_the_end . + Command: /rw + Use-case: you have 3 permanent-world which is boundary-limited, and you want to provides infinite resource for the newbie players, then you can use `resource world` while keeping the permanent-world. """) @@ -183,9 +187,10 @@ public class RandomTeleport { @Documentation(""" This module adds a warmup cooldown before player-teleporatation. - The teleporatation will be cancelled if: - 1. the player runs to far. + The teleportation will be cancelled if: + 1. the player runs too far. 2. the player gets damage. + 3. the player is in combat. """) public class TeleportWarmup { @@ -217,6 +222,10 @@ The tuple means (day_of_week, minutes_of_the_day, max_fake_player_per_player). Besides, you can add multi rules, the rules are checked from up to down. The first rule that matches current time will be used to decide the max_fake_player_per_player. + + You can issue `/player who` to see the owner of the fake-player. + Only the owner can operates the fake-player. (Op can bypass this limit) + """) public ArrayList> caps_limit_rule = new ArrayList<>() { { @@ -230,6 +239,8 @@ The tuple means (day_of_week, minutes_of_the_day, max_fake_player_per_player). The command `/player renew` allows the player to manually renew all of his `fake-player`. If a fake-player don't gets renew, then it will expired and get killed. + + Use-case: to avoid some long-term alive fake-player. """) public int renew_duration_ms = 1000 * 60 * 60 * 12; @@ -258,6 +269,8 @@ public class BetterInfo { @Documentation(""" This module provides a cooldown before each command the player issued. + + Use-case: use this module to avoid some heavy-command abuse """) public class CommandCooldown { public boolean enable = false; @@ -370,6 +383,10 @@ The dict to define how laggy a type(entity/entity_block) should be. @Documentation(""" This module provides chat custom. + + Command: /chat + + You can also insert some placeholder in chat message: `pos` """) public class Chat { public boolean enable = false; @@ -387,6 +404,9 @@ public class Chat { public History history = new History(); public Display display = new Display(); + @Documentation(""" + New joined players can see the historical chat messages. + """) public class History { @Documentation("How many chat components should we save, so that we can send for a new-join player.") public int cache_size = 50; @@ -466,7 +486,9 @@ public class Tpa { All `work` types: 1. Non-production work: the project don't produce any resource (e.g. bone, string, coal). - 2. Production work: the project produce some resource. + 2. Production work: the project produce some resource. + For a production-work, fuji provides the `production sample` to count the `hopper` and `minecart-hopper` + """) public class Works { public boolean enable = false; @@ -502,6 +524,9 @@ public class WorldDownloader { public int context_cache_size = 5; } + @Documentation(""" + This module bypass "Kicked for spamming" + """) public class BypassChatSpeed { public boolean enable = false; } @@ -530,6 +555,9 @@ public class DeathLog { @Documentation(""" This module provides some useful stats, you can use the stats placeholder with ChatModule and MotdModule + + Placeholders: total_playtime, total_mined, total_placed, total_killed and total_moved (We call these 5 stats `MainStats`). + You can use these placeholders in `Chat module` and `MOTD module` """) public class MainStats { public boolean enable = false; @@ -539,6 +567,11 @@ public class MainStats { In vanilla minecraft, each `ender-portal` links to `the only one obsidian platform`. This module makes each `ender-portal` links to its own `obsidian platform`. + makes every EnderPortal generate its own Obsidian Platform (Up to 128 in survival-mode. + You can even use creative-mode to build more Ender Portal and more ObsidianPlatform. + + Please note that: all the obsidian-platform are vanilla-respect, which means they have the SAME chunk-layout and the SAME behaviour as vanilla obsidian-platform which locates in (100,50,0)) + Use-case: you want more `obsidian platform` for your redstone-struture. """) public class MultiObsidianPlatform { @@ -549,21 +582,28 @@ public class MultiObsidianPlatform { public double factor = 4; } + @Documentation("auto deop an op-player when he leaves the server.") public class OpProtect { public boolean enable = false; } @Documentation(""" - This module provides `/pvp` command. + This module provides `/pvp` command. """) public class Pvp { public boolean enable = false; } + @Documentation(""" + a fix patch for ServerWorld#PlayerList, to avoid CME in player-list (e.g. sometimes tick-entity and tick-block-entity will randomly crash the server because of player-list CME) + """) public class FixPlayerListCME { public boolean enable = false; } + @Documentation(""" + for offline whitelist, this makes whitelist ONLY compare the username and ignore UUID! + """) public class FixWhitelist { public boolean enable = false; @@ -584,19 +624,22 @@ public class Head { @Documentation(""" Enable this module requires `spark` mod installed. - This module provides `/profiler` command. + This module provides `/profiler` command to show server health status (including os, vm, cpu, ram, tps, mspt and gc) """) public class Profiler { public boolean enable = false; } + @Documentation("log command issue into the console.") public class CommandSpy { public boolean enable = false; } @Documentation(""" This module provides scheduler for auto-run jobs, and `/schudler_trigger` command. + + You can add schedule jobs by cron expression, set the random command-list to be executed. """) public class Scheduler { @@ -629,13 +672,21 @@ public class God { } @Documentation(""" - If this module is enabled, then `/fuji reload` command will reload the files inside `/config/fuji/lang`. + This module provides multi-language support for your players. + (Disable this module will force all the players to use the default language) + + - The default language is en_us. + - Respect the player's client-side language-setting. + - If the player's client-side language-setting is not supported, then use the default language. + - Lazy-load support, which means if a language is not required, then it will not be loaded. + - Dynamic-reload support, you need to enable `ConfigModule` to use reload command. + """) public class Language { public boolean enable = false; } - @Documentation("This module provides `/reply` command.") + @Documentation("This module provides `/reply` command, which replys the recent player who `/msg` you") public class Reply { public boolean enable = false; } @@ -682,6 +733,11 @@ public class Suicide { The placeholder `@u` means the user player name. e.g. Line 1 contains `//kill @u` will execute the command `/kill {player_name}` + + - If the sign contains `//`, then you must press `shift` to edit this sign + - You can add some comments before the first `//` + - You can use all the four lines to insert `//` (Every `//` means one command) + - Placeholder `@u` means the user of this sign """) public class CommandInteractive { @@ -739,6 +795,14 @@ public class Ping { This module allows you to custom every system-message defined by mojang in `./assets/minecraft/lang/en_us.json` The mojang offical en_us.json file may looks like: [en_us.json for minecraft 1.21](https://github.com/sakurawald/fuji-fabric/blob/dev/.github/files/en_us.json) + + The system messages including: + - Player join and leave server message + - Player advancement message + - Player death message + - Player command feedback + - Player white-list message + - ... (and 7000+ other system messages) """) public class SystemMessage { @@ -802,19 +866,19 @@ public class StoneCutter { public boolean enable = false; } - @Documentation("This module provides `/bed` command, which teleports the player to his bed.") public Bed bed = new Bed(); + @Documentation("This module provides `/bed` command, which teleports the player to his bed.") public class Bed { public boolean enable = false; } + public Sit sit = new Sit(); + @Documentation(""" This module provides `/sit` command, and the ability to sit by right-click any chair. """) - public Sit sit = new Sit(); - public class Sit { public boolean enable = false; @@ -847,7 +911,7 @@ public class CommandAlias { public CommandRewrite command_rewrite = new CommandRewrite(); @Documentation(""" - This module provides command rewrite, so that you can rewrite the `command line` a player issued. + This module provides command rewrite, so that you can use `regex language` to rewrite the `command line` a player issued. """) public class CommandRewrite { public boolean enable = false; diff --git a/src/test/java/DocumentationGeneratorTest.java b/src/test/java/ConfigurationDocumentationGeneratorTest.java similarity index 97% rename from src/test/java/DocumentationGeneratorTest.java rename to src/test/java/ConfigurationDocumentationGeneratorTest.java index 003caa769..2fe78b399 100644 --- a/src/test/java/DocumentationGeneratorTest.java +++ b/src/test/java/ConfigurationDocumentationGeneratorTest.java @@ -13,7 +13,7 @@ import java.util.List; import java.util.Map; -public class DocumentationGeneratorTest { +public class ConfigurationDocumentationGeneratorTest { private JsonObject processJavaObject(Object obj) { JsonObject jsonObject = new JsonObject(); @@ -93,5 +93,4 @@ void buildConfigurationDocumentation() { writeToFile("config.json", processJavaObject(new ConfigModel())); } - // todo: a generator for Module.md } diff --git a/src/test/java/ModuleDocumentationGeneratorTest.java b/src/test/java/ModuleDocumentationGeneratorTest.java new file mode 100644 index 000000000..50d45be9c --- /dev/null +++ b/src/test/java/ModuleDocumentationGeneratorTest.java @@ -0,0 +1,67 @@ +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import io.github.sakurawald.config.annotation.Documentation; +import io.github.sakurawald.config.model.ConfigModel; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +@Slf4j +public class ModuleDocumentationGeneratorTest { + + private StringBuilder processJavaObject(Object obj) { + StringBuilder sb = new StringBuilder(); + sb.append(""" + # Modules + + _**By default, all the modules are disabled.**_ + + _**This page is generated by program. To get more detailed documentation, read [the runtime-control configuration](https://github.com/sakurawald/fuji-fabric/blob/dev/src/main/java/io/github/sakurawald/config/model/ConfigModel.java)**_ + + """); + + processFields(sb, obj); + return sb; + } + + private void processFields(StringBuilder sb, Object obj) { + Class clazz = obj.getClass(); + for (Class innerClazz : clazz.getDeclaredClasses()) { + String name = innerClazz.getSimpleName(); + + /* insert related comment property */ + if (innerClazz.isAnnotationPresent(Documentation.class)) { + Documentation annotation = innerClazz.getAnnotation(Documentation.class); + sb.append("## ").append(name).append(" module"); + sb.append("\n").append(annotation.value().trim()).append("\n\n"); + } + } + } + + private boolean isPrimitiveOrWrapper(Class clazz) { + return clazz.isPrimitive() || clazz == Boolean.class || clazz == Character.class || + Number.class.isAssignableFrom(clazz) || clazz == String.class; + } + + private void writeToFile(String fileName, Object object) { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + String filePath = "./fuji-fabric.wiki/" + fileName; + new File(filePath).getParentFile().mkdirs(); + + try (FileWriter writer = new FileWriter(filePath)) { + writer.write(object.toString()); + System.out.println("File " + fileName + " has been written successfully."); + } catch (IOException e) { + System.err.println("An error occurred while writing file: " + e.getMessage()); + } + } + + @Test + void buildModuleDocumentation() { + writeToFile("Module.md", processJavaObject(new ConfigModel().modules)); + } + +} From 58cb0920fb43a843badbc7a5673bce3126ce7b49 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 19:15:30 +0800 Subject: [PATCH 44/50] update: github wiki --- src/test/java/ModuleDocumentationGeneratorTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/ModuleDocumentationGeneratorTest.java b/src/test/java/ModuleDocumentationGeneratorTest.java index 50d45be9c..d9f3298cf 100644 --- a/src/test/java/ModuleDocumentationGeneratorTest.java +++ b/src/test/java/ModuleDocumentationGeneratorTest.java @@ -17,9 +17,9 @@ private StringBuilder processJavaObject(Object obj) { sb.append(""" # Modules - _**By default, all the modules are disabled.**_ - - _**This page is generated by program. To get more detailed documentation, read [the runtime-control configuration](https://github.com/sakurawald/fuji-fabric/blob/dev/src/main/java/io/github/sakurawald/config/model/ConfigModel.java)**_ + > _**This page is generated by program. To get more detailed documentation, read [the runtime-control configuration](https://github.com/sakurawald/fuji-fabric/blob/dev/src/main/java/io/github/sakurawald/config/model/ConfigModel.java)**_ + + > _**By default, all the modules are disabled.**_ """); From de8f9ff3c0cbd7f24f1f5bb9a2a6acf06994c859 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 19:17:09 +0800 Subject: [PATCH 45/50] update: github wiki --- fuji-fabric.wiki | 2 +- src/test/java/ModuleDocumentationGeneratorTest.java | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/fuji-fabric.wiki b/fuji-fabric.wiki index 2e1744ebf..1cb645117 160000 --- a/fuji-fabric.wiki +++ b/fuji-fabric.wiki @@ -1 +1 @@ -Subproject commit 2e1744ebf4883c445c7627c4a73e7de4f9cfb438 +Subproject commit 1cb645117bac2a79551b01c66fcc3069e43489fc diff --git a/src/test/java/ModuleDocumentationGeneratorTest.java b/src/test/java/ModuleDocumentationGeneratorTest.java index d9f3298cf..f2c817687 100644 --- a/src/test/java/ModuleDocumentationGeneratorTest.java +++ b/src/test/java/ModuleDocumentationGeneratorTest.java @@ -32,20 +32,16 @@ private void processFields(StringBuilder sb, Object obj) { for (Class innerClazz : clazz.getDeclaredClasses()) { String name = innerClazz.getSimpleName(); - /* insert related comment property */ + sb.append("## ").append(name).append(" module"); if (innerClazz.isAnnotationPresent(Documentation.class)) { Documentation annotation = innerClazz.getAnnotation(Documentation.class); - sb.append("## ").append(name).append(" module"); sb.append("\n").append(annotation.value().trim()).append("\n\n"); + } else { + sb.append("\n").append("No documentation.").append("\n\n"); } } } - private boolean isPrimitiveOrWrapper(Class clazz) { - return clazz.isPrimitive() || clazz == Boolean.class || clazz == Character.class || - Number.class.isAssignableFrom(clazz) || clazz == String.class; - } - private void writeToFile(String fileName, Object object) { Gson gson = new GsonBuilder().setPrettyPrinting().create(); String filePath = "./fuji-fabric.wiki/" + fileName; From dd1a0b8a3fddc63c3babf70979a30b6d394ee07c Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 19:17:23 +0800 Subject: [PATCH 46/50] update: github wiki --- fuji-fabric.wiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuji-fabric.wiki b/fuji-fabric.wiki index 1cb645117..2521a72b3 160000 --- a/fuji-fabric.wiki +++ b/fuji-fabric.wiki @@ -1 +1 @@ -Subproject commit 1cb645117bac2a79551b01c66fcc3069e43489fc +Subproject commit 2521a72b36bc5e6b03da0c44cc4bb63d40f1ab1b From 8700c4df9a5f3ebf10231e02998eeba9e1c760a5 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 19:18:59 +0800 Subject: [PATCH 47/50] update: github wiki --- .../java/io/github/sakurawald/config/model/ConfigModel.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java index e12fb8a8f..0b7c29614 100644 --- a/src/main/java/io/github/sakurawald/config/model/ConfigModel.java +++ b/src/main/java/io/github/sakurawald/config/model/ConfigModel.java @@ -609,6 +609,9 @@ public class FixWhitelist { public boolean enable = false; } + @Documentation(""" + See [permission](https://github.com/sakurawald/fuji-fabric/wiki/Permission) + """) public class CommandPermission { public boolean enable = false; } From 8b90fd3ef0dec6de660c07c359c35db22e39114e Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sat, 6 Jul 2024 19:19:29 +0800 Subject: [PATCH 48/50] update: github wiki --- fuji-fabric.wiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuji-fabric.wiki b/fuji-fabric.wiki index 2521a72b3..0c4ece22d 160000 --- a/fuji-fabric.wiki +++ b/fuji-fabric.wiki @@ -1 +1 @@ -Subproject commit 2521a72b36bc5e6b03da0c44cc4bb63d40f1ab1b +Subproject commit 0c4ece22d0064d4840e204de1de5298823208af0 From f620f09b75a9f539c2d98f454341352205930b30 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Sun, 7 Jul 2024 15:08:56 +0800 Subject: [PATCH 49/50] update: github wiki --- README.md | 2 +- fuji-fabric.wiki | 2 +- src/main/java/io/github/sakurawald/Fuji.java | 15 ++++++++++++--- .../module/initializer/chat/ChatModule.java | 1 - .../initializer/scheduler/SpecializedCommand.java | 2 +- .../java/io/github/sakurawald/util/LogUtil.java | 1 + 6 files changed, 16 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a41a6a860..cda977a60 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Introduction +# Description Fuji is a minecraft mod that provides many essential and useful modules for vanilla survival. > **_If minecraft gets updated, you can mail sakurawald@gmail.com for fuji update reminder._** diff --git a/fuji-fabric.wiki b/fuji-fabric.wiki index 0c4ece22d..2a71d1b5a 160000 --- a/fuji-fabric.wiki +++ b/fuji-fabric.wiki @@ -1 +1 @@ -Subproject commit 0c4ece22d0064d4840e204de1de5298823208af0 +Subproject commit 2a71d1b5a328554425bf54170b54d7e0b5124dce diff --git a/src/main/java/io/github/sakurawald/Fuji.java b/src/main/java/io/github/sakurawald/Fuji.java index 352801cc6..17b7a8584 100644 --- a/src/main/java/io/github/sakurawald/Fuji.java +++ b/src/main/java/io/github/sakurawald/Fuji.java @@ -8,11 +8,11 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.server.MinecraftServer; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Logger; import java.nio.file.Path; - // TODO: placeholder module (placeholder api) // TODO: specific command module @@ -25,11 +25,20 @@ // TODO: command warmup module // TODO: /spawn module // TODO: /tppos module -// TODO: playtime(every/for) rewards and rank like module +// TODO: playtime(every/for) rewards module +// TODO: rank module + +// TODO: a light-weight way to implement chat module + +// TODO: revert some custom events + +// TODO: delete ./github images + +// TODO: remove fabric-api dep public class Fuji implements ModInitializer { public static final String MOD_ID = "fuji"; - public static final Logger LOGGER = LogUtil.createLogger("Fuji"); + public static final Logger LOGGER = LogUtil.createLogger(StringUtils.capitalize(MOD_ID)); public static final Path CONFIG_PATH = FabricLoader.getInstance().getConfigDir().resolve(MOD_ID).toAbsolutePath(); public static MinecraftServer SERVER; diff --git a/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java b/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java index 802e8162c..d0016590b 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java +++ b/src/main/java/io/github/sakurawald/module/initializer/chat/ChatModule.java @@ -169,7 +169,6 @@ private Component resolvePositionTag(ServerPlayerEntity player, Component compon } String dim_display_name; - // TODO: insert `pos` in resource world will throw error if (MessageUtil.ofString(player, dim_name) != null) { dim_display_name = MessageUtil.ofString(player, dim_name); } else { diff --git a/src/main/java/io/github/sakurawald/module/initializer/scheduler/SpecializedCommand.java b/src/main/java/io/github/sakurawald/module/initializer/scheduler/SpecializedCommand.java index 8a178600a..cdde31ab9 100644 --- a/src/main/java/io/github/sakurawald/module/initializer/scheduler/SpecializedCommand.java +++ b/src/main/java/io/github/sakurawald/module/initializer/scheduler/SpecializedCommand.java @@ -12,7 +12,7 @@ public class SpecializedCommand { - // TODO: a language parser is needed here (supports some expressions solver) + // TODO: require a DSL here private static final String RANDOM_PLAYER = "!random_player!"; private static final String ALL_PLAYER = "!all_player!"; diff --git a/src/main/java/io/github/sakurawald/util/LogUtil.java b/src/main/java/io/github/sakurawald/util/LogUtil.java index 39645d979..dc6c818b4 100644 --- a/src/main/java/io/github/sakurawald/util/LogUtil.java +++ b/src/main/java/io/github/sakurawald/util/LogUtil.java @@ -9,6 +9,7 @@ @UtilityClass public class LogUtil { + public static Logger createLogger(String name) { Logger logger = LogManager.getLogger(name); try { From f074d534e99bafa9680a87721a81bbb4dfe3ac47 Mon Sep 17 00:00:00 2001 From: sakurawald Date: Mon, 17 Jun 2024 21:27:25 +0800 Subject: [PATCH 50/50] revert: bump commit --- gradle.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 670dc66f7..fcc87e1ec 100755 --- a/gradle.properties +++ b/gradle.properties @@ -8,13 +8,13 @@ maven_group=io.github.sakurawald archives_base_name=fuji # fabric deps -minecraft_version=1.21 +minecraft_version=1.20.6 loader_version=0.15.11 -yarn_mappings=1.21+build.2 +yarn_mappings=1.20.6+build.1 # mod deps -fabric_api_version=0.100.1+1.21 -carpet_core_version=1.21-1.4.147+v240613 +fabric_api_version=0.98.0+1.20.6 +carpet_core_version=1.20.6-1.4.141+v240429 sgui_version=1.6.0+1.21 adventure_api_version=4.17.0 adventure_platform_fabric_version=5.14.0-SNAPSHOT