Skip to content

Commit bff89d2

Browse files
authored
Merge pull request #40 from huanmeng-qwq/feat/translation-render
Add support for GlobalTranslator
2 parents d6a3cb7 + acbb438 commit bff89d2

11 files changed

Lines changed: 220 additions & 16 deletions

File tree

api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,6 @@ public interface EntityLibAPI<T> {
5353
@NotNull
5454
EntityContainer getDefaultContainer();
5555

56+
@NotNull
57+
UserLocaleProvider getUserLocaleProvider();
5658
}

api/src/main/java/me/tofaa/entitylib/Platform.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ public interface Platform<P> {
2626
*/
2727
@NotNull EntityUuidProvider getEntityUuidProvider();
2828

29+
/**
30+
* Gets the provider responsible for retrieving the locale of a user.
31+
*
32+
* @return a non-null {@link UserLocaleProvider} instance.
33+
*/
34+
@NotNull UserLocaleProvider getUserLocaleProvider();
35+
2936
/**
3037
* Sets the entityId integer provider. This can be provided by a platform if needed.
3138
* @param provider the entityId integer provider.
@@ -38,6 +45,12 @@ public interface Platform<P> {
3845
*/
3946
void setEntityUuidProvider(@NotNull EntityUuidProvider provider);
4047

48+
/**
49+
* Sets the provider responsible for retrieving the locale of a user.
50+
*
51+
* @param provider the {@link UserLocaleProvider} instance to be set. Must not be null.
52+
*/
53+
void setUserLocaleProvider(@NotNull UserLocaleProvider provider);
4154

4255
/**
4356
* @return the logger EntityLib uses internally.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package me.tofaa.entitylib;
2+
3+
import java.util.Locale;
4+
import java.util.UUID;
5+
6+
public interface UserLocaleProvider {
7+
Locale locale(UUID user);
8+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package me.tofaa.entitylib.utils;
2+
3+
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
4+
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
5+
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
6+
import me.tofaa.entitylib.EntityLib;
7+
import java.util.Locale;
8+
import java.util.Optional;
9+
import java.util.UUID;
10+
import net.kyori.adventure.text.Component;
11+
import net.kyori.adventure.translation.GlobalTranslator;
12+
13+
public class PacketUtil {
14+
private PacketUtil() {
15+
}
16+
17+
public static void renderPacket(UUID user, WrapperPlayServerEntityMetadata metadata) {
18+
Locale locale = EntityLib.getApi().getUserLocaleProvider().locale(user);
19+
for (final EntityData<?> entityData : metadata.getEntityMetadata()) {
20+
if (entityData.getType() == EntityDataTypes.ADV_COMPONENT) {
21+
Component component = (Component) entityData.getValue();
22+
final Component rendered = GlobalTranslator.render(component, locale);
23+
((EntityData<Component>) entityData).setValue(rendered);
24+
} else if (entityData.getType() == EntityDataTypes.OPTIONAL_ADV_COMPONENT) {
25+
final Optional<Component> optional = (Optional<Component>) entityData.getValue();
26+
if (optional.isPresent()) {
27+
final Component component = optional.get();
28+
final Component rendered = GlobalTranslator.render(component, locale);
29+
((EntityData<Optional<Component>>) entityData).setValue(Optional.of(rendered));
30+
}
31+
}
32+
}
33+
}
34+
}

api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,39 @@
55
import com.github.retrooper.packetevents.protocol.world.Location;
66
import com.github.retrooper.packetevents.util.Vector3d;
77
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
8-
import com.github.retrooper.packetevents.wrapper.play.server.*;
8+
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerBundle;
9+
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities;
10+
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityHeadLook;
11+
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
12+
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRotation;
13+
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityTeleport;
14+
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityVelocity;
15+
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetPassengers;
16+
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity;
17+
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSystemChatMessage;
918
import me.tofaa.entitylib.EntityLib;
1019
import me.tofaa.entitylib.container.EntityContainer;
1120
import me.tofaa.entitylib.meta.EntityMeta;
1221
import me.tofaa.entitylib.meta.types.ObjectData;
1322
import me.tofaa.entitylib.tick.Tickable;
23+
import me.tofaa.entitylib.utils.PacketUtil;
1424
import me.tofaa.entitylib.ve.ViewerRule;
1525
import me.tofaa.entitylib.wrapper.spawning.SpawnPacketProvider;
26+
import java.util.Collection;
27+
import java.util.Collections;
28+
import java.util.List;
29+
import java.util.Optional;
30+
import java.util.Set;
31+
import java.util.UUID;
32+
import java.util.concurrent.ConcurrentHashMap;
33+
import java.util.concurrent.CopyOnWriteArrayList;
34+
import java.util.function.Consumer;
1635
import net.kyori.adventure.text.Component;
1736
import org.jetbrains.annotations.ApiStatus;
1837
import org.jetbrains.annotations.NotNull;
1938
import org.jetbrains.annotations.Nullable;
2039
import org.jetbrains.annotations.UnmodifiableView;
2140

22-
import java.util.*;
23-
import java.util.concurrent.ConcurrentHashMap;
24-
import java.util.concurrent.CopyOnWriteArrayList;
25-
import java.util.function.Consumer;
26-
2741
public class WrapperEntity implements Tickable {
2842
private final UUID uuid;
2943
private final int entityId;
@@ -510,6 +524,11 @@ private static void sendPacket(UUID user, PacketWrapper<?> wrapper) {
510524
return;
511525
}
512526

527+
// Special handling for entity metadata packets to support `GlobalTranslator` functionality and component rendering
528+
if (wrapper instanceof WrapperPlayServerEntityMetadata) {
529+
PacketUtil.renderPacket(user, (WrapperPlayServerEntityMetadata) wrapper);
530+
}
531+
513532
EntityLib.getApi().getPacketEvents().getProtocolManager().sendPacket(channel, wrapper);
514533
}
515534

common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import me.tofaa.entitylib.APIConfig;
55
import me.tofaa.entitylib.EntityLibAPI;
66
import me.tofaa.entitylib.Platform;
7+
import me.tofaa.entitylib.UserLocaleProvider;
78
import me.tofaa.entitylib.container.EntityContainer;
89
import me.tofaa.entitylib.tick.TickContainer;
910
import me.tofaa.entitylib.wrapper.WrapperEntity;
@@ -63,4 +64,9 @@ public PacketEventsAPI<?> getPacketEvents() {
6364
public @NotNull Collection<TickContainer<?, T>> getTickContainers() {
6465
return tickContainers;
6566
}
67+
68+
@Override
69+
public @NotNull UserLocaleProvider getUserLocaleProvider() {
70+
return platform.getUserLocaleProvider();
71+
}
6672
}

platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,17 @@
55
import io.github.retrooper.packetevents.bstats.charts.SimplePie;
66
import me.tofaa.entitylib.APIConfig;
77
import me.tofaa.entitylib.EntityLib;
8+
import me.tofaa.entitylib.UserLocaleProvider;
89
import me.tofaa.entitylib.common.AbstractPlatform;
9-
import me.tofaa.entitylib.utils.ConcurrentWeakIdentityHashMap;
10-
import org.bukkit.Bukkit;
11-
import org.bukkit.World;
12-
import org.bukkit.entity.Entity;
10+
import java.util.logging.Logger;
1311
import org.bukkit.plugin.Plugin;
1412
import org.bukkit.plugin.java.JavaPlugin;
1513
import org.jetbrains.annotations.NotNull;
16-
import org.jetbrains.annotations.Nullable;
17-
18-
import java.util.Map;
19-
import java.util.logging.Logger;
20-
import java.util.stream.Stream;
2114

2215
public class SpigotEntityLibPlatform extends AbstractPlatform<JavaPlugin> {
2316

2417
private SpigotEntityLibAPI api;
18+
private UserLocaleProvider userLocaleProvider = new SpigotPlayerLocaleProvider();
2519

2620
public SpigotEntityLibPlatform(@NotNull JavaPlugin plugin) {
2721
super(plugin);
@@ -36,7 +30,7 @@ public void setupApi(@NotNull APIConfig settings) {
3630
this.api.onLoad();
3731
this.api.onEnable();
3832
if (settings.shouldUseBstats()) {
39-
PacketEventsAPI<Plugin> pe = (PacketEventsAPI<Plugin>)api.getPacketEvents();
33+
PacketEventsAPI<Plugin> pe = (PacketEventsAPI<Plugin>) api.getPacketEvents();
4034
Metrics metrics = new Metrics(pe.getPlugin(), 21916);
4135
metrics.addCustomChart(new SimplePie("entitylib-version", () -> EntityLib.getVersion().toString()));
4236
}
@@ -52,4 +46,14 @@ public SpigotEntityLibAPI getAPI() {
5246
public String getName() {
5347
return "Spigot";
5448
}
49+
50+
@Override
51+
public @NotNull UserLocaleProvider getUserLocaleProvider() {
52+
return userLocaleProvider;
53+
}
54+
55+
@Override
56+
public void setUserLocaleProvider(@NotNull final UserLocaleProvider provider) {
57+
this.userLocaleProvider = provider;
58+
}
5559
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package me.tofaa.entitylib.spigot;
2+
3+
import me.tofaa.entitylib.UserLocaleProvider;
4+
import java.lang.invoke.MethodHandle;
5+
import java.lang.invoke.MethodHandles;
6+
import java.lang.invoke.MethodType;
7+
import java.util.Locale;
8+
import java.util.UUID;
9+
import java.util.function.Function;
10+
import net.kyori.adventure.translation.Translator;
11+
import org.bukkit.Bukkit;
12+
import org.bukkit.entity.Player;
13+
import org.jetbrains.annotations.NotNull;
14+
15+
16+
/**
17+
* This implementation is based on code from the scoreboard-library project:
18+
* <a href="https://github.com/MegavexNetwork/scoreboard-library/blob/bc8e3c2d2ecf9973ec0d6bb8ae4af94ed008b360/commons/src/main/java/net/megavex/scoreboardlibrary/implementation/commons/LocaleProvider.java">LocaleProvider</a>
19+
* Modified and adapted for use in EntityLib.
20+
*/
21+
public class SpigotPlayerLocaleProvider implements UserLocaleProvider {
22+
private static final Locale DEFAULT_LOCALE = Locale.US;
23+
private static final Function<Player, Locale> provider = get();
24+
25+
@Override
26+
public Locale locale(final UUID user) {
27+
final Player player = Bukkit.getPlayer(user);
28+
return player == null ? DEFAULT_LOCALE : provider.apply(player);
29+
}
30+
31+
private static @NotNull Function<Player, Locale> get() {
32+
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
33+
try {
34+
MethodHandle adventureMethod = lookup.findVirtual(Player.class, "locale", MethodType.methodType(Locale.class));
35+
return player -> {
36+
try {
37+
return (Locale) adventureMethod.invokeExact(player);
38+
} catch (Throwable e) {
39+
throw new RuntimeException(e);
40+
}
41+
};
42+
} catch (IllegalAccessException | NoSuchMethodException ignored) {
43+
}
44+
45+
MethodType methodType = MethodType.methodType(String.class);
46+
try {
47+
MethodHandle legacySpigotMethod = lookup.findVirtual(Player.Spigot.class, "getLocale", methodType);
48+
return player -> {
49+
try {
50+
Locale locale = Translator.parseLocale((String) legacySpigotMethod.invokeExact(player.spigot()));
51+
return locale == null ? DEFAULT_LOCALE : locale;
52+
} catch (Throwable e) {
53+
throw new RuntimeException(e);
54+
}
55+
};
56+
} catch (IllegalAccessException | NoSuchMethodException ignored) {
57+
}
58+
59+
try {
60+
MethodHandle legacyMethod = lookup.findVirtual(Player.class, "getLocale", methodType);
61+
return player -> {
62+
try {
63+
Locale locale = Translator.parseLocale((String) legacyMethod.invokeExact(player));
64+
return locale == null ? DEFAULT_LOCALE : locale;
65+
} catch (Throwable e) {
66+
throw new RuntimeException(e);
67+
}
68+
};
69+
} catch (IllegalAccessException | NoSuchMethodException ignored) {
70+
throw new RuntimeException("No way to get players locale found");
71+
}
72+
}
73+
}

platforms/standalone/src/main/java/me/tofaa/entitylib/standalone/StandaloneEntityLibPlatform.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
import me.tofaa.entitylib.APIConfig;
44
import me.tofaa.entitylib.EntityLibAPI;
5+
import me.tofaa.entitylib.UserLocaleProvider;
56
import me.tofaa.entitylib.common.AbstractPlatform;
7+
import java.util.Locale;
68
import org.jetbrains.annotations.NotNull;
79

810
public class StandaloneEntityLibPlatform extends AbstractPlatform<Object> {
911

1012

1113
private StandaloneEntityLibApi api;
14+
private UserLocaleProvider userLocaleProvider = (user) -> Locale.US;
1215

1316
public StandaloneEntityLibPlatform() {
1417
super(null);
@@ -34,4 +37,14 @@ public EntityLibAPI<?> getAPI() {
3437
public String getName() {
3538
return "Standalone";
3639
}
40+
41+
@Override
42+
public @NotNull UserLocaleProvider getUserLocaleProvider() {
43+
return userLocaleProvider;
44+
}
45+
46+
@Override
47+
public void setUserLocaleProvider(@NotNull final UserLocaleProvider provider) {
48+
this.userLocaleProvider = provider;
49+
}
3750
}

platforms/velocity/src/main/java/me/tofaa/entitylib/velocity/VelocityEntityLibPlatform.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
import io.github.retrooper.packetevents.velocity.factory.VelocityPacketEventsBuilder;
1010
import me.tofaa.entitylib.APIConfig;
1111
import me.tofaa.entitylib.EntityLibAPI;
12+
import me.tofaa.entitylib.UserLocaleProvider;
1213
import me.tofaa.entitylib.common.AbstractPlatform;
1314
import org.jetbrains.annotations.NotNull;
1415

1516
import java.util.logging.Logger;
1617

1718
public class VelocityEntityLibPlatform extends AbstractPlatform<ProxyServer> {
1819
private VelocityEntityLibAPI api;
20+
private UserLocaleProvider userLocaleProvider;
1921
private Object plugin;
2022

2123
public VelocityEntityLibPlatform(Object plugin, ProxyServer handle) {
@@ -54,4 +56,14 @@ public EntityLibAPI<?> getAPI() {
5456
public String getName() {
5557
return "Velocity";
5658
}
59+
60+
@Override
61+
public @NotNull UserLocaleProvider getUserLocaleProvider() {
62+
return userLocaleProvider;
63+
}
64+
65+
@Override
66+
public void setUserLocaleProvider(final UserLocaleProvider userLocaleProvider) {
67+
this.userLocaleProvider = userLocaleProvider;
68+
}
5769
}

0 commit comments

Comments
 (0)