mirror of
https://github.com/GeyserMC/Floodgate.git
synced 2025-12-19 14:59:20 +00:00
Reduce session server lookups (#509)
* fix: add default skin to gameprofiles * fix: add signatures by default to prevent issues * cleanup * no longer apply empty textures * revert formatting change * fix(spigot): linked player textures * fix(velocity): linked player textures * fix(bungeecord): apply linked textures * Made the MojangUtils class instance based, removed some unneeded code * Don't block Velocity event threads, made the Bungee variant work * Add some comments --------- Co-authored-by: bridge <haha@haha.com> Co-authored-by: Tim203 <mctim203@gmail.com>
This commit is contained in:
@@ -39,6 +39,7 @@ import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
|||||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||||
import net.md_5.bungee.api.event.PreLoginEvent;
|
import net.md_5.bungee.api.event.PreLoginEvent;
|
||||||
import net.md_5.bungee.api.plugin.Listener;
|
import net.md_5.bungee.api.plugin.Listener;
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
import net.md_5.bungee.connection.InitialHandler;
|
import net.md_5.bungee.connection.InitialHandler;
|
||||||
import net.md_5.bungee.event.EventHandler;
|
import net.md_5.bungee.event.EventHandler;
|
||||||
import net.md_5.bungee.event.EventPriority;
|
import net.md_5.bungee.event.EventPriority;
|
||||||
@@ -46,10 +47,10 @@ import net.md_5.bungee.netty.ChannelWrapper;
|
|||||||
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
|
||||||
import org.geysermc.floodgate.skin.SkinApplier;
|
import org.geysermc.floodgate.skin.SkinApplier;
|
||||||
import org.geysermc.floodgate.skin.SkinDataImpl;
|
import org.geysermc.floodgate.skin.SkinDataImpl;
|
||||||
import org.geysermc.floodgate.util.LanguageManager;
|
import org.geysermc.floodgate.util.LanguageManager;
|
||||||
|
import org.geysermc.floodgate.util.MojangUtils;
|
||||||
import org.geysermc.floodgate.util.ReflectionUtils;
|
import org.geysermc.floodgate.util.ReflectionUtils;
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
@@ -66,7 +67,7 @@ public final class BungeeListener implements Listener {
|
|||||||
checkNotNull(PLAYER_NAME, "Initial name field cannot be null");
|
checkNotNull(PLAYER_NAME, "Initial name field cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject private ProxyFloodgateConfig config;
|
@Inject private Plugin plugin;
|
||||||
@Inject private ProxyFloodgateApi api;
|
@Inject private ProxyFloodgateApi api;
|
||||||
@Inject private LanguageManager languageManager;
|
@Inject private LanguageManager languageManager;
|
||||||
@Inject private FloodgateLogger logger;
|
@Inject private FloodgateLogger logger;
|
||||||
@@ -80,6 +81,8 @@ public final class BungeeListener implements Listener {
|
|||||||
@Named("kickMessageAttribute")
|
@Named("kickMessageAttribute")
|
||||||
private AttributeKey<String> kickMessageAttribute;
|
private AttributeKey<String> kickMessageAttribute;
|
||||||
|
|
||||||
|
@Inject private MojangUtils mojangUtils;
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
public void onPreLogin(PreLoginEvent event) {
|
public void onPreLogin(PreLoginEvent event) {
|
||||||
// well, no reason to check if the player will be kicked anyway
|
// well, no reason to check if the player will be kicked anyway
|
||||||
@@ -127,13 +130,28 @@ public final class BungeeListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
public void onPostLogin(PostLoginEvent event) {
|
public void onPostLogin(PostLoginEvent event) {
|
||||||
// To fix the February 2 2022 Mojang authentication changes
|
|
||||||
if (!config.isSendFloodgateData()) {
|
|
||||||
FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId());
|
FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId());
|
||||||
if (player != null && !player.isLinked()) {
|
|
||||||
skinApplier.applySkin(player, new SkinDataImpl("", ""));
|
// Skin look up (on Spigot and friends) would result in it failing, so apply a default skin
|
||||||
}
|
if (!player.isLinked()) {
|
||||||
|
skinApplier.applySkin(player, SkinDataImpl.DEFAULT_SKIN);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Floodgate players are seen as offline mode players, meaning we have to look up
|
||||||
|
// the linked player's textures ourselves
|
||||||
|
|
||||||
|
event.registerIntent(plugin);
|
||||||
|
|
||||||
|
mojangUtils.skinFor(player.getJavaUniqueId())
|
||||||
|
.exceptionally(exception -> {
|
||||||
|
logger.debug("Unexpected skin fetch error for " + player.getJavaUniqueId(), exception);
|
||||||
|
return SkinDataImpl.DEFAULT_SKIN;
|
||||||
|
})
|
||||||
|
.thenAccept(skin -> {
|
||||||
|
skinApplier.applySkin(player, skin);
|
||||||
|
event.completeIntent(plugin);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
|||||||
@@ -92,8 +92,6 @@ public final class BungeeSkinApplier implements SkinApplier {
|
|||||||
SkinData currentSkin = currentSkin(properties);
|
SkinData currentSkin = currentSkin(properties);
|
||||||
|
|
||||||
SkinApplyEvent event = new SkinApplyEventImpl(floodgatePlayer, currentSkin, skinData);
|
SkinApplyEvent event = new SkinApplyEventImpl(floodgatePlayer, currentSkin, skinData);
|
||||||
event.setCancelled(floodgatePlayer.isLinked());
|
|
||||||
|
|
||||||
eventBus.fire(event);
|
eventBus.fire(event);
|
||||||
|
|
||||||
if (event.isCancelled()) {
|
if (event.isCancelled()) {
|
||||||
|
|||||||
@@ -29,8 +29,14 @@ import com.google.gson.JsonObject;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
|
||||||
|
import org.geysermc.floodgate.util.Constants;
|
||||||
|
|
||||||
public class SkinDataImpl implements SkinData {
|
public class SkinDataImpl implements SkinData {
|
||||||
|
public static final SkinData DEFAULT_SKIN = new SkinDataImpl(
|
||||||
|
Constants.DEFAULT_MINECRAFT_JAVA_SKIN_TEXTURE,
|
||||||
|
Constants.DEFAULT_MINECRAFT_JAVA_SKIN_SIGNATURE
|
||||||
|
);
|
||||||
|
|
||||||
private final String value;
|
private final String value;
|
||||||
private final String signature;
|
private final String signature;
|
||||||
|
|
||||||
|
|||||||
110
core/src/main/java/org/geysermc/floodgate/util/MojangUtils.java
Normal file
110
core/src/main/java/org/geysermc/floodgate/util/MojangUtils.java
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @author GeyserMC
|
||||||
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.geysermc.floodgate.util;
|
||||||
|
|
||||||
|
import com.google.common.cache.Cache;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
import com.google.inject.name.Named;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
|
||||||
|
import org.geysermc.floodgate.skin.SkinDataImpl;
|
||||||
|
import org.geysermc.floodgate.util.HttpClient.HttpResponse;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class MojangUtils {
|
||||||
|
private final Cache<UUID, SkinData> SKIN_CACHE = CacheBuilder.newBuilder()
|
||||||
|
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||||
|
.maximumSize(500)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
@Inject private HttpClient httpClient;
|
||||||
|
@Inject
|
||||||
|
@Named("commonPool")
|
||||||
|
private ExecutorService commonPool;
|
||||||
|
|
||||||
|
public CompletableFuture<@NonNull SkinData> skinFor(UUID playerId) {
|
||||||
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
|
try {
|
||||||
|
return SKIN_CACHE.get(playerId, () -> fetchSkinFor(playerId));
|
||||||
|
} catch (ExecutionException exception) {
|
||||||
|
throw new RuntimeException(exception.getCause());
|
||||||
|
}
|
||||||
|
}, commonPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
private @NonNull SkinData fetchSkinFor(UUID playerId) {
|
||||||
|
HttpResponse<JsonObject> httpResponse = httpClient.get(
|
||||||
|
String.format(Constants.PROFILE_WITH_PROPERTIES_URL, playerId.toString()));
|
||||||
|
|
||||||
|
if (httpResponse.getHttpCode() != 200) {
|
||||||
|
return SkinDataImpl.DEFAULT_SKIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject response = httpResponse.getResponse();
|
||||||
|
|
||||||
|
if (response == null) {
|
||||||
|
return SkinDataImpl.DEFAULT_SKIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonArray properties = response.getAsJsonArray("properties");
|
||||||
|
|
||||||
|
if (properties.size() == 0) {
|
||||||
|
return SkinDataImpl.DEFAULT_SKIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (JsonElement property : properties) {
|
||||||
|
if (!property.isJsonObject()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject propertyObject = property.getAsJsonObject();
|
||||||
|
|
||||||
|
if (!propertyObject.has("name")
|
||||||
|
|| !propertyObject.has("value")
|
||||||
|
|| !propertyObject.has("signature")
|
||||||
|
|| !propertyObject.get("name").getAsString().equals("textures")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SkinDataImpl(
|
||||||
|
propertyObject.get("value").getAsString(),
|
||||||
|
propertyObject.get("signature").getAsString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SkinDataImpl.DEFAULT_SKIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,6 +56,9 @@ public final class Constants {
|
|||||||
public static final String LATEST_VERSION_URL =
|
public static final String LATEST_VERSION_URL =
|
||||||
"https://download.geysermc.org/v2/projects/%s/versions/latest/builds/latest";
|
"https://download.geysermc.org/v2/projects/%s/versions/latest/builds/latest";
|
||||||
|
|
||||||
|
public static final String PROFILE_WITH_PROPERTIES_URL =
|
||||||
|
"https://sessionserver.mojang.com/session/minecraft/profile/%s?unsigned=false";
|
||||||
|
|
||||||
|
|
||||||
public static final String NTP_SERVER = "time.cloudflare.com";
|
public static final String NTP_SERVER = "time.cloudflare.com";
|
||||||
public static final String INTERNAL_ERROR_MESSAGE =
|
public static final String INTERNAL_ERROR_MESSAGE =
|
||||||
@@ -70,4 +73,7 @@ public final class Constants {
|
|||||||
public static final int HANDSHAKE_PACKET_ID = 0;
|
public static final int HANDSHAKE_PACKET_ID = 0;
|
||||||
public static final int LOGIN_SUCCESS_PACKET_ID = 2;
|
public static final int LOGIN_SUCCESS_PACKET_ID = 2;
|
||||||
public static final int SET_COMPRESSION_PACKET_ID = 3;
|
public static final int SET_COMPRESSION_PACKET_ID = 3;
|
||||||
|
|
||||||
|
public static final String DEFAULT_MINECRAFT_JAVA_SKIN_TEXTURE = "ewogICJ0aW1lc3RhbXAiIDogMTcxNTcxNzM1NTI2MywKICAicHJvZmlsZUlkIiA6ICIyMWUzNjdkNzI1Y2Y0ZTNiYjI2OTJjNGEzMDBhNGRlYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJHZXlzZXJNQyIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS8zMWY0NzdlYjFhN2JlZWU2MzFjMmNhNjRkMDZmOGY2OGZhOTNhMzM4NmQwNDQ1MmFiMjdmNDNhY2RmMWI2MGNiIgogICAgfQogIH0KfQ";
|
||||||
|
public static final String DEFAULT_MINECRAFT_JAVA_SKIN_SIGNATURE = "dFKIZ5d6vNqCSe1IFGiVLjt3cnW8qh4qNP2umg9zqkX9bvAQawuR1iuO1kCD/+ye8A6GQFv2wRCdxdrjp5+Vrr0SsWqMnsYDN8cEg6CD18mAnaKI1TYDuGbdJaqLyGqN5wqSMdHxchs9iovFkde5ir4aYdvHkA11vOTi11L4kUzETGzJ4iKVuZOv4dq+B7wFAWqp4n8QZfhixyvemFazQHlLmxnuhU+jhpZMvYY9MAaRAJonfy/wJe9LymbTe0EJ8N+NwZQDrEUzgfBFo4OIGDqRZwvydInCqkjhPMtHCSL25VOKwcFocYpRYbk4eIKM4CLjYlBiQGki+XKsPaljwjVhnT0jUupSf7yraGb3T0CsVBjhDbIIIp9nytlbO0GvxHu0TzYjkr4Iji0do5jlCKQ/OasXcL21wd6ozw0t1QZnnzxi9ewSuyYVY9ErmWdkww1OtCIgJilceEBwNAB8+mhJ062WFaYPgJQAmOREM8InW33dbbeENMFhQi4LIO5P7p9ye3B4Lrwm20xtd9wJk3lewzcs8ezh0LUF6jPSDQDivgSKU49mLCTmOi+WZh8zKjjxfVEtNZON2W+3nct0LiWBVsQ55HzlvF0FFxuRVm6pxi6MQK2ernv3DQl0hUqyQ1+RV9nfZXTQOAUzwLjKx3t2zKqyZIiNEKLE+iAXrsE=";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import static org.geysermc.floodgate.util.ReflectionUtils.getCastedValue;
|
|||||||
import static org.geysermc.floodgate.util.ReflectionUtils.setValue;
|
import static org.geysermc.floodgate.util.ReflectionUtils.setValue;
|
||||||
|
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import com.mojang.authlib.properties.Property;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
@@ -38,9 +39,16 @@ import org.geysermc.floodgate.config.FloodgateConfig;
|
|||||||
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
|
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
|
||||||
import org.geysermc.floodgate.player.FloodgateHandshakeHandler.HandshakeResult;
|
import org.geysermc.floodgate.player.FloodgateHandshakeHandler.HandshakeResult;
|
||||||
import org.geysermc.floodgate.util.ClassNames;
|
import org.geysermc.floodgate.util.ClassNames;
|
||||||
|
import org.geysermc.floodgate.util.Constants;
|
||||||
import org.geysermc.floodgate.util.ProxyUtils;
|
import org.geysermc.floodgate.util.ProxyUtils;
|
||||||
|
|
||||||
public final class SpigotDataHandler extends CommonDataHandler {
|
public final class SpigotDataHandler extends CommonDataHandler {
|
||||||
|
private static final Property DEFAULT_TEXTURE_PROPERTY = new Property(
|
||||||
|
"textures",
|
||||||
|
Constants.DEFAULT_MINECRAFT_JAVA_SKIN_TEXTURE,
|
||||||
|
Constants.DEFAULT_MINECRAFT_JAVA_SKIN_SIGNATURE
|
||||||
|
);
|
||||||
|
|
||||||
private Object networkManager;
|
private Object networkManager;
|
||||||
private FloodgatePlayer player;
|
private FloodgatePlayer player;
|
||||||
private boolean proxyData;
|
private boolean proxyData;
|
||||||
@@ -171,6 +179,13 @@ public final class SpigotDataHandler extends CommonDataHandler {
|
|||||||
player.getCorrectUniqueId(), player.getCorrectUsername()
|
player.getCorrectUniqueId(), player.getCorrectUsername()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!player.isLinked()) {
|
||||||
|
// Otherwise game server will try to fetch the skin from Mojang.
|
||||||
|
// No need to worry that this overrides proxy data, because those won't reach this
|
||||||
|
// method / are already removed (in the case of username validation)
|
||||||
|
gameProfile.getProperties().put("textures", DEFAULT_TEXTURE_PROPERTY);
|
||||||
|
}
|
||||||
|
|
||||||
// we have to fake the offline player (login) cycle
|
// we have to fake the offline player (login) cycle
|
||||||
|
|
||||||
if (ClassNames.IS_PRE_1_20_2) {
|
if (ClassNames.IS_PRE_1_20_2) {
|
||||||
|
|||||||
@@ -26,20 +26,24 @@
|
|||||||
package org.geysermc.floodgate.listener;
|
package org.geysermc.floodgate.listener;
|
||||||
|
|
||||||
import com.destroystokyo.paper.event.profile.PreFillProfileEvent;
|
import com.destroystokyo.paper.event.profile.PreFillProfileEvent;
|
||||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
|
||||||
import com.destroystokyo.paper.profile.ProfileProperty;
|
import com.destroystokyo.paper.profile.ProfileProperty;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
|
import org.geysermc.floodgate.util.Constants;
|
||||||
|
|
||||||
public final class PaperProfileListener implements Listener {
|
public final class PaperProfileListener implements Listener {
|
||||||
|
private static final ProfileProperty DEFAULT_TEXTURE_PROPERTY = new ProfileProperty(
|
||||||
|
"textures",
|
||||||
|
Constants.DEFAULT_MINECRAFT_JAVA_SKIN_TEXTURE,
|
||||||
|
Constants.DEFAULT_MINECRAFT_JAVA_SKIN_SIGNATURE
|
||||||
|
);
|
||||||
|
|
||||||
@Inject private SimpleFloodgateApi api;
|
@Inject private SimpleFloodgateApi api;
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@@ -62,26 +66,8 @@ public final class PaperProfileListener implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Set<ProfileProperty> properties = new HashSet<>(event.getPlayerProfile().getProperties());
|
Set<ProfileProperty> properties = new HashSet<>(event.getPlayerProfile().getProperties());
|
||||||
properties.add(new ProfileProperty("textures", "", ""));
|
properties.add(DEFAULT_TEXTURE_PROPERTY);
|
||||||
|
|
||||||
event.setProperties(properties);
|
event.setProperties(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
|
||||||
Player bukkitPlayer = event.getPlayer();
|
|
||||||
FloodgatePlayer player = api.getPlayer(bukkitPlayer.getUniqueId());
|
|
||||||
if (player == null || player.isLinked()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayerProfile profile = bukkitPlayer.getPlayerProfile();
|
|
||||||
if (profile.getProperties().stream().noneMatch(
|
|
||||||
prop -> "textures".equals(prop.getName()) && prop.getValue().isEmpty()
|
|
||||||
&& prop.getSignature() != null && prop.getSignature().isEmpty())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
profile.removeProperty("textures");
|
|
||||||
bukkitPlayer.setPlayerProfile(profile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import com.google.common.cache.Cache;
|
|||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.name.Named;
|
import com.google.inject.name.Named;
|
||||||
|
import com.velocitypowered.api.event.Continuation;
|
||||||
import com.velocitypowered.api.event.PostOrder;
|
import com.velocitypowered.api.event.PostOrder;
|
||||||
import com.velocitypowered.api.event.Subscribe;
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
import com.velocitypowered.api.event.connection.DisconnectEvent;
|
import com.velocitypowered.api.event.connection.DisconnectEvent;
|
||||||
@@ -48,7 +49,7 @@ import com.velocitypowered.api.util.GameProfile.Property;
|
|||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Collections;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
@@ -56,12 +57,16 @@ import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
|||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
||||||
|
import org.geysermc.floodgate.skin.SkinDataImpl;
|
||||||
|
import org.geysermc.floodgate.util.Constants;
|
||||||
import org.geysermc.floodgate.util.LanguageManager;
|
import org.geysermc.floodgate.util.LanguageManager;
|
||||||
|
import org.geysermc.floodgate.util.MojangUtils;
|
||||||
|
|
||||||
public final class VelocityListener {
|
public final class VelocityListener {
|
||||||
private static final Field INITIAL_MINECRAFT_CONNECTION;
|
private static final Field INITIAL_MINECRAFT_CONNECTION;
|
||||||
private static final Field INITIAL_CONNECTION_DELEGATE;
|
private static final Field INITIAL_CONNECTION_DELEGATE;
|
||||||
private static final Field CHANNEL;
|
private static final Field CHANNEL;
|
||||||
|
private static final Property DEFAULT_TEXTURE_PROPERTY;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Class<?> initialConnection = getPrefixedClass("connection.client.InitialInboundConnection");
|
Class<?> initialConnection = getPrefixedClass("connection.client.InitialInboundConnection");
|
||||||
@@ -82,6 +87,12 @@ public final class VelocityListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CHANNEL = getFieldOfType(minecraftConnection, Channel.class);
|
CHANNEL = getFieldOfType(minecraftConnection, Channel.class);
|
||||||
|
|
||||||
|
DEFAULT_TEXTURE_PROPERTY = new Property(
|
||||||
|
"textures",
|
||||||
|
Constants.DEFAULT_MINECRAFT_JAVA_SKIN_TEXTURE,
|
||||||
|
Constants.DEFAULT_MINECRAFT_JAVA_SKIN_SIGNATURE
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Cache<InboundConnection, FloodgatePlayer> playerCache =
|
private final Cache<InboundConnection, FloodgatePlayer> playerCache =
|
||||||
@@ -103,6 +114,9 @@ public final class VelocityListener {
|
|||||||
@Named("kickMessageAttribute")
|
@Named("kickMessageAttribute")
|
||||||
private AttributeKey<String> kickMessageAttribute;
|
private AttributeKey<String> kickMessageAttribute;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private MojangUtils mojangUtils;
|
||||||
|
|
||||||
@Subscribe(order = PostOrder.EARLY)
|
@Subscribe(order = PostOrder.EARLY)
|
||||||
public void onPreLogin(PreLoginEvent event) {
|
public void onPreLogin(PreLoginEvent event) {
|
||||||
FloodgatePlayer player = null;
|
FloodgatePlayer player = null;
|
||||||
@@ -139,22 +153,38 @@ public final class VelocityListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(order = PostOrder.EARLY)
|
@Subscribe(order = PostOrder.EARLY)
|
||||||
public void onGameProfileRequest(GameProfileRequestEvent event) {
|
public void onGameProfileRequest(GameProfileRequestEvent event, Continuation continuation) {
|
||||||
FloodgatePlayer player = playerCache.getIfPresent(event.getConnection());
|
FloodgatePlayer player = playerCache.getIfPresent(event.getConnection());
|
||||||
if (player != null) {
|
if (player == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
playerCache.invalidate(event.getConnection());
|
playerCache.invalidate(event.getConnection());
|
||||||
|
|
||||||
GameProfile profile = new GameProfile(
|
// Skin look up (on Spigot and friends) would result in it failing, so apply a default skin
|
||||||
|
if (!player.isLinked()) {
|
||||||
|
event.setGameProfile(new GameProfile(
|
||||||
player.getCorrectUniqueId(),
|
player.getCorrectUniqueId(),
|
||||||
player.getCorrectUsername(),
|
player.getCorrectUsername(),
|
||||||
Collections.emptyList()
|
List.of(DEFAULT_TEXTURE_PROPERTY)
|
||||||
);
|
));
|
||||||
// The texture properties addition is to fix the February 2 2022 Mojang authentication changes
|
return;
|
||||||
if (!config.isSendFloodgateData() && !player.isLinked()) {
|
|
||||||
profile = profile.addProperty(new Property("textures", "", ""));
|
|
||||||
}
|
|
||||||
event.setGameProfile(profile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Floodgate players are seen as offline mode players, meaning we have to look up
|
||||||
|
// the linked player's textures ourselves
|
||||||
|
|
||||||
|
mojangUtils.skinFor(player.getJavaUniqueId())
|
||||||
|
.exceptionally(exception -> {
|
||||||
|
logger.debug("Unexpected skin fetch error for " + player.getJavaUniqueId(), exception);
|
||||||
|
return SkinDataImpl.DEFAULT_SKIN;
|
||||||
|
}).thenAccept(skin -> {
|
||||||
|
event.setGameProfile(new GameProfile(
|
||||||
|
player.getCorrectUniqueId(),
|
||||||
|
player.getCorrectUsername(),
|
||||||
|
List.of(new Property("textures", skin.value(), skin.signature()))
|
||||||
|
));
|
||||||
|
continuation.resume();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(order = PostOrder.LAST)
|
@Subscribe(order = PostOrder.LAST)
|
||||||
|
|||||||
Reference in New Issue
Block a user