Merge pull request #40 from huanmeng-qwq/feat/translation-render
Add support for GlobalTranslator
This commit is contained in:
commit
bff89d2fac
11 changed files with 220 additions and 16 deletions
|
@ -53,4 +53,6 @@ public interface EntityLibAPI<T> {
|
|||
@NotNull
|
||||
EntityContainer getDefaultContainer();
|
||||
|
||||
@NotNull
|
||||
UserLocaleProvider getUserLocaleProvider();
|
||||
}
|
||||
|
|
|
@ -26,6 +26,13 @@ public interface Platform<P> {
|
|||
*/
|
||||
@NotNull EntityUuidProvider getEntityUuidProvider();
|
||||
|
||||
/**
|
||||
* Gets the provider responsible for retrieving the locale of a user.
|
||||
*
|
||||
* @return a non-null {@link UserLocaleProvider} instance.
|
||||
*/
|
||||
@NotNull UserLocaleProvider getUserLocaleProvider();
|
||||
|
||||
/**
|
||||
* Sets the entityId integer provider. This can be provided by a platform if needed.
|
||||
* @param provider the entityId integer provider.
|
||||
|
@ -38,6 +45,12 @@ public interface Platform<P> {
|
|||
*/
|
||||
void setEntityUuidProvider(@NotNull EntityUuidProvider provider);
|
||||
|
||||
/**
|
||||
* Sets the provider responsible for retrieving the locale of a user.
|
||||
*
|
||||
* @param provider the {@link UserLocaleProvider} instance to be set. Must not be null.
|
||||
*/
|
||||
void setUserLocaleProvider(@NotNull UserLocaleProvider provider);
|
||||
|
||||
/**
|
||||
* @return the logger EntityLib uses internally.
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package me.tofaa.entitylib;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface UserLocaleProvider {
|
||||
Locale locale(UUID user);
|
||||
}
|
34
api/src/main/java/me/tofaa/entitylib/utils/PacketUtil.java
Normal file
34
api/src/main/java/me/tofaa/entitylib/utils/PacketUtil.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
package me.tofaa.entitylib.utils;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
|
||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
|
||||
import me.tofaa.entitylib.EntityLib;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.translation.GlobalTranslator;
|
||||
|
||||
public class PacketUtil {
|
||||
private PacketUtil() {
|
||||
}
|
||||
|
||||
public static void renderPacket(UUID user, WrapperPlayServerEntityMetadata metadata) {
|
||||
Locale locale = EntityLib.getApi().getUserLocaleProvider().locale(user);
|
||||
for (final EntityData<?> entityData : metadata.getEntityMetadata()) {
|
||||
if (entityData.getType() == EntityDataTypes.ADV_COMPONENT) {
|
||||
Component component = (Component) entityData.getValue();
|
||||
final Component rendered = GlobalTranslator.render(component, locale);
|
||||
((EntityData<Component>) entityData).setValue(rendered);
|
||||
} else if (entityData.getType() == EntityDataTypes.OPTIONAL_ADV_COMPONENT) {
|
||||
final Optional<Component> optional = (Optional<Component>) entityData.getValue();
|
||||
if (optional.isPresent()) {
|
||||
final Component component = optional.get();
|
||||
final Component rendered = GlobalTranslator.render(component, locale);
|
||||
((EntityData<Optional<Component>>) entityData).setValue(Optional.of(rendered));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,25 +5,39 @@ import com.github.retrooper.packetevents.protocol.player.User;
|
|||
import com.github.retrooper.packetevents.protocol.world.Location;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.*;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerBundle;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityHeadLook;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRotation;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityTeleport;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityVelocity;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetPassengers;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSystemChatMessage;
|
||||
import me.tofaa.entitylib.EntityLib;
|
||||
import me.tofaa.entitylib.container.EntityContainer;
|
||||
import me.tofaa.entitylib.meta.EntityMeta;
|
||||
import me.tofaa.entitylib.meta.types.ObjectData;
|
||||
import me.tofaa.entitylib.tick.Tickable;
|
||||
import me.tofaa.entitylib.utils.PacketUtil;
|
||||
import me.tofaa.entitylib.ve.ViewerRule;
|
||||
import me.tofaa.entitylib.wrapper.spawning.SpawnPacketProvider;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.Consumer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnmodifiableView;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class WrapperEntity implements Tickable {
|
||||
private final UUID uuid;
|
||||
private final int entityId;
|
||||
|
@ -510,6 +524,11 @@ public class WrapperEntity implements Tickable {
|
|||
return;
|
||||
}
|
||||
|
||||
// Special handling for entity metadata packets to support `GlobalTranslator` functionality and component rendering
|
||||
if (wrapper instanceof WrapperPlayServerEntityMetadata) {
|
||||
PacketUtil.renderPacket(user, (WrapperPlayServerEntityMetadata) wrapper);
|
||||
}
|
||||
|
||||
EntityLib.getApi().getPacketEvents().getProtocolManager().sendPacket(channel, wrapper);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.github.retrooper.packetevents.PacketEventsAPI;
|
|||
import me.tofaa.entitylib.APIConfig;
|
||||
import me.tofaa.entitylib.EntityLibAPI;
|
||||
import me.tofaa.entitylib.Platform;
|
||||
import me.tofaa.entitylib.UserLocaleProvider;
|
||||
import me.tofaa.entitylib.container.EntityContainer;
|
||||
import me.tofaa.entitylib.tick.TickContainer;
|
||||
import me.tofaa.entitylib.wrapper.WrapperEntity;
|
||||
|
@ -63,4 +64,9 @@ public abstract class AbstractEntityLibAPI<P, T> implements EntityLibAPI<T> {
|
|||
public @NotNull Collection<TickContainer<?, T>> getTickContainers() {
|
||||
return tickContainers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull UserLocaleProvider getUserLocaleProvider() {
|
||||
return platform.getUserLocaleProvider();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,23 +5,17 @@ import io.github.retrooper.packetevents.bstats.bukkit.Metrics;
|
|||
import io.github.retrooper.packetevents.bstats.charts.SimplePie;
|
||||
import me.tofaa.entitylib.APIConfig;
|
||||
import me.tofaa.entitylib.EntityLib;
|
||||
import me.tofaa.entitylib.UserLocaleProvider;
|
||||
import me.tofaa.entitylib.common.AbstractPlatform;
|
||||
import me.tofaa.entitylib.utils.ConcurrentWeakIdentityHashMap;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import java.util.logging.Logger;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SpigotEntityLibPlatform extends AbstractPlatform<JavaPlugin> {
|
||||
|
||||
private SpigotEntityLibAPI api;
|
||||
private UserLocaleProvider userLocaleProvider = new SpigotPlayerLocaleProvider();
|
||||
|
||||
public SpigotEntityLibPlatform(@NotNull JavaPlugin plugin) {
|
||||
super(plugin);
|
||||
|
@ -36,7 +30,7 @@ public class SpigotEntityLibPlatform extends AbstractPlatform<JavaPlugin> {
|
|||
this.api.onLoad();
|
||||
this.api.onEnable();
|
||||
if (settings.shouldUseBstats()) {
|
||||
PacketEventsAPI<Plugin> pe = (PacketEventsAPI<Plugin>)api.getPacketEvents();
|
||||
PacketEventsAPI<Plugin> pe = (PacketEventsAPI<Plugin>) api.getPacketEvents();
|
||||
Metrics metrics = new Metrics(pe.getPlugin(), 21916);
|
||||
metrics.addCustomChart(new SimplePie("entitylib-version", () -> EntityLib.getVersion().toString()));
|
||||
}
|
||||
|
@ -52,4 +46,14 @@ public class SpigotEntityLibPlatform extends AbstractPlatform<JavaPlugin> {
|
|||
public String getName() {
|
||||
return "Spigot";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull UserLocaleProvider getUserLocaleProvider() {
|
||||
return userLocaleProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserLocaleProvider(@NotNull final UserLocaleProvider provider) {
|
||||
this.userLocaleProvider = provider;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
package me.tofaa.entitylib.spigot;
|
||||
|
||||
import me.tofaa.entitylib.UserLocaleProvider;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import net.kyori.adventure.translation.Translator;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
/**
|
||||
* This implementation is based on code from the scoreboard-library project:
|
||||
* <a href="https://github.com/MegavexNetwork/scoreboard-library/blob/bc8e3c2d2ecf9973ec0d6bb8ae4af94ed008b360/commons/src/main/java/net/megavex/scoreboardlibrary/implementation/commons/LocaleProvider.java">LocaleProvider</a>
|
||||
* Modified and adapted for use in EntityLib.
|
||||
*/
|
||||
public class SpigotPlayerLocaleProvider implements UserLocaleProvider {
|
||||
private static final Locale DEFAULT_LOCALE = Locale.US;
|
||||
private static final Function<Player, Locale> provider = get();
|
||||
|
||||
@Override
|
||||
public Locale locale(final UUID user) {
|
||||
final Player player = Bukkit.getPlayer(user);
|
||||
return player == null ? DEFAULT_LOCALE : provider.apply(player);
|
||||
}
|
||||
|
||||
private static @NotNull Function<Player, Locale> get() {
|
||||
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
|
||||
try {
|
||||
MethodHandle adventureMethod = lookup.findVirtual(Player.class, "locale", MethodType.methodType(Locale.class));
|
||||
return player -> {
|
||||
try {
|
||||
return (Locale) adventureMethod.invokeExact(player);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
} catch (IllegalAccessException | NoSuchMethodException ignored) {
|
||||
}
|
||||
|
||||
MethodType methodType = MethodType.methodType(String.class);
|
||||
try {
|
||||
MethodHandle legacySpigotMethod = lookup.findVirtual(Player.Spigot.class, "getLocale", methodType);
|
||||
return player -> {
|
||||
try {
|
||||
Locale locale = Translator.parseLocale((String) legacySpigotMethod.invokeExact(player.spigot()));
|
||||
return locale == null ? DEFAULT_LOCALE : locale;
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
} catch (IllegalAccessException | NoSuchMethodException ignored) {
|
||||
}
|
||||
|
||||
try {
|
||||
MethodHandle legacyMethod = lookup.findVirtual(Player.class, "getLocale", methodType);
|
||||
return player -> {
|
||||
try {
|
||||
Locale locale = Translator.parseLocale((String) legacyMethod.invokeExact(player));
|
||||
return locale == null ? DEFAULT_LOCALE : locale;
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
} catch (IllegalAccessException | NoSuchMethodException ignored) {
|
||||
throw new RuntimeException("No way to get players locale found");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,13 +2,16 @@ package me.tofaa.entitylib.standalone;
|
|||
|
||||
import me.tofaa.entitylib.APIConfig;
|
||||
import me.tofaa.entitylib.EntityLibAPI;
|
||||
import me.tofaa.entitylib.UserLocaleProvider;
|
||||
import me.tofaa.entitylib.common.AbstractPlatform;
|
||||
import java.util.Locale;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class StandaloneEntityLibPlatform extends AbstractPlatform<Object> {
|
||||
|
||||
|
||||
private StandaloneEntityLibApi api;
|
||||
private UserLocaleProvider userLocaleProvider = (user) -> Locale.US;
|
||||
|
||||
public StandaloneEntityLibPlatform() {
|
||||
super(null);
|
||||
|
@ -34,4 +37,14 @@ public class StandaloneEntityLibPlatform extends AbstractPlatform<Object> {
|
|||
public String getName() {
|
||||
return "Standalone";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull UserLocaleProvider getUserLocaleProvider() {
|
||||
return userLocaleProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserLocaleProvider(@NotNull final UserLocaleProvider provider) {
|
||||
this.userLocaleProvider = provider;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import com.velocitypowered.api.proxy.ProxyServer;
|
|||
import io.github.retrooper.packetevents.velocity.factory.VelocityPacketEventsBuilder;
|
||||
import me.tofaa.entitylib.APIConfig;
|
||||
import me.tofaa.entitylib.EntityLibAPI;
|
||||
import me.tofaa.entitylib.UserLocaleProvider;
|
||||
import me.tofaa.entitylib.common.AbstractPlatform;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
@ -16,6 +17,7 @@ import java.util.logging.Logger;
|
|||
|
||||
public class VelocityEntityLibPlatform extends AbstractPlatform<ProxyServer> {
|
||||
private VelocityEntityLibAPI api;
|
||||
private UserLocaleProvider userLocaleProvider;
|
||||
private Object plugin;
|
||||
|
||||
public VelocityEntityLibPlatform(Object plugin, ProxyServer handle) {
|
||||
|
@ -54,4 +56,14 @@ public class VelocityEntityLibPlatform extends AbstractPlatform<ProxyServer> {
|
|||
public String getName() {
|
||||
return "Velocity";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull UserLocaleProvider getUserLocaleProvider() {
|
||||
return userLocaleProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserLocaleProvider(final UserLocaleProvider userLocaleProvider) {
|
||||
this.userLocaleProvider = userLocaleProvider;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package me.tofaa.entitylib.velocity;
|
||||
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import me.tofaa.entitylib.UserLocaleProvider;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
public class VelocityPlayerLocaleProvider implements UserLocaleProvider {
|
||||
private final ProxyServer proxyServer;
|
||||
|
||||
public VelocityPlayerLocaleProvider(final ProxyServer proxyServer) {
|
||||
this.proxyServer = proxyServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale locale(final UUID user) {
|
||||
return proxyServer.getPlayer(user).map(Player::getEffectiveLocale).orElse(Locale.US);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue