Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement translations for item name and lore #3763

Merged
merged 2 commits into from
Oct 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/main/java/org/spongepowered/common/util/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,9 @@ public static final class Item {
public static final String ITEM_STORED_ENCHANTMENTS_LIST = "StoredEnchantments";
public static final String ITEM_DISPLAY = "display";
public static final String ITEM_LORE = "Lore";
public static final String ITEM_NAME = "Name";
public static final String ITEM_ORIGINAL_LORE = "SpongeOriginalLore";
public static final String ITEM_ORIGINAL_NAME = "SpongeOriginalName";
public static final String ITEM_ENCHANTMENT_ID = "id";
public static final String ITEM_ENCHANTMENT_LEVEL = "lvl";
public static final String ITEM_BREAKABLE_BLOCKS = "CanDestroy";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,23 @@
*/
package org.spongepowered.common.mixin.core.network;

import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.StringTag;
import net.minecraft.world.item.ItemStack;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.api.util.locale.Locales;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.common.adventure.NativeComponentRenderer;
import org.spongepowered.common.bridge.network.FriendlyByteBufBridge;

import java.util.Locale;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import org.spongepowered.common.util.Constants;

@Mixin(FriendlyByteBuf.class)
public abstract class FriendlyByteBufMixin implements FriendlyByteBufBridge {
Expand All @@ -43,7 +49,89 @@ public abstract class FriendlyByteBufMixin implements FriendlyByteBufBridge {

@ModifyVariable(method = "writeComponent", at = @At("HEAD"), argsOnly = true)
private Component localizeComponent(final Component input) {
return NativeComponentRenderer.apply(input, this.impl$locale == null ? Locales.EN_US : this.impl$locale);
return NativeComponentRenderer.apply(input, this.impl$locale == null ? Locales.DEFAULT : this.impl$locale);
}

@Redirect(method = "writeItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;getTag()Lnet/minecraft/nbt/CompoundTag;"))
public CompoundTag renderItemComponents(final ItemStack stack) {
CompoundTag tag = stack.getTag();
if (tag == null || !tag.contains(Constants.Item.ITEM_DISPLAY, 10)) {
return tag;
}

final Locale locale = this.impl$locale == null ? Locales.DEFAULT : this.impl$locale;
CompoundTag display = tag.getCompound(Constants.Item.ITEM_DISPLAY);
boolean copy = true;

if (display.contains(Constants.Item.ITEM_NAME, 8)) {
final String nameStr = display.getString(Constants.Item.ITEM_NAME);
final Component name = Component.Serializer.fromJson(nameStr);
final Component renderedName = NativeComponentRenderer.apply(name, locale);

if (!renderedName.equals(name)) {
if (copy) {
tag = tag.copy();
display = tag.getCompound(Constants.Item.ITEM_DISPLAY);
copy = false;
}

display.putString(Constants.Item.ITEM_ORIGINAL_NAME, nameStr);
display.putString(Constants.Item.ITEM_NAME, Component.Serializer.toJson(renderedName));
}
}

if (display.contains(Constants.Item.ITEM_LORE, 9)) {
final ListTag lore = display.getList(Constants.Item.ITEM_LORE, 8);

final Component[] renderedLines = new Component[lore.size()];
boolean equal = true;

for (int i = 0; i < renderedLines.length; i++) {
final String lineStr = lore.getString(i);
final Component line = Component.Serializer.fromJson(lineStr);
final Component renderedLine = NativeComponentRenderer.apply(line, locale);

renderedLines[i] = renderedLine;
equal = equal && renderedLine.equals(line);
}

if (!equal) {
if (copy) {
tag = tag.copy();
display = tag.getCompound(Constants.Item.ITEM_DISPLAY);
copy = false;
}

final ListTag newLore = new ListTag();
for (Component renderedLine : renderedLines) {
newLore.add(StringTag.valueOf(Component.Serializer.toJson(renderedLine)));
}

display.put(Constants.Item.ITEM_ORIGINAL_LORE, lore);
display.put(Constants.Item.ITEM_LORE, newLore);
}
}
return tag;
}

@Redirect(method = "readItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;setTag(Lnet/minecraft/nbt/CompoundTag;)V"))
public void restoreItemComponents(final ItemStack stack, final CompoundTag tag) {
if (tag != null && tag.contains(Constants.Item.ITEM_DISPLAY, 10)) {
final CompoundTag display = tag.getCompound(Constants.Item.ITEM_DISPLAY);

if (display.contains(Constants.Item.ITEM_ORIGINAL_NAME, 8)) {
final String name = display.getString(Constants.Item.ITEM_ORIGINAL_NAME);
display.remove(Constants.Item.ITEM_ORIGINAL_NAME);
display.putString(Constants.Item.ITEM_NAME, name);
}

if (display.contains(Constants.Item.ITEM_ORIGINAL_LORE, 9)) {
final ListTag lore = display.getList(Constants.Item.ITEM_ORIGINAL_LORE, 8);
display.remove(Constants.Item.ITEM_ORIGINAL_LORE);
display.put(Constants.Item.ITEM_LORE, lore);
}
}
stack.setTag(tag);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ResultSlot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ChunkPos;
Expand Down Expand Up @@ -171,11 +172,12 @@ public abstract class ServerPlayerMixin extends PlayerMixin implements SubjectBr
@Shadow protected abstract void shadow$createEndPlatform(ServerLevel p_241206_1_, BlockPos blockPos);
@Shadow protected abstract void shadow$triggerDimensionChangeTriggers(ServerLevel serverworld);
@Shadow public abstract void shadow$doCloseContainer();
@Shadow public abstract void shadow$refreshContainer(AbstractContainerMenu container);
// @formatter:on


private net.minecraft.network.chat.@Nullable Component impl$connectionMessage;
private Locale impl$language = Locales.EN_US;
private Locale impl$language = Locales.DEFAULT;
private Scoreboard impl$scoreboard = Sponge.game().server().serverScoreboard().get();
@Nullable private Boolean impl$keepInventory = null;
// Used to restore original item received in a packet after canceling an event
Expand Down Expand Up @@ -265,17 +267,21 @@ public abstract class ServerPlayerMixin extends PlayerMixin implements SubjectBr

@Override
public void bridge$setLanguage(final Locale language) {
this.impl$language = language;

// Update locale on Channel, used for sending localized messages
if (this.connection != null) {
final Channel channel = ((ConnectionAccessor) this.connection.connection).accessor$channel();
channel.attr(SpongeAdventure.CHANNEL_LOCALE).set(language);

SpongeAdventure.forEachBossBar(bar -> {
if (bar.getPlayers().contains(this)) {
this.connection.send(new ClientboundBossEventPacket(ClientboundBossEventPacket.Operation.UPDATE_NAME, bar));
}
});

this.shadow$refreshContainer(this.containerMenu);
}
this.impl$language = language;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.spongepowered.api.adventure.SpongeComponents;
import org.spongepowered.api.command.Command;
import org.spongepowered.api.command.CommandResult;
import org.spongepowered.api.command.exception.CommandException;
import org.spongepowered.api.command.parameter.CommandContext;
import org.spongepowered.api.command.parameter.Parameter;
import org.spongepowered.api.data.Keys;
Expand All @@ -55,12 +56,15 @@
import org.spongepowered.api.event.lifecycle.RegisterCommandEvent;
import org.spongepowered.api.event.message.PlayerChatEvent;
import org.spongepowered.api.event.network.ServerSideConnectionEvent;
import org.spongepowered.api.item.ItemTypes;
import org.spongepowered.api.item.inventory.ItemStack;
import org.spongepowered.api.util.locale.Locales;
import org.spongepowered.plugin.PluginContainer;
import org.spongepowered.plugin.builtin.jvm.Plugin;
import org.spongepowered.test.LoadableModule;

import java.util.Arrays;
import java.util.Collections;
import java.util.Locale;
import java.util.ResourceBundle;

Expand Down Expand Up @@ -124,6 +128,20 @@ public void registerCommands(final RegisterCommandEvent<Command.Parameterized> e
return CommandResult.success();
}).build(), "sendbook");

event.register(this.container, Command.builder()
.permission("chattest.giveitem")
.executor(ctx -> {
final ServerPlayer player = ctx.cause().first(ServerPlayer.class)
.orElseThrow(() -> new CommandException(Component.text("You must be a player to use this command!")));

final ItemStack itemStack = ItemStack.builder().itemType(ItemTypes.PAPER)
.add(Keys.CUSTOM_NAME, Component.translatable("chattest.item.name"))
.add(Keys.LORE, Collections.singletonList(Component.translatable("chattest.item.lore"))).build();

player.inventory().offer(itemStack);
return CommandResult.success();
}).build(), "giveitem");

final Parameter.Value<ServerPlayer> targetArg = Parameter.player().key("target").build();
final Parameter.Value<Component> messageArg = Parameter.jsonText().key("message").build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ chattest.bars.info=Have you eaten your FLARD yet?
chattest.response.chat=Message "{0}" sent by {1}
chattest.book.1=First page of the book!
chattest.book.2=Second page of the book!
chattest.response=A test response!
chattest.response=A test response!
chattest.item.name=Item name
chattest.item.lore=Item lore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ chattest.response.chat={1} ʎq ʇuǝs „{0}„ ǝƃɐssǝꟽ
chattest.book.1=¡ʞooq ǝɥʇ ⅎo ǝƃɐd ʇsɹᴉᖵ
chattest.book.2=¡ʞooq ǝɥʇ ⅎo ǝƃɐd puoɔǝS
chattest.response=a test but upside down (but not, because i''m lazy)
chattest.item.name=ǝɯɐu ɯǝʇI
chattest.item.lore=ǝɹoʅ ɯǝʇI