Skip to content

Commit

Permalink
Implement translations for item name and lore (#3763)
Browse files Browse the repository at this point in the history
* Implement translations for item name and lore

* Invert condition to reduce branching
  • Loading branch information
Yeregorix authored Oct 12, 2022
1 parent 39dfae5 commit 6ed72d7
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 4 deletions.
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

0 comments on commit 6ed72d7

Please sign in to comment.