diff --git a/src/main/java/vazkii/quark/base/Quark.java b/src/main/java/vazkii/quark/base/Quark.java index a148b32c95..5b3e6ec6fc 100644 --- a/src/main/java/vazkii/quark/base/Quark.java +++ b/src/main/java/vazkii/quark/base/Quark.java @@ -13,17 +13,17 @@ public class Quark { public static final String MOD_ID = "quark"; public static final String ODDITIES_ID = "quarkoddities"; - + public static Quark instance; public static CommonProxy proxy; public static final Logger LOG = LogManager.getLogger(MOD_ID); - + public Quark() { instance = this; - - proxy = DistExecutor.runForDist(() -> ClientProxy::new, () -> CommonProxy::new); + + proxy = DistExecutor.safeRunForDist(() -> ClientProxy::new, () -> CommonProxy::new); proxy.start(); } - + } diff --git a/src/main/java/vazkii/quark/base/module/LoadModule.java b/src/main/java/vazkii/quark/base/module/LoadModule.java index 01825710ea..627efd278e 100644 --- a/src/main/java/vazkii/quark/base/module/LoadModule.java +++ b/src/main/java/vazkii/quark/base/module/LoadModule.java @@ -1,18 +1,18 @@ package vazkii.quark.base.module; +import net.minecraftforge.api.distmarker.Dist; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import net.minecraftforge.api.distmarker.Dist; - @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface LoadModule { ModuleCategory category(); - + String name() default ""; String description() default ""; String[] antiOverlap() default { }; @@ -21,5 +21,5 @@ Dist[] subscribeOn() default { Dist.CLIENT, Dist.DEDICATED_SERVER }; boolean enabledByDefault() default true; - + } diff --git a/src/main/java/vazkii/quark/base/module/config/ConfigFlagManager.java b/src/main/java/vazkii/quark/base/module/config/ConfigFlagManager.java index ffb67b502b..25cadbdacb 100644 --- a/src/main/java/vazkii/quark/base/module/config/ConfigFlagManager.java +++ b/src/main/java/vazkii/quark/base/module/config/ConfigFlagManager.java @@ -1,21 +1,23 @@ package vazkii.quark.base.module.config; -import java.util.HashMap; -import java.util.Map; - import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType; import net.minecraftforge.common.crafting.CraftingHelper; import vazkii.quark.base.Quark; import vazkii.quark.base.module.QuarkModule; +import vazkii.quark.base.module.sync.SyncedFlagHandler; import vazkii.quark.base.recipe.ingredient.FlagIngredient; import vazkii.quark.base.recipe.ingredient.PotionIngredient; +import java.util.*; + public final class ConfigFlagManager { public static LootItemConditionType flagLootConditionType; + private final List orderedFlags = new ArrayList<>(); + private final Set allFlags = new HashSet<>(); private final Map flags = new HashMap<>(); private boolean registered = false; @@ -28,12 +30,14 @@ public void registerConfigBoundElements() { CraftingHelper.register(new FlagRecipeCondition.Serializer(this, new ResourceLocation(Quark.MOD_ID, "flag"))); CraftingHelper.register(new FlagAdvancementCondition.Serializer(this, new ResourceLocation(Quark.MOD_ID, "advancement_flag"))); - + flagLootConditionType = new LootItemConditionType(new FlagLootCondition.FlagSerializer(this)); Registry.register(Registry.LOOT_CONDITION_TYPE, new ResourceLocation(Quark.MOD_ID, "flag"), flagLootConditionType); CraftingHelper.register(new ResourceLocation(Quark.MOD_ID, "potion"), PotionIngredient.Serializer.INSTANCE); CraftingHelper.register(new ResourceLocation(Quark.MOD_ID, "flag"), new FlagIngredient.Serializer(this)); + + SyncedFlagHandler.setupFlagManager(this, orderedFlags); } public void clear() { @@ -42,10 +46,14 @@ public void clear() { public void putFlag(QuarkModule module, String flag, boolean value) { flags.put(flag, value && module.enabled); + if (!allFlags.contains(flag)) { + orderedFlags.add(flag); + allFlags.add(flag); + } } public void putEnabledFlag(QuarkModule module) { - flags.put(module.lowercaseName, module.enabled); + putFlag(module, module.lowercaseName, true); } public boolean isValidFlag(String flag) { diff --git a/src/main/java/vazkii/quark/base/module/config/ConfigObjectSerializer.java b/src/main/java/vazkii/quark/base/module/config/ConfigObjectSerializer.java index 3f4de37c05..37df1fd0ee 100644 --- a/src/main/java/vazkii/quark/base/module/config/ConfigObjectSerializer.java +++ b/src/main/java/vazkii/quark/base/module/config/ConfigObjectSerializer.java @@ -1,5 +1,12 @@ package vazkii.quark.base.module.config; +import net.minecraftforge.common.ForgeConfigSpec; +import org.apache.commons.lang3.text.WordUtils; +import org.jetbrains.annotations.Nullable; +import vazkii.quark.base.module.QuarkModule; +import vazkii.quark.base.module.config.type.IConfigType; +import vazkii.quark.base.module.hint.HintManager; + import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -12,20 +19,12 @@ import java.util.function.Predicate; import java.util.function.Supplier; -import org.apache.commons.lang3.text.WordUtils; -import org.jetbrains.annotations.Nullable; - -import net.minecraftforge.common.ForgeConfigSpec; -import vazkii.quark.base.module.QuarkModule; -import vazkii.quark.base.module.config.type.IConfigType; -import vazkii.quark.base.module.hint.HintManager; - public final class ConfigObjectSerializer { public static void serialize(IConfigBuilder builder, ConfigFlagManager flagManager, List callbacks, Object object) throws ReflectiveOperationException { serialize(builder, flagManager, callbacks, object, object); } - + public static void serialize(IConfigBuilder builder, ConfigFlagManager flagManager, List callbacks, Object object, Object root) throws ReflectiveOperationException { List fields = recursivelyGetFields(object.getClass()); for(Field f : fields) { diff --git a/src/main/java/vazkii/quark/base/module/config/ConfigResolver.java b/src/main/java/vazkii/quark/base/module/config/ConfigResolver.java index df30640cca..104dbdb8ca 100644 --- a/src/main/java/vazkii/quark/base/module/config/ConfigResolver.java +++ b/src/main/java/vazkii/quark/base/module/config/ConfigResolver.java @@ -33,7 +33,7 @@ public class ConfigResolver { private final ConfigFlagManager flagManager; - private List refreshRunnables = new LinkedList<>(); + private final List refreshRunnables = new LinkedList<>(); private ModConfig config; public ConfigResolver() { diff --git a/src/main/java/vazkii/quark/base/module/sync/SyncedFlagHandler.java b/src/main/java/vazkii/quark/base/module/sync/SyncedFlagHandler.java new file mode 100644 index 0000000000..dfbddf3571 --- /dev/null +++ b/src/main/java/vazkii/quark/base/module/sync/SyncedFlagHandler.java @@ -0,0 +1,75 @@ +package vazkii.quark.base.module.sync; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.PacketListener; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import vazkii.quark.base.module.config.ConfigFlagManager; +import vazkii.quark.base.network.QuarkNetwork; +import vazkii.quark.base.network.message.structural.S2CUpdateFlag; + +import java.util.*; + +public class SyncedFlagHandler { + private static ConfigFlagManager flagManager; + private static List allFlags; + + public static void setupFlagManager(ConfigFlagManager manager, List flags) { + flagManager = manager; + allFlags = flags; + } + + public static BitSet compileFlagInfo() { + BitSet set = new BitSet(); + int i = 0; + for (String flag : allFlags) set.set(i++, flagManager.getFlag(flag)); + + return set; + } + + private static Set decodeFlags(BitSet bitSet) { + Set enabledFlags = new HashSet<>(); + + for (int i = bitSet.nextSetBit(0); i >= 0; i = bitSet.nextSetBit(i + 1)) { + enabledFlags.add(allFlags.get(i)); + } + + return enabledFlags; + } + + public static void receiveFlagInfoFromPlayer(ServerPlayer player, BitSet bitSet) { + flagsFromPlayers.put(player, decodeFlags(bitSet)); + } + + @OnlyIn(Dist.CLIENT) + public static void receiveFlagInfoFromServer(BitSet bitSet) { + flagsFromServer.put(Minecraft.getInstance().getConnection(), decodeFlags(bitSet)); + } + + public static void sendFlagInfoToPlayers() { + QuarkNetwork.sendToPlayers(new S2CUpdateFlag(), flagsFromPlayers.keySet()); + } + + private static final WeakHashMap> flagsFromServer = new WeakHashMap<>(); + private static final WeakHashMap> flagsFromPlayers = new WeakHashMap<>(); + + public static boolean getFlagForPlayer(ServerPlayer player, String flag) { + Set enabledFlags = flagsFromPlayers.get(player); + if (enabledFlags == null) + return flagManager.getFlag(flag); + + return enabledFlags.contains(flag); + } + + @OnlyIn(Dist.CLIENT) + public static boolean getFlagForServer(String flag) { + for (PacketListener listener : flagsFromServer.keySet()) { + Set enabledFlags = flagsFromServer.get(listener); + if (enabledFlags != null) + return enabledFlags.contains(flag); + } + + return flagManager.getFlag(flag); + } +} diff --git a/src/main/java/vazkii/quark/base/network/QuarkNetwork.java b/src/main/java/vazkii/quark/base/network/QuarkNetwork.java index 249993c77d..66a84bfa85 100644 --- a/src/main/java/vazkii/quark/base/network/QuarkNetwork.java +++ b/src/main/java/vazkii/quark/base/network/QuarkNetwork.java @@ -1,37 +1,29 @@ package vazkii.quark.base.network; -import java.time.Instant; - import net.minecraft.network.chat.LastSeenMessages; import net.minecraft.network.chat.MessageSignature; import net.minecraft.network.protocol.Packet; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraftforge.network.NetworkDirection; +import net.minecraftforge.network.simple.SimpleChannel; import vazkii.arl.network.IMessage; import vazkii.arl.network.MessageSerializer; import vazkii.arl.network.NetworkHandler; import vazkii.quark.base.Quark; -import vazkii.quark.base.network.message.ChangeHotbarMessage; -import vazkii.quark.base.network.message.DoEmoteMessage; -import vazkii.quark.base.network.message.DoubleDoorMessage; -import vazkii.quark.base.network.message.EditSignMessage; -import vazkii.quark.base.network.message.HarvestMessage; -import vazkii.quark.base.network.message.InventoryTransferMessage; -import vazkii.quark.base.network.message.RequestEmoteMessage; -import vazkii.quark.base.network.message.ScrollOnBundleMessage; -import vazkii.quark.base.network.message.SetLockProfileMessage; -import vazkii.quark.base.network.message.ShareItemMessage; -import vazkii.quark.base.network.message.SortInventoryMessage; -import vazkii.quark.base.network.message.UpdateTridentMessage; +import vazkii.quark.base.network.message.*; import vazkii.quark.base.network.message.experimental.PlaceVariantUpdateMessage; import vazkii.quark.base.network.message.oddities.HandleBackpackMessage; import vazkii.quark.base.network.message.oddities.MatrixEnchanterOperationMessage; import vazkii.quark.base.network.message.oddities.ScrollCrateMessage; +import vazkii.quark.base.network.message.structural.*; + +import java.time.Instant; +import java.util.BitSet; public final class QuarkNetwork { - private static final int PROTOCOL_VERSION = 1; + private static final int PROTOCOL_VERSION = 2; private static NetworkHandler network; @@ -39,6 +31,7 @@ public static void setup() { MessageSerializer.mapHandlers(Instant.class, (buf, field) -> buf.readInstant(), (buf, field, instant) -> buf.writeInstant(instant)); MessageSerializer.mapHandlers(MessageSignature.class, (buf, field) -> new MessageSignature(buf), (buf, field, signature) -> signature.write(buf)); MessageSerializer.mapHandlers(LastSeenMessages.Update.class, (buf, field) -> new LastSeenMessages.Update(buf), (buf, field, update) -> update.write(buf)); + MessageSerializer.mapHandlers(BitSet.class, (buf, field) -> BitSet.valueOf(buf.readLongArray()), (buf, field, bitSet) -> buf.writeLongArray(bitSet.toLongArray())); network = new NetworkHandler(Quark.MOD_ID, PROTOCOL_VERSION); @@ -60,12 +53,32 @@ public static void setup() { // Experimental network.register(PlaceVariantUpdateMessage.class, NetworkDirection.PLAY_TO_SERVER); - + // Clientbound network.register(DoEmoteMessage.class, NetworkDirection.PLAY_TO_CLIENT); network.register(EditSignMessage.class, NetworkDirection.PLAY_TO_CLIENT); network.register(UpdateTridentMessage.class, NetworkDirection.PLAY_TO_CLIENT); + // Flag Syncing + network.register(S2CUpdateFlag.class, NetworkDirection.PLAY_TO_CLIENT); + network.register(C2SUpdateFlag.class, NetworkDirection.PLAY_TO_SERVER); + loginIndexedBuilder(S2CLoginFlag.class, 98, NetworkDirection.LOGIN_TO_CLIENT) + .decoder(S2CLoginFlag::new) + .buildLoginPacketList(S2CLoginFlag::generateRegistryPackets) + .add(); + loginIndexedBuilder(C2SLoginFlag.class, 99, NetworkDirection.LOGIN_TO_SERVER) + .decoder(C2SLoginFlag::new) + .noResponse() + .add(); + } + + private static SimpleChannel.MessageBuilder loginIndexedBuilder(Class clazz, int id, NetworkDirection direction) { + return network.channel.messageBuilder(clazz, id, direction) + .loginIndex(HandshakeMessage::getLoginIndex, HandshakeMessage::setLoginIndex) + .encoder(HandshakeMessage::encode) + .consumerNetworkThread((msg, context) -> { + return msg.consume(context.get(), network.channel::reply); + }); } public static void sendToPlayer(IMessage msg, ServerPlayer player) { diff --git a/src/main/java/vazkii/quark/base/network/message/structural/C2SLoginFlag.java b/src/main/java/vazkii/quark/base/network/message/structural/C2SLoginFlag.java new file mode 100644 index 0000000000..85da95b290 --- /dev/null +++ b/src/main/java/vazkii/quark/base/network/message/structural/C2SLoginFlag.java @@ -0,0 +1,33 @@ +package vazkii.quark.base.network.message.structural; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent; +import vazkii.quark.base.module.sync.SyncedFlagHandler; + +import java.util.BitSet; +import java.util.function.BiConsumer; + +public class C2SLoginFlag extends HandshakeMessage { + + public BitSet flags; + + public C2SLoginFlag() { + flags = SyncedFlagHandler.compileFlagInfo(); + } + + public C2SLoginFlag(FriendlyByteBuf buf) { + this.flags = BitSet.valueOf(buf.readLongArray()); + } + + @Override + public void encode(FriendlyByteBuf buf) { + buf.writeLongArray(flags.toLongArray()); + } + + @Override + public boolean consume(NetworkEvent.Context context, BiConsumer reply) { + SyncedFlagHandler.receiveFlagInfoFromPlayer(context.getSender(), flags); + return true; + } + +} diff --git a/src/main/java/vazkii/quark/base/network/message/structural/C2SUpdateFlag.java b/src/main/java/vazkii/quark/base/network/message/structural/C2SUpdateFlag.java new file mode 100644 index 0000000000..0b1458c249 --- /dev/null +++ b/src/main/java/vazkii/quark/base/network/message/structural/C2SUpdateFlag.java @@ -0,0 +1,34 @@ +package vazkii.quark.base.network.message.structural; + +import net.minecraftforge.network.NetworkEvent; +import vazkii.arl.network.IMessage; +import vazkii.quark.base.module.sync.SyncedFlagHandler; + +import java.io.Serial; +import java.util.BitSet; + +public class C2SUpdateFlag implements IMessage { + + @Serial + private static final long serialVersionUID = 7483741039149504284L; + + public BitSet flags; + + @Override + public boolean receive(NetworkEvent.Context context) { + SyncedFlagHandler.receiveFlagInfoFromPlayer(context.getSender(), flags); + return true; + } + + public C2SUpdateFlag() { + // NO-OP + } + + private C2SUpdateFlag(BitSet flags) { + this.flags = flags; + } + + public static C2SUpdateFlag createPacket() { + return new C2SUpdateFlag(SyncedFlagHandler.compileFlagInfo()); + } +} diff --git a/src/main/java/vazkii/quark/base/network/message/structural/HandshakeMessage.java b/src/main/java/vazkii/quark/base/network/message/structural/HandshakeMessage.java new file mode 100644 index 0000000000..2b4d469647 --- /dev/null +++ b/src/main/java/vazkii/quark/base/network/message/structural/HandshakeMessage.java @@ -0,0 +1,29 @@ +package vazkii.quark.base.network.message.structural; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent; + +import java.util.function.BiConsumer; +import java.util.function.IntSupplier; + +// Not an IMessage to avoid serializing things like loginIndex +public abstract class HandshakeMessage implements IntSupplier { + private int loginIndex; + + public void setLoginIndex(final int loginIndex) { + this.loginIndex = loginIndex; + } + + public int getLoginIndex() { + return loginIndex; + } + + @Override + public int getAsInt() { + return loginIndex; + } + + public abstract void encode(FriendlyByteBuf buf); + + public abstract boolean consume(NetworkEvent.Context context, BiConsumer reply); +} diff --git a/src/main/java/vazkii/quark/base/network/message/structural/S2CLoginFlag.java b/src/main/java/vazkii/quark/base/network/message/structural/S2CLoginFlag.java new file mode 100644 index 0000000000..1a2ae3b68b --- /dev/null +++ b/src/main/java/vazkii/quark/base/network/message/structural/S2CLoginFlag.java @@ -0,0 +1,42 @@ +package vazkii.quark.base.network.message.structural; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent; +import org.apache.commons.lang3.tuple.Pair; +import vazkii.quark.base.module.sync.SyncedFlagHandler; + +import java.util.BitSet; +import java.util.Collections; +import java.util.List; +import java.util.function.BiConsumer; + +public class S2CLoginFlag extends HandshakeMessage { + + public BitSet flags; + + public S2CLoginFlag() { + flags = SyncedFlagHandler.compileFlagInfo(); + } + + public S2CLoginFlag(FriendlyByteBuf buf) { + this.flags = BitSet.valueOf(buf.readLongArray()); + } + + @Override + public void encode(FriendlyByteBuf buf) { + buf.writeLongArray(flags.toLongArray()); + } + + public static List> generateRegistryPackets(boolean isLocal) { + return !isLocal ? + Collections.singletonList(Pair.of(S2CLoginFlag.class.getName(), new S2CLoginFlag())) : + Collections.emptyList(); + } + + @Override + public boolean consume(NetworkEvent.Context context, BiConsumer reply) { + SyncedFlagHandler.receiveFlagInfoFromServer(flags); + reply.accept(new C2SLoginFlag(), context); + return true; + } +} diff --git a/src/main/java/vazkii/quark/base/network/message/structural/S2CUpdateFlag.java b/src/main/java/vazkii/quark/base/network/message/structural/S2CUpdateFlag.java new file mode 100644 index 0000000000..ca0431de46 --- /dev/null +++ b/src/main/java/vazkii/quark/base/network/message/structural/S2CUpdateFlag.java @@ -0,0 +1,34 @@ +package vazkii.quark.base.network.message.structural; + +import net.minecraftforge.network.NetworkEvent; +import vazkii.arl.network.IMessage; +import vazkii.quark.base.module.sync.SyncedFlagHandler; + +import java.io.Serial; +import java.util.BitSet; + +public class S2CUpdateFlag implements IMessage { + + @Serial + private static final long serialVersionUID = 2346906475290526858L; + + public BitSet flags; + + @Override + public boolean receive(NetworkEvent.Context context) { + SyncedFlagHandler.receiveFlagInfoFromServer(flags); + return true; + } + + public S2CUpdateFlag() { + // NO-OP + } + + private S2CUpdateFlag(BitSet flags) { + this.flags = flags; + } + + public static S2CUpdateFlag createPacket() { + return new S2CUpdateFlag(SyncedFlagHandler.compileFlagInfo()); + } +} diff --git a/src/main/java/vazkii/quark/base/proxy/ClientProxy.java b/src/main/java/vazkii/quark/base/proxy/ClientProxy.java index abbd8caf9b..7959d98c51 100644 --- a/src/main/java/vazkii/quark/base/proxy/ClientProxy.java +++ b/src/main/java/vazkii/quark/base/proxy/ClientProxy.java @@ -28,6 +28,8 @@ import vazkii.quark.base.handler.WoodSetHandler; import vazkii.quark.base.module.ModuleLoader; import vazkii.quark.base.module.config.IConfigCallback; +import vazkii.quark.base.network.QuarkNetwork; +import vazkii.quark.base.network.message.structural.C2SUpdateFlag; import vazkii.quark.mixin.client.accessor.AccessorMultiPlayerGameMode; import java.io.File; @@ -132,6 +134,7 @@ public void handleQuarkConfigChange() { super.handleQuarkConfigChange(); ModuleLoader.INSTANCE.configChangedClient(); + QuarkNetwork.sendToServer(C2SUpdateFlag.createPacket()); IngameConfigHandler.INSTANCE.refresh(); Minecraft mc = Minecraft.getInstance(); diff --git a/src/main/java/vazkii/quark/base/proxy/CommonProxy.java b/src/main/java/vazkii/quark/base/proxy/CommonProxy.java index 2a2d9cb069..b236c2ce0a 100644 --- a/src/main/java/vazkii/quark/base/proxy/CommonProxy.java +++ b/src/main/java/vazkii/quark/base/proxy/CommonProxy.java @@ -21,6 +21,7 @@ import vazkii.quark.base.handler.*; import vazkii.quark.base.module.ModuleLoader; import vazkii.quark.base.module.config.IConfigCallback; +import vazkii.quark.base.module.sync.SyncedFlagHandler; import vazkii.quark.base.network.QuarkNetwork; import vazkii.quark.base.recipe.*; import vazkii.quark.base.world.EntitySpawnHandler; @@ -103,6 +104,7 @@ public void registerCapabilities(RegisterCapabilitiesEvent event) { public void handleQuarkConfigChange() { ModuleLoader.INSTANCE.configChanged(); EntitySpawnHandler.refresh(); + SyncedFlagHandler.sendFlagInfoToPlayers(); } /** diff --git a/src/main/java/vazkii/quark/content/management/module/AutomaticToolRestockModule.java b/src/main/java/vazkii/quark/content/management/module/AutomaticToolRestockModule.java index 6832e228f6..64e4861a13 100644 --- a/src/main/java/vazkii/quark/content/management/module/AutomaticToolRestockModule.java +++ b/src/main/java/vazkii/quark/content/management/module/AutomaticToolRestockModule.java @@ -1,19 +1,8 @@ package vazkii.quark.content.management.module; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.Stack; -import java.util.WeakHashMap; -import java.util.function.Predicate; - import com.google.common.collect.Lists; import net.minecraft.core.Registry; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; @@ -34,19 +23,22 @@ import vazkii.arl.util.InventoryIIH; import vazkii.quark.addons.oddities.module.BackpackModule; import vazkii.quark.api.event.GatherToolClassesEvent; -import vazkii.quark.base.handler.GeneralConfig; import vazkii.quark.base.handler.MiscUtil; import vazkii.quark.base.module.LoadModule; import vazkii.quark.base.module.ModuleCategory; import vazkii.quark.base.module.ModuleLoader; import vazkii.quark.base.module.QuarkModule; import vazkii.quark.base.module.config.Config; +import vazkii.quark.base.module.sync.SyncedFlagHandler; + +import java.util.*; +import java.util.function.Predicate; @LoadModule(category = ModuleCategory.MANAGEMENT, hasSubscriptions = true, antiOverlap = "inventorytweaks") public class AutomaticToolRestockModule extends QuarkModule { private static final Map ACTION_TO_CLASS = new HashMap<>(); - + static { ACTION_TO_CLASS.put(ToolActions.AXE_DIG, "axe"); ACTION_TO_CLASS.put(ToolActions.HOE_DIG, "hoe"); @@ -56,7 +48,7 @@ public class AutomaticToolRestockModule extends QuarkModule { ACTION_TO_CLASS.put(ToolActions.SHEARS_HARVEST, "shears"); ACTION_TO_CLASS.put(ToolActions.FISHING_ROD_CAST, "fishing_rod"); } - + private static final WeakHashMap> replacements = new WeakHashMap<>(); public List importantEnchants = new ArrayList<>(); @@ -66,23 +58,28 @@ public class AutomaticToolRestockModule extends QuarkModule { description = "Enchantments deemed important enough to have special priority when finding a replacement") private List enchantNames = generateDefaultEnchantmentList(); - @Config(description = "Enable replacing your tools with tools of the same type but not the same item") + private static final String LOOSE_MATCHING = "automatic_restock_loose_matching"; + private static final String ENCHANT_MATCHING = "automatic_restock_enchant_matching"; + private static final String CHECK_HOTBAR = "automatic_restock_check_hotbar"; + private static final String UNSTACKABLES_ONLY = "automatic_restock_unstackables_only"; + + @Config(description = "Enable replacing your tools with tools of the same type but not the same item", flag = LOOSE_MATCHING) private boolean enableLooseMatching = true; - @Config(description = "Enable comparing enchantments to find a replacement") + @Config(description = "Enable comparing enchantments to find a replacement", flag = ENCHANT_MATCHING) private boolean enableEnchantMatching = true; - - @Config(description = "Allow pulling items from one hotbar slot to another") + + @Config(description = "Allow pulling items from one hotbar slot to another", flag = CHECK_HOTBAR) private boolean checkHotbar = false; - @Config + @Config(flag = UNSTACKABLES_ONLY) private boolean unstackablesOnly = false; @Config(description = "Any items you place in this list will be ignored by the restock feature") private List ignoredItems = Lists.newArrayList("botania:exchange_rod", "botania:dirt_rod", "botania:skydirt_rod", "botania:cobble_rod"); - + private Object mutex = new Object(); - + @Override public void configChanged() { importantEnchants = MiscUtil.massRegistryGet(enchantNames, ForgeRegistries.ENCHANTMENTS); @@ -95,66 +92,79 @@ public void onToolBreak(PlayerDestroyItemEvent event) { ItemStack stack = event.getOriginal(); Item item = stack.getItem(); - if(player != null && player.level != null && !player.level.isClientSide && !stack.isEmpty() && !(item instanceof ArmorItem) && (!unstackablesOnly || !stack.isStackable())) { - int currSlot = player.getInventory().selected; - if(event.getHand() == InteractionHand.OFF_HAND) - currSlot = player.getInventory().getContainerSize() - 1; - - List enchantmentsOnStack = getImportantEnchantments(stack); - Predicate itemPredicate = (other) -> other.getItem() == item; - if(!stack.isDamageableItem()) - itemPredicate = itemPredicate.and((other) -> other.getDamageValue() == stack.getDamageValue()); - - Predicate enchantmentPredicate = (other) -> !(new ArrayList<>(enchantmentsOnStack)).retainAll(getImportantEnchantments(other)); - - Set classes = getItemClasses(stack); - Optional> toolPredicate = Optional.empty(); - - if(!classes.isEmpty()) - toolPredicate = Optional.of((other) -> { - Set otherClasses = getItemClasses(other); - return !otherClasses.isEmpty() && !otherClasses.retainAll(classes); - }); - - RestockContext ctx = new RestockContext(player, currSlot, enchantmentsOnStack, itemPredicate, enchantmentPredicate, toolPredicate); - - int lower = checkHotbar ? 0 : 9; - int upper = player.getInventory().items.size(); - boolean foundInInv = crawlInventory(new PlayerInvWrapper(player.getInventory()), lower, upper, ctx); - - if(!foundInInv && ModuleLoader.INSTANCE.isModuleEnabled(BackpackModule.class)) { - ItemStack backpack = player.getInventory().armor.get(2); - - if(backpack.getItem() == BackpackModule.backpack) { - InventoryIIH inv = new InventoryIIH(backpack); - crawlInventory(inv, 0, inv.getSlots(), ctx); + if (player instanceof ServerPlayer serverPlayer) { + if (!SyncedFlagHandler.getFlagForPlayer(serverPlayer, "automatic_tool_restock")) + return; + + boolean onlyUnstackables = SyncedFlagHandler.getFlagForPlayer(serverPlayer, UNSTACKABLES_ONLY); + + if (!stack.isEmpty() && !(item instanceof ArmorItem) && (!onlyUnstackables || !stack.isStackable())) { + + boolean hotbar = SyncedFlagHandler.getFlagForPlayer(serverPlayer, CHECK_HOTBAR); + + int currSlot = player.getInventory().selected; + if (event.getHand() == InteractionHand.OFF_HAND) + currSlot = player.getInventory().getContainerSize() - 1; + + List enchantmentsOnStack = getImportantEnchantments(stack); + Predicate itemPredicate = (other) -> other.getItem() == item; + if (!stack.isDamageableItem()) + itemPredicate = itemPredicate.and((other) -> other.getDamageValue() == stack.getDamageValue()); + + Predicate enchantmentPredicate = (other) -> !(new ArrayList<>(enchantmentsOnStack)).retainAll(getImportantEnchantments(other)); + + Set classes = getItemClasses(stack); + Optional> toolPredicate = Optional.empty(); + + if (!classes.isEmpty()) + toolPredicate = Optional.of((other) -> { + Set otherClasses = getItemClasses(other); + return !otherClasses.isEmpty() && !otherClasses.retainAll(classes); + }); + + RestockContext ctx = new RestockContext(serverPlayer, currSlot, enchantmentsOnStack, itemPredicate, enchantmentPredicate, toolPredicate); + + int lower = hotbar ? 0 : 9; + int upper = player.getInventory().items.size(); + boolean foundInInv = crawlInventory(new PlayerInvWrapper(player.getInventory()), lower, upper, ctx); + + if (!foundInInv && ModuleLoader.INSTANCE.isModuleEnabled(BackpackModule.class)) { + ItemStack backpack = player.getInventory().armor.get(2); + + if (backpack.getItem() == BackpackModule.backpack) { + InventoryIIH inv = new InventoryIIH(backpack); + crawlInventory(inv, 0, inv.getSlots(), ctx); + } } } } } - + private boolean crawlInventory(IItemHandler inv, int lowerBound, int upperBound, RestockContext ctx) { - Player player = ctx.player; + ServerPlayer player = ctx.player; int currSlot = ctx.currSlot; List enchantmentsOnStack = ctx.enchantmentsOnStack; Predicate itemPredicate = ctx.itemPredicate; Predicate enchantmentPredicate = ctx.enchantmentPredicate; Optional> toolPredicateOpt = ctx.toolPredicate; - - if(enableEnchantMatching && findReplacement(inv, player, lowerBound, upperBound, currSlot, itemPredicate.and(enchantmentPredicate))) + + boolean enchantMatching = SyncedFlagHandler.getFlagForPlayer(player, ENCHANT_MATCHING); + boolean looseMatching = SyncedFlagHandler.getFlagForPlayer(player, LOOSE_MATCHING); + + if(enchantMatching && findReplacement(inv, player, lowerBound, upperBound, currSlot, itemPredicate.and(enchantmentPredicate))) return true; if(findReplacement(inv, player, lowerBound, upperBound, currSlot, itemPredicate)) return true; - if(enableLooseMatching && toolPredicateOpt.isPresent()) { + if(looseMatching && toolPredicateOpt.isPresent()) { Predicate toolPredicate = toolPredicateOpt.get(); - if(enableEnchantMatching && !enchantmentsOnStack.isEmpty() && findReplacement(inv, player, lowerBound, upperBound, currSlot, toolPredicate.and(enchantmentPredicate))) + if(enchantMatching && !enchantmentsOnStack.isEmpty() && findReplacement(inv, player, lowerBound, upperBound, currSlot, toolPredicate.and(enchantmentPredicate))) return true; return findReplacement(inv, player, lowerBound, upperBound, currSlot, toolPredicate); } - + return false; } @@ -173,22 +183,22 @@ public void onPlayerTick(PlayerTickEvent event) { private HashSet getItemClasses(ItemStack stack) { Item item = stack.getItem(); - + HashSet classes = new HashSet<>(); if(item instanceof BowItem) classes.add("bow"); - + else if(item instanceof CrossbowItem) classes.add("crossbow"); - + for(ToolAction action : ACTION_TO_CLASS.keySet()) { if(item.canPerformAction(stack, action)) classes.add(ACTION_TO_CLASS.get(action)); } - + GatherToolClassesEvent event = new GatherToolClassesEvent(stack, classes); MinecraftForge.EVENT_BUS.post(event); - + return classes; } @@ -221,7 +231,7 @@ private void switchItems(Player player, QueuedRestock restock) { int providingSlot = restock.providingSlot; int playerSlot = restock.playerSlot; - + if(providingSlot >= providingInv.getSlots() || playerSlot >= playerInv.items.size()) return; @@ -234,7 +244,7 @@ private void switchItems(Player player, QueuedRestock restock) { providingInv.extractItem(providingSlot, stackProvidingSlot.getCount(), false); providingInv.insertItem(providingSlot, stackAtPlayerSlot, false); - + playerInv.setItem(playerSlot, stackProvidingSlot); } @@ -261,18 +271,18 @@ private static List generateDefaultEnchantmentList() { }; List strings = new ArrayList<>(); - for(Enchantment e : enchants) + for(Enchantment e : enchants) strings.add(Registry.ENCHANTMENT.getKey(e).toString()); return strings; } - - private record RestockContext(Player player, int currSlot, - List enchantmentsOnStack, - Predicate itemPredicate, + + private record RestockContext(ServerPlayer player, int currSlot, + List enchantmentsOnStack, + Predicate itemPredicate, Predicate enchantmentPredicate, Optional> toolPredicate) {} - + private record QueuedRestock(IItemHandler providingInv, int providingSlot, int playerSlot) {} } diff --git a/src/main/resources/assets/quark/lang/pt_pt.json b/src/main/resources/assets/quark/lang/pt_pt.json index fb7de563a5..5ccc2f5357 100644 --- a/src/main/resources/assets/quark/lang/pt_pt.json +++ b/src/main/resources/assets/quark/lang/pt_pt.json @@ -32,7 +32,6 @@ "quark.gui.config.social.website": "Quark Website", "quark.gui.config.social.discord": "Quark/Violet Moon Discord", "quark.gui.config.social.patreon": "Patreon de Vazkii", - "quark.gui.config.social.reddit": "/r/QuarkMod Reddit", "quark.gui.config.social.twitter": "@VazkiiMods Twitter", "quark.gui.config.header": "%s Configuração", "quark.gui.config.subheader1": "Quark é possível graças ao apoio de %s%s%s e outras pessoas.", @@ -49,9 +48,14 @@ "quark.gui.celebration.vm": "Feliz aniversário, Violet Moon!", "quark.gui.celebration.minecraft": "Feliz aniversário, Minecraft!", - "quark.gui.celebration.vns": "Feliz aniversário, MCVinnyq e Sully!", - "quark.gui.celebration.vazkii": "Feliz aniversário, Vazkii!", - "quark.gui.celebration.wire": "Feliz aniversário, Wire Segal!", + "quark.gui.celebration.vns": "Feliz aniversário a MCVinnyq e Sully!", + "quark.gui.celebration.vazkii": "Feliz aniversário a Vazkii!", + "quark.gui.celebration.wire": "Feliz aniversário a Wire Segal!", + "quark.gui.celebration.anb": "Feliz aniversário a AmyMialee e DJBaphomet!", + "quark.gui.celebration.kame": "Feliz aniversário a Kamefrede!", + "quark.gui.celebration.adrian": "Feliz aniversário a Adrian!", + "quark.gui.celebration.train": "Feliz aniversário a Train!", + "quark.gui.celebration.zemmy": "Feliz aniversário a Zemmy!", "quark.gui.celebration.iad": "Feliz Dia Internacional da Assexualidade!", "quark.gui.celebration.iad2": "Feliz Dia de Consciencialização Intersexo!", @@ -78,6 +82,8 @@ "quark.gui.celebration.wwd": "Feliz Dia Mundial da Vida Selvagem!", "quark.gui.celebration.hrd": "Feliz Dia dos Direitos Humanos!", "quark.gui.celebration.ny": "Feliz Ano Novo!", + + "quark.gui.celebration.edballs": "Ed Balls", "quark.gui.celebration.doyouremember": "Do you remember?", "quark.category.general": "Definições Gerais", @@ -93,13 +99,29 @@ "quark.category.oddities": "Curiosidades", "quark.category.experimental": "Experimental", + "_quark.config.tl_note1": "Additional translation keys for config elements can be added here", + "_quark.config.tl_note2": "The format is quark.config.[(category).]+.(name).", + "_quark.config.tl_note3": "where (name) is lower case, with spaces replaced with underscores, and all non alphanumerical characters stripped", + "_quark.config.tl_note4": "Any non localized entries will revert to the default english values in the config", + "_quark.config.tl_note5": "This localization is only for the ingame viewer, and will not affect the config file. Additional .descs can be added at will", + "_quark.config.tl_note6": "Descriptions can be removed by translating them to an empty key, if desired. Use \n to split lines", + "_quark.config.tl_note7": "See below for examples (with the key prefixed by _) so it doesnt load ingame:", + "_quark.config.tl_note8": "If you use IntelliJ the Minecraft Dev Plugin will assist you in this by adding entries automatically from en_us.json", + + "_quark.config.automation.feeding_trough.name": "Test 100", + "_quark.config.automation.feeding_trough.desc": "Yeah I'm testing\nWith multiple lines too!", + "_quark.config.automation.feeding_trough.max_animals.name": "Testeroni", + "_quark.config.automation.feeding_trough.max_animals.desc": "Testerino with one line", + "_quark.config.automation.feeding_trough.love_chance.name": "This do be a test doe", + "_quark.config.automation.feeding_trough.love_chance.desc": "", + "quark.camera.filter": "Filtrar: ", "quark.camera.filter.none": "Nehnum", - "quark.camera.filter.grayscale": "Grayscale", - "quark.camera.filter.monochrome": "Monochrome", + "quark.camera.filter.grayscale": "Escala de cinzento", + "quark.camera.filter.monochrome": "Monocromático", "quark.camera.filter.sepia": "Sépia", - "quark.camera.filter.desaturate": "Desaturar", - "quark.camera.filter.oversaturate": "Oversaturar", + "quark.camera.filter.desaturate": "Desaturado", + "quark.camera.filter.oversaturate": "Sobresaturado", "quark.camera.filter.cool": "Frio", "quark.camera.filter.warm": "Quente", "quark.camera.filter.conjugate": "Conjugado", @@ -152,6 +174,135 @@ "quark.jei.influence": "Influência de Matrix", "quark.jei.boost_influence": "Melhora probabilidades de:", "quark.jei.dampen_influence": "Diminui probabilidades de:", + "quark.jei.hint_preamble": "[Quark]\n", + + "quark.jei.hint.pickarang": "É uma picareta boomerang! Pode ser atirado e vai minar tudo o que atingir e trazer os drops de volta. Também pode ser encantado para um melhor desempenho.", + "quark.jei.hint.flamerang": "Funciona como um Pickarang, mas todos os objetos que apanha tornam-se imunes a danos de fogo e lava enquanto viajam.", + "quark.jei.hint.echorang": "Funciona como um Pickarang, mas emite vibrações constantes e aumenta o seu tempo de voo se ouvir um alarme de sculk.", + "quark.jei.hint.abacus": "Utiliza este botão num bloco e ele conta a distância entre o bloco que estás a ver e aquele em que clicaste, até 48 blocos.", + "quark.jei.hint.ancient_fruit": "Cai de árvores ancestrais quando estas são cortadas. Dá-te uma pequena quantidade de XP quando comido.", + "quark.jei.hint.ancient_sapling": "Pode ser encontrado nos baús da cidade ancestral.", + "quark.jei.hint.backpack": "Equipa isto para ganhar mais três filas de espaço no inventário.", + "quark.jei.hint.blackstone_furnace": "Se o bloco por baixo desta fornalha produzir fogo das almas quando aceso, a fornalha também o fará.", + "quark.jei.hint.blaze_lantern": "Arde para sempre, tal como netherrack.", + "quark.jei.hint.blue_blossom_sapling": "Pode ser encontrado em biomas frios.", + "quark.jei.hint.bottled_cloud": "Obtém-se usando uma garrafa de vidro ao nível das nuvens. Pode ser clicado com o botão direito do rato no ar para criar um bloco temporário sobre o qual podem ser colocados outros blocos.", + "quark.jei.hint.charcoal_block": "Arde para sempre, tal como netherrack.", + "quark.jei.hint.chute": "Ejeta todos os objetos alimentados por um funil/ejetor para baixo.", + "quark.jei.hint.dragon_scale": "Cai do dragão do ender em qualquer morte além da primeira.", + "quark.jei.hint.ender_watcher": "Emite um sinal de redstone com base em quão perto do centro do olho o jogador está a olhar.", + "quark.jei.hint.music_disc_endermosh": "Pode ser encontrado em baús na cidade do End.", + "quark.jei.hint.forgotten_hat": "Cai dos esqueçidos, que podem ser encontrados nas profundezas do subsolo. Tem cuidado com o seu equipamento poderoso e os seus múltiplos estilos de combate.", + "quark.jei.hint.feeding_trough": "Animais podem comer comidas aqui colocadas e reproduzir-se a partir delas. Por vezes, podem comer em excesso, não se reproduzem se houver demasiados por perto e não produzem XP.", + "quark.jei.hint.glass_item_frame": "Oculta a moldura quando um item é colocado no interior para mostrar apenas o item. Tem um comportamento personalizado para estandartes e escudos, e pode ficar nivelado com uma tabuleta que esteja no chão. Também pode ser clicado com o botão direito do rato para abrir qualquer inventário por trás dele.", + "quark.jei.hint.glowing_glass_item_frame": "Versão brilhante de uma moldura de vidro - tem todas as mesmas propriedades.", + "quark.jei.hint.glow_lichen_growth": "Encontrado no raro bioma de Cervura Cintilante, nas profundezas do subsolo.", + "quark.jei.hint.glow_shroom": "Encontrado no raro bioma de caverna de cogumelos brilhantes, nas profundezas do subsolo. Farinha de osso pode ser utilizada para criar uma grande variante.", + "quark.jei.hint.gold_button": "Emite um impulso muito curto, de 2 tiques de redstone.", + "quark.jei.hint.golden_apple_crate": "Pode ser usado como base para sinalizadores.", + "quark.jei.hint.gravisand": "Só cai quando recebe um sinal de redstone, levando consigo as pedras adjacentes. Se não poder cair, flutua para cima. Emits a comparator signal of 15.", + "quark.jei.hint.diamond_heart": "Pode ser obtido ao partir a carapaça de um Stoneling no subsolo. Não te preocupes - o Stoneling está bem. O corpo é apenas uma carapaça à volta do coração! Se vires uma pequena criatura a segurar um objeto, essa é ele! Aproxima-te sorrateiramente para que ele não repare em ti, ou usa um cogumelo brilhante para o atrair. Se usares o coração numa pedra, o Stoneling construirá um novo corpo a partir dela, e ficará mais confortável com os jogadores depois de ter estado no teu inventário.", + "quark.jei.hint.iron_button": "Emite um impulso muito longo, de 5 segundos.", + "quark.jei.hint.grate": "Os animais que não tenham coleira não andam por aqui e objetos vão passar por isto.", + "quark.jei.hint.iron_rod": "Parte todos os blocos à sua frente quando empurrado com um pistão.", + "quark.jei.hint.jasper": "Pode ser encontrado em grandes grupos em terras áridas e desertos.", + "quark.jei.hint.lavender_blossom_sapling": "Pode ser encontrado em pântanos.", + "quark.jei.hint.limestone": "Pode ser encontrado em grandes grupos em pântanos e oceanos.", + "quark.jei.hint.myalite": "Pode ser encontrado em grandes aglomerados nas terras altas do extremo exterior. A sua cor muda consoante o local onde é colocado.", + "quark.jei.hint.orange_blossom_sapling": "Pode ser encontrado em savanas.", + "quark.jei.hint.pathfinders_quill": "Pode ser usado para encontrar o bioma nele inscrito. Troca-o com cartógrafos ou vendedores ambulantes.", + "quark.jei.hint.permafrost": "Pode ser encontrado no topo de picos congelados.", + "quark.jei.hint.pink_blossom_sapling": "Poder ser encontrado em montanhas.", + "quark.jei.hint.ravager_hide": "Cai de devastadores em invasões.", + "quark.jei.hint.red_blossom_sapling": "Poder ser encontrado nas terras áridas.", + "quark.jei.hint.redstone_randomizer": "Repete aleatoriamente o sinal dado para a esquerda ou para a direita.", + "quark.jei.hint.rope": "Deve ser colocada no teto e pode ser escalada. Pode ser clicado com o botão direito do rato sobre outra bobina de corda para descer ou puxar para cima enquanto se esgueira. Pode deslocar o bloco que se encontra no borda.", + "quark.jei.hint.seed_pouch": "Pode conter uma série de sementes ou rebentos, bastando clicar com o botão direito do rato para os colocar e retirar. A bolsa também pode apanhar automaticamente sementes se a estiveres a segurar, ou colocar áreas de 3x3 usando-a num bloco.", + "quark.jei.hint.shale": "Pode ser encontrado em grandes grupos em biomas frios.", + "quark.jei.hint.slime_in_a_bucket": "Usa um balde num pequeno slime para o apanhares. Ele começará a saltar para o balde quando estiver dentro de um chunk de slime.", + "quark.jei.hint.soul_bead": "Cai de Wraiths em vales de areia das almas. Quando usado, voa em direção à fortaleza do Nether mais próxima.", + "quark.jei.hint.sturdy_stone": "Não pode ser movido por pistões.", + "quark.jei.hint.tiny_potato": "Acredita em ti!", + "quark.jei.hint.torch_arrow": "Tentará colocar uma tocha onde quer que ela caia.", + "quark.jei.hint.trowel": "Coloca aleatoriamente um bloco da tua barra de atalho quando utilizado. Podes ter o mesmo bloco em várias ranhuras para aumentar as tuas probabilidades.", + "quark.jei.hint.yellow_blossom_sapling": "Pode ser encontrado em planícies.", + "quark.jei.hint.ancient_tome": "Pode melhorar o encantamento de um item ou livro em um nível, até um acima do limite normal. Raramente encontrado em masmorras ou fortalezas.", + "quark.jei.hint.hollow_logs": "Pode rastejar-se enquanto se caminha para o lado oco, mas também se pode trepar quando se está lá dentro.", + "quark.jei.hint.skull_pikes": "Quando colocado sobre uma cerca, os monstros simples que andam por perto assustam-se e fogem.", + "quark.jei.hint.pottable_stuff": "Pode agora ser adicionado a um vaso.", + "quark.jei.hint.stools": "Pode sentar-se e mantém-se sentado quando movido por um pistão. Colocando um bloco em cima, o banco transforma-se numa mesa.", + "quark.jei.hint.posts": "Pode ser colocado em qualquer eixo. As correntes e as lanternas podem ligar-se a este bloco.", + "quark.jei.hint.soul_fire_candles": "Quando colocado em qualquer bloco que possa produzir fogo das almas quando aceso, também o fará.", + "quark.jei.hint.wool_muffling": "Pode ser utilizado para silenciar carrinhos de mina se for colocado debaixo do carril.", + "quark.jei.hint.shulker_box_right_click": "Os itens podem ser clicados com o botão direito do rato na caixa de shulker, tal como se faz para uma bolsa.", + "quark.jei.hint.rotating_bundles": "Ao deslocar o cursor sobre uma bolsa, os itens são rodados.", + "quark.jei.hint.crab_info": "Os caranguejos podem ser encontrados nas praias e criados com trigo, galinha ou qualquer tipo de peixe.", + "quark.jei.hint.ambience_discs": "Os discos ambientais podem ser obtidos quando um esqueleto mata uma aranha. Ao contrário dos discos de música, estes repetem-se infinitamente.", + "quark.jei.hint.runes": "Combina numa bigorna com um item encantado para mudar a cor do seu brilho. Isto é puramente visual.", + "quark.jei.hint.parrot_eggs": "Jogar para criar um papagaio bebé. Alimente um papagaio com muitas sementes de beterraba até gostar de si e, depois de 10 minutos, ele vai chocar um.", + "quark.jei.hint.doors_open_together": "Ao criar uma porta dupla, estas abrem/fecham em conjunto.", + "quark.jei.hint.fence_gates_open_together": "Quando outro portão é colocado por cima ou por baixo deste, estes abrem ou fecham em conjunto.", + "quark.jei.hint.item_frame_dyeing": "Pode ser tingido da mesma forma que se tinge uma armadura de couro.", + "quark.jei.hint.gold_tool_fortune": "As Ferramentas de ouro vem com um efeito de fortuna %s ou pilhagem incorporado. Isto não se acumula com a versão de encantamento, apenas o mais alto será aplicado.", + "quark.jei.hint.gold_tool_harvest_level": "As ferramentas douradas têm agora um nível de colheita de %s", + "quark.jei.hint.hoe_harvesting": "As enxadas agora podem quebrar uma área de vegetação de 3 de largura de uma só vez. As enxadas de nível superior, como as de diamante ou netherite, podem partir 5.", + "quark.jei.hint.head_sfx": "Qualquer cabeça de monstro pode ser colocada na lateral de um bloco musical para emitir o seu som quando o bloco musical está ligado.", + "quark.jei.hint.sign_editing": "Os sinais podem ser editados clicando com o botão direito do rato sobre eles.", + "quark.jei.hint.chorus_weeds": "Spawnam invulgarmente nos pântanos do extremo exterior. Teletransportam-se aleatoriamente e reproduzem-se ao longo do tempo ou se forem forçados por pisoteio, farinha de ossos ou água adajcente. Pode também gerar Endermites quando pisado.", + "quark.jei.hint.corundum": "Pode ser encontrado no subsolo em grandes grupos de duas cores cada. Crescerão lentamente para cima se forem colocadas no subsolo. Pode ser encerado para evitar o crescimento e a emissão de partículas.", + "quark.jei.hint.crystal_lamp": "Estas lâmpadas só mudam a cor de um feixe de um sinalizador quando estão ligadas.", + "quark.jei.hint.snow_golem_player_heads": "Se uma bruxa matar um golem de neve nomeado, a cabeça de jogador correspondente ao nome do golem cairá.", + "quark.jei.hint.use_for_vanishing": "Se uma abóbora estiver encantada com maldição do desaparecimento, não mostrará a cobertura escura quando usada.", + "quark.jei.hint.use_for_binding": "Uma cabeça de jogador com a maldição da união pode ser colocada num suporte de armadura para mostrar o corpo completo do jogador.", + "quark.jei.hint.pipe": "Move os objetos colocados com um funil/dispensador ou equivalente, ou através da forma de um objeto largado numa borda. Os objetos preferem cair para baixo, depois para a frente, depois aleatoriamente para os lados e só depois para cima. Os objetos que entram num contentor cheio voltam para trás. Qualquer cano pode ser desativado com um sinal de Redstone, e a quantidade de objetos num cano pode ser lida com um comparador de redstone. Os canos com mais de 16 objetos vão partir.", + "quark.jei.hint.magnet": "Pode empurrar e puxar qualquer bloco de cobre ou ferro quando ativado, dependendo do lado. Se vários ímanes estiverem a mover o mesmo bloco, a maior força vencerá. A força de um íman sobre um bloco é o sinal de redstone que lhe é dado menos a distância ao bloco. Os funis movidos com um íman deixam cair um objeto na frente por cada bloco movido. Se o item for uma semente, ele tentará plantá-la. Os cortadores de pedras movidos com um íman tentarão partir o bloco que está por cima deles.", + "quark.jei.hint.dusky_myalite": "Can be found embeded in Spiral Spires around the outer end.", + + "quark.jei.hint.banner_layer_buff": "Estandartes foram atualizados para terem até %d camadas.", + "quark.jei.hint.crate": "Pode conter até %d itens, independentemente do tamanho da pilha. Não é muito bom para armazenamento em massa, mas é fantástico para itens não empilháveis ou uma grande variedade de itens aleatórios.", + "quark.jei.hint.piston_te": "Agora é possível empurrar blocos complexos (também conhecidos como entidades de mosaico), exceto os geradores de monstros.", + "quark.jei.hint.piston_sturdy": "Experimente a pedra resistente se precisar de um bloco inamovível para uma máquina.", + "quark.jei.hint.piston_max_blocks": "A quantidade máxima de blocos que podem ser movidos também foi alterada para %d.", + "quark.jei.hint.beacon_redirection": "O feixe do sinalizador pode ser redirecionado com %s, colocando-o no caminho do feixe. Note que o último deve estar sempre virado para o céu e que o feixe tem uma distância horizontal limitada que pode cobrir.", + "quark.jei.hint.beacon_amethyst": "Ametista", + "quark.jei.hint.beacon_corundum": "Coríndo", + "quark.jei.hint.compass_nether": "Pode funcionar no Nether, apontando para o portal por onde entrou.", + "quark.jei.hint.compass_end": "Pode funcionar no End, apontando para o portal de saída.", + "quark.jei.hint.compass_nerf": "Deve ser criado antes de fazer qualquer coisa para evitar o facilitamento do livro de receitas.", + "quark.jei.hint.ladder_dropping": "Pode ser clicado com o botão direito do rato sobre outra escada para a fazer descer.", + "quark.jei.hint.ladder_freestanding": "Desde que haja um bloco estruturalmente sólido por trás, pode ficar de pé sem qualquer bloco por trás.", + "quark.jei.hint.ladder_sliding": "Olhar para baixo enquanto está numa escada fá-lo-á descer mais depressa.", + "quark.jei.hint.ladder_sneak": "Abrir o seu inventário numa escada fará com que se esgueire automaticamente.", + "quark.jei.hint.corundum_cluster_grow": "Cresce ao lado do respetivo coríndo, quer seja gerado naturalmente ou quando deixado a crescer.", + "quark.jei.hint.corundum_cluster_redirect": "Pode redirecionar feixes de Sinalizador, consulte o item Sinalizador para obter informações.", + "quark.jei.hint.myalite_crystal_get": "Pode ser encontrado no topo das espirais na extremidade exterior.", + "quark.jei.hint.myalite_crystal_viaduct": "Quando um enderman ou um jogador que usa uma pérola do ender se teletransporta adjacente a vários destes numa linha, acabará no outro extremo da linha. As divisões funcionam, mas os laços não.", + "quark.jei.hint.myalite_crystal_grow": "Pode ser cultivado colocando-o sob blocos de coríndo em crescimento.", + "quark.jei.hint.matrix_enchanting": "O encantamento agora usa um novo sistema de \"Encantamento de Matriz\". As peças podem ser geradas com lápis e XP e colocadas numa grelha. Duas peças do mesmo tipo podem ser unidas para melhorar o nível da peça. Para além disso, a mesa de encantamento pode agora guardar o teu item e o lápis nele contido, viva!", + "quark.jei.hint.matrix_influencing": "As velas também podem ser utilizadas para aumentar as probabilidades de encantamentos específicos.", + "quark.jei.hint.repair_item_removed": "Este item foi alterado para não poder ser reparado numa bigorna com materiais de reparação.", + "quark.jei.hint.repair_item_changed": "O material de reparação deste item numa bigorna foi alterado para %s.", + "quark.jei.hint.repair_item_changed_multiple": "O material de reparação deste item numa bigorna foi alterado para um dos seguintes %s.", + "quark.jei.hint.shiba_find_low_light": "Se tiveres uma lanterna na mão, os shibas indicam-te os pontos escuros que deves iluminar.", + + "quark.jei.hint.minecraft.clock": "Deve ser criado antes de fazer qualquer coisa para evitar o facilitamento do livro de receitas.", + "quark.jei.hint.minecraft.amethyst_block": "Pode ser colocado debaixo de um bloco de notas para emitir o som icónico da ametista.", + "quark.jei.hint.minecraft.shulker_shell": "Os baús podem ser convertidas em caixas de shulker sem as partir, bastando para isso usar duas casca de shulker de uma só vez - uma em cada mão.", + "quark.jei.hint.minecraft.calcite": "Outros grandes aglomerados de calcite são adicionados às montanhas.", + "quark.jei.hint.minecraft.chain": "Quando ligado a um bloco, se esse bloco for movido por um pistão, o mesmo acontecerá com a corrente e qualquer outra coisa na outra extremidade.", + "quark.jei.hint.minecraft.emerald_block": "Pode ser utilizado para fazer com que os aldeões o/a sigam, tal como os animais seguem os alimentos.", + "quark.jei.hint.minecraft.jukebox": "Utilize um dispensador para colocar discos na jukebox para reproduzir música automaticamente.", + "quark.jei.hint.minecraft.magma_cream": "Um slime que morra com magma vai dividir-se em cubos de magma. Nota que os cubos de magma pequenos não deixam cair creme de magma.", + "quark.jei.hint.minecraft.poisonous_potato": "Quando se dá de comer a um animal bebé, há a possibilidade de o envenenar. Se o animal for envenenado, nunca se tornará num adulto.", + "quark.jei.hint.minecraft.scaffolding": "Clicar com o botão direito do rato no andaime com qualquer bloco substitui a peça de andaime mais afastada pelo bloco. Esgueira-se para usar a colocação normal.", + "quark.jei.hint.minecraft.sponge": "Pode agora ser colocado em água.", + "quark.jei.hint.minecraft.spore_blossom": "Pode agora ser renovado com farinha de ossos.", + "quark.jei.hint.minecraft.vine": "A tesoura pode agora ser usada para cortar a ponta da videira para evitar que continue a crescer.", + "quark.jei.hint.minecraft.campfire": "Impulsiona os jogadores que voam com élitros por cima mais para cima.", + "quark.jei.hint.minecraft.soul_campfire": "Puxa para o chão os jogadores que voam com élitros por cima.", + "quark.jei.hint.minecraft.tinted_glass": "Pode ser utilizado para tornar os feixes dos sinalizadores mais fracos, colocando o bloco no caminho. Vários blocos podem ser empilhados.", + "quark.jei.hint.minecraft.lava_bucket": "Clique com o botão direito do mouse em um item do seu inventário no balde de lava para destruí-lo para sempre! As caixas de shulker e os objetos imunes ao fogo, como a netherite, não podem ser destruídos desta forma.", + "quark.jei.hint.minecraft.armor_stand": "Agora tem braços, o que permite segurar um item e um escudo.", "quark.keybind.change_hotbar": "Trocador de Hotbar", "quark.keybind.lock_rotation": "Trava de Rotação", @@ -218,6 +369,7 @@ "quark.subtitles.pipe_pickup": "Cano absorve", "quark.subtitles.pipe_shoot_lenny": "Pipe nuts", "quark.subtitles.pipe_pickup_lenny": "Pipe succ", + "quark.subtitles.bucket.fill_crab": "Crab grabbed", "quark.subtitles.do_it": "DO IT", "quark.subtitles.soda": "SODA !!", "quark.subtitles.kingbdogz": "Kingbdogz", @@ -275,7 +427,10 @@ "quark.misc.mod_disabled": "Desativado. Instala %s para ativar.", "quark.misc.repaired": "(Foi Reparado)", "quark.misc.celebration": "Celebrando 10 Anos de Vazkii's Mods (2021)", + "quark.misc.enchantment_with_actual_level": "%s (%s)", "quark.misc.ancient_tome_tooltip": "+I %s (Máximo. %s)", + "quark.misc.ancient_tome_tooltip_curse": "Aplica uma maldição á sorte", + "quark.misc.ancient_tome_tooltip_any": "(Qualquer Encantamento)", "quark.misc.autowalking": "Auto-Andar", "quark.misc.rightclick_to_craft": "Clique direito para fazer", "quark.misc.opened_screen": "Abriu Ecrã %s", @@ -290,6 +445,12 @@ "quark.misc.my_children": "Nunca mais fale comigo ou com as minhas crianças.", "quark.misc.shared_item": "%s partilhou um item: ", "quark.misc.configure_quark_here": "Configura o Quark Aqui!", + "quark.misc.only_one_quill": "A pena do explorador já está a procurar...", + "quark.misc.quill_finished": "O mapa do explorador foi completado.", + "quark.misc.quill_failed": "A pena do explorador não conseguiu encontrar nenhum bioma nas proximidades.", + "quark.misc.quill_retry": "A pena do explorador não conseguiu encontrar nenhum bioma nas proximidades. Tenta noutro luga.", + "quark.misc.quill_blank": "Em branco", + "quark.misc.quill_searching": "Á procura", "quark.misc.you_came_to_the_wrong_neighborhood.0": "Six letter word just to get me along", "quark.misc.you_came_to_the_wrong_neighborhood.1": "It's a intricacy and I'm coding on my mod and I,", @@ -315,7 +476,7 @@ "quark.container.feeding_trough": "Comedouro", - "item.quark.trowel": "Pazinha", + "item.quark.trowel": "Pázinha", "item.quark.slime_in_a_bucket": "Balde de Slime", "item.quark.slime_in_a_bucket.named": "Balde de %s", "item.quark.black_shard": "Estilhaço de vidro preto", @@ -338,27 +499,28 @@ "item.quark.dirty_shard": "Estilhaço de vidro sujo", "item.quark.glass_item_frame": "Moldura de vidro", "item.quark.glowing_glass_item_frame": "Moldura de vidro brilhante", - "item.quark.black_rune": "Runa preta", - "item.quark.blue_rune": "Runa azul", - "item.quark.brown_rune": "Runa castanha", - "item.quark.cyan_rune": "Runa ciano", - "item.quark.gray_rune": "Runa cinzento", - "item.quark.green_rune": "Runa verde", - "item.quark.light_blue_rune": "Runa azul-clara", - "item.quark.light_gray_rune": "Runa cinzento-clara", - "item.quark.lime_rune": "Runa verde-lima", - "item.quark.magenta_rune": "Runa magenta", - "item.quark.orange_rune": "Runa laranja", - "item.quark.pink_rune": "Runa rosa", - "item.quark.purple_rune": "Runa roxa", - "item.quark.red_rune": "Runa vermelha", - "item.quark.white_rune": "Runa branca", - "item.quark.yellow_rune": "Runa amarela", - "item.quark.rainbow_rune": "Runa arco-íris", - "item.quark.blank_rune": "Runa em branco", + "item.quark.black_rune": "Runa preta", + "item.quark.blue_rune": "Runa azul", + "item.quark.brown_rune": "Runa castanha", + "item.quark.cyan_rune": "Runa ciano", + "item.quark.gray_rune": "Runa cinzento", + "item.quark.green_rune": "Runa verde", + "item.quark.light_blue_rune": "Runa azul-clara", + "item.quark.light_gray_rune": "Runa cinzento-clara", + "item.quark.lime_rune": "Runa verde-lima", + "item.quark.magenta_rune": "Runa magenta", + "item.quark.orange_rune": "Runa laranja", + "item.quark.pink_rune": "Runa rosa", + "item.quark.purple_rune": "Runa roxa", + "item.quark.red_rune": "Runa vermelha", + "item.quark.white_rune": "Runa branca", + "item.quark.yellow_rune": "Runa amarela", + "item.quark.rainbow_rune": "Runa arco-íris", + "item.quark.blank_rune": "Runa em branco", "item.quark.pickarang": "Pickarang", "item.quark.diamond_heart": "Coração de diamante", "item.quark.ancient_tome": "Tomo ancestral", + "item.quark.crab_bucket": "Balde de canranguejo", "item.quark.crab_leg": "Perna de caranguejo crua", "item.quark.cooked_crab_leg": "Perna de caranguejo cozida", "item.quark.crab_shell": "Carapaça de caranguejo", @@ -401,25 +563,28 @@ "item.quark.music_disc_crickets.desc": "Cricket Song", "item.quark.music_disc_chatter": "Disco ambiental", "item.quark.music_disc_chatter.desc": "Packed Venue", - "item.quark.saw": "Serra de Sculk (NYI)", + "item.quark.torch_arrow": "Flecha de tocha", + "item.quark.ancient_boat": "Barco ancestral", + "item.quark.ancient_chest_boat": "Barco ancestral com baú", + "item.quark.ancient_fruit": "Fruta ancestral", + "item.quark.pathfinders_quill": "Pena do explorador", "item.minecraft.potion.effect.quark.resilience": "Poção de estabilidade", "item.minecraft.splash_potion.effect.quark.resilience": "Poção arremessável de estabilidade", "item.minecraft.lingering_potion.effect.quark.resilience": "Poção prolongada de estabilidade", "item.minecraft.tipped_arrow.effect.quark.resilience": "Flecha de estabilidade", - "item.minecraft.potion.effect.quark.resistance": "Poção de fortitude", - "item.minecraft.splash_potion.effect.quark.resistance": "Poção arremessável de fortitude", - "item.minecraft.lingering_potion.effect.quark.resistance": "Poção prolongada de fortitude", - "item.minecraft.tipped_arrow.effect.quark.resistance": "Flecha de fortitude", "item.quark.biome_map": "Mapa de caminho de %s", "item.quark.biome_map.unknown": "Bioma Desconhecido", - "_biome_map_comment": "As seguintes chaves de tradução são apenas relevantes para mapas gerados antes Quark 354.", + "_biome_map_comment": "As seguintes chaves de tradução são apenas relevantes para mapas gerados antes de Quark 354.", + "item.quark.biome_map.snowy_plains": "Mapa de caminho para a planície nevada", + "item.quark.biome_map.windswept_hills": "Mapa de caminho de montanhas congeladas", "item.quark.biome_map.dark_forest": "Mapa de caminho para a floresta escura", "item.quark.biome_map.desert": "Mapa de caminho para o deserto", "item.quark.biome_map.savanna": "Mapa de caminho para a savana", "item.quark.biome_map.swamp": "Mapa de caminho para o pântano", + "item.quark.biome_map.old_growth_pine_taiga": "Mapa de caminho para taiga com pinheiros velhos", "item.quark.biome_map.flower_forest": "Mapa de caminho para a floresta de flores", "item.quark.biome_map.jungle": "Mapa de caminho para a selva", "item.quark.biome_map.bamboo_jungle": "Mapa de caminho para a selva de bambu", @@ -463,6 +628,28 @@ "block.quark.nether_brick_trapped_chest": "Baú de tijolos do Nether armadilhado", "block.quark.purpur_trapped_chest": "Baú de púrpura armadilhado", "block.quark.prismarine_trapped_chest": "Baú de prismanhino armadilhado", + "block.quark.lootr_oak_chest": "Cofre de carvalho", + "block.quark.lootr_spruce_chest": "Cofre de abeto", + "block.quark.lootr_birch_chest": "Cofre de bétula", + "block.quark.lootr_jungle_chest": "Cofre da selva", + "block.quark.lootr_acacia_chest": "Cofre de acácia", + "block.quark.lootr_dark_oak_chest": "Cofre de carvalho escuro", + "block.quark.lootr_warped_chest": "Cofre deformado", + "block.quark.lootr_crimson_chest": "Cofre de carmesím", + "block.quark.lootr_nether_brick_chest": "Cofre de tijolos do Nether", + "block.quark.lootr_purpur_chest": "Cofre de púrpura", + "block.quark.lootr_prismarine_chest": "Cofre de prismarinho", + "block.quark.lootr_oak_trapped_chest": "Cofre de carvalho armadilhado", + "block.quark.lootr_spruce_trapped_chest": "Cofre de abeto armadilhado", + "block.quark.lootr_birch_trapped_chest": "Cofre de bétula armadilhado", + "block.quark.lootr_jungle_trapped_chest": "Cofre da selva armadilhado", + "block.quark.lootr_acacia_trapped_chest": "Cofre de acácia armadilhado", + "block.quark.lootr_dark_oak_trapped_chest": "Cofre de carvalho escuro armadilhado", + "block.quark.lootr_warped_trapped_chest": "Cofre deformado armadilhado", + "block.quark.lootr_crimson_trapped_chest": "Cofre de carmesím armadilhado", + "block.quark.lootr_nether_brick_trapped_chest": "Cofre de tijolos do Nether armadilhado", + "block.quark.lootr_purpur_trapped_chest": "Cofre de púrpura armadilhado", + "block.quark.lootr_prismarine_trapped_chest": "Cofre de prismarinho armadilhado", "block.quark.blaze_lantern": "Lanterna de blaze", "block.quark.sugar_cane_block": "Sacola de cana-de-açúcar", "block.quark.permafrost": "Permafrost", @@ -655,7 +842,7 @@ "block.quark.shale_wall": "Muro de xisto", "block.quark.weather_sensor": "Detector meteorológico", "block.quark.redstone_randomizer": "Randomizador redstone", - "block.quark.grate": "Grelha de verro", + "block.quark.grate": "Grelha de ferro", "block.quark.gravisand": "Gravisand", "block.quark.red_corundum": "Corindo vermelho", "block.quark.orange_corundum": "Corindo laranja", @@ -693,6 +880,24 @@ "block.quark.violet_corundum_cluster": "Cristal de corindo violeta", "block.quark.white_corundum_cluster": "Cristal de corindo branco", "block.quark.black_corundum_cluster": "Cristal de corindo preto", + "block.quark.red_corundum_lamp": "Red Corundum Lamp", + "block.quark.orange_corundum_lamp": "Orange Corundum Lamp", + "block.quark.yellow_corundum_lamp": "Yellow Corundum Lamp", + "block.quark.green_corundum_lamp": "Green Corundum Lamp", + "block.quark.blue_corundum_lamp": "Blue Corundum Lamp", + "block.quark.indigo_corundum_lamp": "Indigo Corundum Lamp", + "block.quark.violet_corundum_lamp": "Violet Corundum Lamp", + "block.quark.white_corundum_lamp": "White Corundum Lamp", + "block.quark.black_corundum_lamp": "Black Corundum Lamp", + "block.quark.red_crystal_lamp": "Red Crystal Lamp", + "block.quark.orange_crystal_lamp": "Orange Crystal Lamp", + "block.quark.yellow_crystal_lamp": "Yellow Crystal Lamp", + "block.quark.green_crystal_lamp": "Green Crystal Lamp", + "block.quark.blue_crystal_lamp": "Blue Crystal Lamp", + "block.quark.indigo_crystal_lamp": "Indigo Crystal Lamp", + "block.quark.violet_crystal_lamp": "Violet Crystal Lamp", + "block.quark.white_crystal_lamp": "White Crystal Lamp", + "block.quark.black_crystal_lamp": "Black Crystal Lamp", "block.quark.feeding_trough": "Comedouro", "block.quark.chute": "Calha", "block.quark.paper_wall": "Parede de papel", @@ -845,7 +1050,6 @@ "block.quark.blue_nether_bricks_slab": "Degrau de tijolos do Nether azuis", "block.quark.blue_nether_bricks_vertical_slab": "Degrau vertical de tijolos do Nether azuis", "block.quark.blue_nether_bricks_wall": "Muro de tijolos do Nether azuis", - "block.quark.shallow_dirt": "Terra rasa", "block.quark.bamboo_mat": "Bloco de tapete de bambu", "block.quark.bamboo_mat_carpet": "Tapete de bambu", "block.quark.cut_vine": "Trepadeiras cortadas", @@ -965,7 +1169,6 @@ "block.quark.netherrack_bricks": "Tijolos de netherrack", "block.quark.stone_lamp": "Lâmpada de pedra", "block.quark.stone_brick_lamp": "Lâmpada de tijolos de pedra", - "block.quark.pallet": "Palete", "block.quark.dusky_myalite": "Mialíto sombrio", "block.quark.cobbled_deepslate_vertical_slab": "Degrau vertical de pedregulho de ardósia", "block.quark.polished_deepslate_vertical_slab": "Degrau vertical de ardósia polida", @@ -1030,6 +1233,8 @@ "block.quark.azalea_bookshelf": "Estante de livros de azálea", "block.quark.azalea_chest": "Baú de azálea", "block.quark.azalea_trapped_chest": "Baú de azálea armadilhado", + "block.quark.lootr_azalea_chest": "Cofre de azálea", + "block.quark.lootr_azalea_trapped_chest": "Cofre de azálea armadilhado", "block.quark.azalea_ladder": "Escada de mão de azálea", "block.quark.azalea_door": "Porta de azálea", "block.quark.azalea_trapdoor": "Alçapão de azálea", @@ -1048,6 +1253,8 @@ "block.quark.blossom_bookshelf": "Estante de livros de flórida", "block.quark.blossom_chest": "Baú de flórida", "block.quark.blossom_trapped_chest": "Baú de flórida armadilhado", + "block.quark.lootr_blossom_chest": "Cofre de flórida", + "block.quark.lootr_blossom_trapped_chest": "Cofre de flórida armadilhado", "block.quark.blossom_ladder": "Escada de mão de flórida", "block.quark.blossom_door": "Porta de flórida", "block.quark.blossom_trapdoor": "Alçapão de flórida", @@ -1073,11 +1280,13 @@ "block.quark.mud_brick_vertical_slab": "Degrau vertical de tijolos de barro", "block.quark.mangrove_bookshelf": "Estante de livro de mangue", "block.quark.mangrove_chest": "Baú de mangue", + "block.quark.mangrove_trapped_chest": "Baú de mangue armadilhado", + "block.quark.lootr_mangrove_chest": "Cofre de mangue", + "block.quark.lootr_mangrove_trapped_chest": "Cofre de mangue armadilhado", "block.quark.mangrove_hedge": "Sebe de mangue", "block.quark.mangrove_ladder": "Escada de mão de mangue", "block.quark.mangrove_leaf_carpet": "Tapete de folhas de mangue", "block.quark.mangrove_post": "Poste de mangue", - "block.quark.mangrove_trapped_chest": "Baú de mangue armadilhado", "block.quark.stripped_mangrove_post": "Porte de mangue descascado", "block.quark.vertical_mangrove_planks": "Tábuas verticais de mangue", "block.quark.raw_iron_bricks": "Tijolos de ferro bruto", @@ -1104,6 +1313,8 @@ "block.quark.bamboo_bookshelf": "Estante de livros de bambu", "block.quark.bamboo_chest": "Baú de bambu", "block.quark.bamboo_trapped_chest": "Baú de bambu armadilhado", + "block.quark.lootr_bamboo_chest": "Baú de tresouro de bambu", + "block.quark.lootr_bamboo_trapped_chest": "Baú de tresouro de bambu armadilhado", "block.quark.bamboo_ladder": "Escada de mão de bambu", "block.quark.bamboo_door": "Porta de bambu", "block.quark.bamboo_trapdoor": "Alçapão de bambu", @@ -1114,6 +1325,47 @@ "block.quark.bamboo_pressure_plate": "Placa de pressão de bambu", "block.quark.vertical_bamboo_planks": "Tábuas verticais de bambu", "block.quark.bamboo_mosaic": "Mosaico de bambu", + "block.quark.hollow_oak_log": "Tronco de carvalho oco", + "block.quark.hollow_spruce_log": "Tronco de abeto oco", + "block.quark.hollow_birch_log": "Tronco de bétula oco", + "block.quark.hollow_jungle_log": "Tronco da selva oco", + "block.quark.hollow_acacia_log": "Tronco de acácia oco", + "block.quark.hollow_dark_oak_log": "Tronco de carvalho escuro oco", + "block.quark.hollow_mangrove_log": "Tronco de mangue oco", + "block.quark.hollow_crimson_stem": "Tronco carmesim oco", + "block.quark.hollow_warped_stem": "Tronco deformado oco", + "block.quark.hollow_blossom_log": "Tronco flórido oco", + "block.quark.hollow_azalea_log": "Tronco de azálea oco", + "block.quark.ancient_planks": "Tábuas ancestrais", + "block.quark.ancient_log": "Tronco ancestral", + "block.quark.stripped_ancient_log": "Tronco ancestral descascado", + "block.quark.ancient_wood": "Madeira ancestral", + "block.quark.stripped_ancient_wood": "Madeira ancestral descascada", + "block.quark.hollow_ancient_log": "Tronco ancestral oco", + "block.quark.ancient_planks_stairs": "Escadas de tábuas ancestral", + "block.quark.ancient_planks_slab": "Degrau de tábuas ancestrais", + "block.quark.ancient_planks_vertical_slab": "Degrau vertical de tábuas ancestrais", + "block.quark.ancient_post": "Poste ancestral", + "block.quark.stripped_ancient_post": "Poste ancestral descascado", + "block.quark.ancient_bookshelf": "Estante de livros ancestral", + "block.quark.ancient_chest": "Baú ancestral", + "block.quark.ancient_trapped_chest": "Baú ancestral armadilhado", + "block.quark.lootr_ancient_chest": "Cofre ancestral", + "block.quark.lootr_ancient_trapped_chest": "Cofre ancestral armadilhado", + "block.quark.ancient_ladder": "Escada de mão ancestral", + "block.quark.ancient_door": "Porta ancestral", + "block.quark.ancient_trapdoor": "Alçapão ancestral", + "block.quark.ancient_fence_gate": "Portão ancestral", + "block.quark.ancient_fence": "Carca ancestral", + "block.quark.ancient_sign": "Tabuleta ancestral", + "block.quark.ancient_button": "Botão ancestral", + "block.quark.ancient_pressure_plate": "Placa de pressão ancestral", + "block.quark.vertical_ancient_planks": "Tábuas verticais ancestral", + "block.quark.ancient_leaves": "Folhas ancestrais", + "block.quark.ancient_sapling": "Rebento ancestral", + "block.quark.ancient_leaf_carpet": "Tapete de folhas ancestrais", + "block.quark.ancient_hedge": "Sebe ancestral", + "block.quark.golden_carrot_crate": "Caixote de cenouras douradas", "item.quark.stoneling_spawn_egg": "Ovo de invocação de stoneling", "item.quark.crab_spawn_egg": "Ovo de invocação de caranguejo", @@ -1175,59 +1427,65 @@ "block.quark.potted_glow_shroom": "Cogumelo brilhante em vaso", "block.quark.potted_chorus_weeds": "Relva do coro em vaso", "block.quark.potted_chorus_twist": "Raízes do coro em vaso", + "block.quark.potted_ancient_sapling": "Rebento ancestral em vaso", + "block.quark.potted_cave_vines": "Trepadeiras de gruta em vaso", + "block.quark.tiny_potato": "Potato pequeno", "block.quark.tiny_potato.angry": "Potato zangado", "biome.quark.glimmering_weald": "Caverna de cogumelos brilhantes", - "item.quark.torch_arrow": "Flecha de tocha", - "item.quark.ancient_boat": "Barco ancestral", - "item.quark.ancient_chest_boat": "Barco ancestral com baú", - "item.quark.biome_map.snowy_plains": "Mapa de caminho para a planície nevada", - "item.quark.biome_map.windswept_hills": "Mapa de caminho de montanhas congeladas", - "item.quark.biome_map.old_growth_pine_taiga": "Mapa de caminho para taiga com pinheiros velhos", - "block.quark.hollow_oak_log": "Tronco de carvalho oco", - "block.quark.hollow_spruce_log": "Tronco de abeto oco", - "block.quark.hollow_birch_log": "Tronco de bétula oco", - "block.quark.hollow_jungle_log": "Tronco da selva oco", - "block.quark.hollow_acacia_log": "Tronco de acácia oco", - "block.quark.hollow_dark_oak_log": "Tronco de carvalho escuro oco", - "block.quark.hollow_mangrove_log": "Tronco de mangue oco", - "block.quark.hollow_crimson_stem": "Tronco carmesim oco", - "block.quark.hollow_warped_stem": "Tronco deformado oco", - "block.quark.hollow_blossom_log": "Tronco flórido oco", - "block.quark.hollow_azalea_log": "Tronco de azálea oco", - "block.quark.ancient_planks": "Tábuas ancestrais", - "block.quark.ancient_log": "Tronco ancestral", - "block.quark.stripped_ancient_log": "Tronco ancestral descascado", - "block.quark.ancient_wood": "Madeira ancestral", - "block.quark.stripped_ancient_wood": "Madeira ancestral descascada", - "block.quark.hollow_ancient_log": "Tronco ancestral oco", - "block.quark.ancient_planks_stairs": "Escadas de tábuas ancestral", - "block.quark.ancient_planks_slab": "Degrau de tábuas ancestrais", - "block.quark.ancient_planks_vertical_slab": "Degrau vertical de tábuas ancestrais", - "block.quark.ancient_post": "Poste ancestral", - "block.quark.stripped_ancient_post": "Poste ancestral descascado", - "block.quark.ancient_bookshelf": "Estante de livros ancestral", - "block.quark.ancient_chest": "Baú ancestral", - "block.quark.ancient_trapped_chest": "Baú ancestral armadilhado", - "block.quark.ancient_ladder": "Escada de mão ancestral", - "block.quark.ancient_door": "Porta ancestral", - "block.quark.ancient_trapdoor": "Alçapão ancestral", - "block.quark.ancient_fence_gate": "Portão ancestral", - "block.quark.ancient_fence": "Carca ancestral", - "block.quark.ancient_sign": "Tabuleta ancestral", - "block.quark.ancient_button": "Botão ancestral", - "block.quark.ancient_pressure_plate": "Placa de pressão ancestral", - "block.quark.vertical_ancient_planks": "Tábuas verticais ancestral", - "item.quark.ancient_fruit": "Fruta ancestral", - "block.quark.ancient_leaves": "Folhas ancestrais", - "block.quark.ancient_sapling": "Rebento ancestral", - "block.quark.ancient_leaf_carpet": "Tapete de folhas ancestrais", - "block.quark.ancient_hedge": "Sebe ancestral", - "block.quark.golden_carrot_crate": "Caixote de cenouras douradas", - "block.quark.potted_ancient_sapling": "Rebento ancestral em vaso", - "block.quark.potted_cave_vines": "Trepadeiras de gruta em vaso", + "tag.item.c.storage_blocks.apple": "Blocos de armazenamento de maçã", + "tag.item.c.storage_blocks.bamboo": "Blocos de armazenamento de bambu", + "tag.item.c.storage_blocks.beetroot": "Blocos de armazenamento de beterraba", + "tag.item.c.storage_blocks.blaze_rod": "Blocos de armazenamento de varas de blaze", + "tag.item.c.storage_blocks.cactus": "Blocos de armazenamento de cato", + "tag.item.c.storage_blocks.carrot": "Blocos de armazenamento de cenoura", + "tag.item.c.storage_blocks.charcoal": "Blocos de armazenamento de carvão vegetal", + "tag.item.c.storage_blocks.chorus_fruit": "Blocos de armazenamento de fruta do coro", + "tag.item.c.storage_blocks.cocoa_beans": "Blocos de armazenamento de cacau", + "tag.item.c.storage_blocks.glow_berries": "Blocos de armazenamento de baga brilhante", + "tag.item.c.storage_blocks.golden_apple": "Blocos de armazenamento de maçã dourada", + "tag.item.c.storage_blocks.golden_carrot": "Blocos de armazenamento de cenoura dourada", + "tag.item.c.storage_blocks.gunpowder": "Blocos de armazenamento de pólvora", + "tag.item.c.storage_blocks.leather": "Blocos de armazenamento de couro", + "tag.item.c.storage_blocks.nether_wart": "Blocos de armazenamento de fungo do Nether", + "tag.item.c.storage_blocks.potato": "Blocos de armazenamento de batata", + "tag.item.c.storage_blocks.rabbit_hide": "Blocos de armazenamento de pele de coelho", + "tag.item.c.storage_blocks.stick": "Blocos de armazenamento de pau", + "tag.item.c.storage_blocks.sugar_cane": "Blocos de armazenamento de cano de açúcar", + "tag.item.c.storage_blocks.sweet_berries": "Blocos de armazenamento de baga doce", + + "tag.item.quark.ancient_logs": "Troncos ancestrais", + "tag.item.quark.azalea_logs": "Troncos de azálea", + "tag.item.quark.bamboo_logs": "Troncos de bambu", + "tag.item.quark.big_harvesting_hoes": "Enxadas de colheita larga", + "tag.item.quark.blossom_logs": "Troncos de flórida", + "tag.item.quark.corundum": "Coríndo", + "tag.item.quark.crystal_lamp": "Lâmpadas de cristaç", + "tag.item.quark.cosmetic_anvil_items": "Actualizações de bigorna apenas cosméticas", + "tag.item.quark.framed_glass_panes": "Painéis de vidro enmoldurados", + "tag.item.quark.framed_glasses": "Vidros enmoldurados", + "tag.item.quark.glow_shroom_feedables": "Cogumelos brilhantes alimentos para stoneling", + "tag.item.quark.hedges": "Sebes", + "tag.item.quark.hollow_logs": "Troncos ocos", + "tag.item.quark.ladders": "Escadas", + "tag.item.quark.parrot_feed": "Comida de papagaio", + "tag.item.quark.pipes": "Canos", + "tag.item.quark.posts": "Postos", + "tag.item.quark.revertable_chests": "Baús transformáveis em baús vanilla", + "tag.item.quark.revertable_trapped_chests": "Baús transformáveis em baús vanilla armadilhados", + "tag.item.quark.runes": "Runas", + "tag.item.quark.runes_lootable": "Runas em saque", + "tag.item.quark.seed_pouch_holdable": "Conteúdos das bolsas de semente", + "tag.item.quark.shards": "Estilhaços de vidro", + "tag.item.quark.stained_framed_glass_panes": "Vidraças enmolduradas sujas", + "tag.item.quark.stained_framed_glasses": "Vidros enmoldurados sujos", + "tag.item.quark.stone_tool_materials": "Materiais de ferramentas de pedra", + "tag.item.quark.stools": "Bancos", + "tag.item.quark.vertical_slabs": "Degraus verticais", + "tag.item.quark.wooden_vertical_slabs": "Degraus verticais de madeira", + "advancements.quark.influence.title": "Influencer", "advancements.quark.influence.description": "Usa velas em encantamento matrix para influenciar um encantamento específico", "advancements.quark.pat_potato.title": "Batatinha quando nasce, esparrama pelo chão.", @@ -1260,8 +1518,8 @@ "advancements.quark.get_bottled_cloud.description": "Put a Cloud in a Bottle", "advancements.quark.apply_color_rune.title": "Glorious Eminence", "advancements.quark.apply_color_rune.description": "Apply a Rune to an enchanted item in an Anvil", - "advancements.quark.wear_full_rainbow.title": "Taste the Rainbow", - "advancements.quark.wear_full_rainbow.description": "Wear a full set of armor with Rainbow Runes applied", + "advancements.quark.wear_full_rainbow.title": "Pintarolas!", + "advancements.quark.wear_full_rainbow.description": "Equipa um conjunto completo de armadura com runas arco-íris aplicadas", "advancements.quark.throw_parrot_egg.title": "Just the Parrots", "advancements.quark.throw_parrot_egg.description": "Feed Beetroot Seeds to a Parrot and toss the egg it lays", "advancements.quark.pathfinder_map_center.title": "Road to Tomorrow", @@ -1283,5 +1541,14 @@ "advancements.quark.shiba_help.title": "Paint The Town", "advancements.quark.shiba_help.description": "Clean up a dark spot with the help of a Shiba while holding a Torch", "advancements.quark.poison_baby.title": "Forever Young", - "advancements.quark.poison_baby.description": "Successfully poison a baby animal with a Poisoned Potato" -} + "advancements.quark.poison_baby.description": "Successfully poison a baby animal with a Poisoned Potato", + "advancements.quark.crab_in_a_bucket.title": "Crabtured", + "advancements.quark.crab_in_a_bucket.description": "Capture a Crab in a Bucket", + "_block.quark.pallet": "Palete", + "_block.quark.shallow_dirt": "Terra rasa", + "_item.minecraft.lingering_potion.effect.quark.resistance": "Poção prolongada de fortitude", + "_item.minecraft.potion.effect.quark.resistance": "Poção de fortitude", + "_item.minecraft.splash_potion.effect.quark.resistance": "Poção arremessável de fortitude", + "_item.minecraft.tipped_arrow.effect.quark.resistance": "Flecha de fortitude", + "_item.quark.saw": "Serra de Sculk (NYI)" +} \ No newline at end of file