mirror of
https://github.com/GeyserMC/Floodgate.git
synced 2025-12-22 00:11:37 +00:00
Added a SkinApplyEvent that can cancel/edit the to be applied skin
This commit is contained in:
@@ -30,6 +30,7 @@ import java.util.UUID;
|
|||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import org.geysermc.cumulus.form.Form;
|
import org.geysermc.cumulus.form.Form;
|
||||||
import org.geysermc.cumulus.form.util.FormBuilder;
|
import org.geysermc.cumulus.form.util.FormBuilder;
|
||||||
|
import org.geysermc.floodgate.api.event.FloodgateEventBus;
|
||||||
import org.geysermc.floodgate.api.link.PlayerLink;
|
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
import org.geysermc.floodgate.api.unsafe.Unsafe;
|
import org.geysermc.floodgate.api.unsafe.Unsafe;
|
||||||
@@ -148,6 +149,10 @@ public interface FloodgateApi {
|
|||||||
*/
|
*/
|
||||||
CompletableFuture<String> getGamertagFor(long xuid);
|
CompletableFuture<String> getGamertagFor(long xuid);
|
||||||
|
|
||||||
|
default FloodgateEventBus getEventBus() {
|
||||||
|
return InstanceHolder.getEventBus();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the instance that manages all the linking.
|
* Returns the instance that manages all the linking.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ package org.geysermc.floodgate.api;
|
|||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import org.geysermc.floodgate.api.event.FloodgateEventBus;
|
||||||
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
||||||
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
||||||
import org.geysermc.floodgate.api.link.PlayerLink;
|
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||||
@@ -35,6 +36,7 @@ import org.geysermc.floodgate.api.packet.PacketHandlers;
|
|||||||
public final class InstanceHolder {
|
public final class InstanceHolder {
|
||||||
@Getter private static FloodgateApi api;
|
@Getter private static FloodgateApi api;
|
||||||
@Getter private static PlayerLink playerLink;
|
@Getter private static PlayerLink playerLink;
|
||||||
|
@Getter private static FloodgateEventBus eventBus;
|
||||||
|
|
||||||
@Getter private static PlatformInjector injector;
|
@Getter private static PlatformInjector injector;
|
||||||
@Getter private static PacketHandlers packetHandlers;
|
@Getter private static PacketHandlers packetHandlers;
|
||||||
@@ -44,11 +46,12 @@ public final class InstanceHolder {
|
|||||||
public static boolean set(
|
public static boolean set(
|
||||||
FloodgateApi floodgateApi,
|
FloodgateApi floodgateApi,
|
||||||
PlayerLink link,
|
PlayerLink link,
|
||||||
|
FloodgateEventBus floodgateEventBus,
|
||||||
PlatformInjector platformInjector,
|
PlatformInjector platformInjector,
|
||||||
PacketHandlers packetHandlers,
|
PacketHandlers packetHandlers,
|
||||||
HandshakeHandlers handshakeHandlers,
|
HandshakeHandlers handshakeHandlers,
|
||||||
UUID key) {
|
UUID key
|
||||||
|
) {
|
||||||
if (storedKey != null) {
|
if (storedKey != null) {
|
||||||
if (!storedKey.equals(key)) {
|
if (!storedKey.equals(key)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -59,14 +62,10 @@ public final class InstanceHolder {
|
|||||||
|
|
||||||
api = floodgateApi;
|
api = floodgateApi;
|
||||||
playerLink = link;
|
playerLink = link;
|
||||||
|
eventBus = floodgateEventBus;
|
||||||
injector = platformInjector;
|
injector = platformInjector;
|
||||||
InstanceHolder.packetHandlers = packetHandlers;
|
InstanceHolder.packetHandlers = packetHandlers;
|
||||||
InstanceHolder.handshakeHandlers = handshakeHandlers;
|
InstanceHolder.handshakeHandlers = handshakeHandlers;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T extends FloodgateApi> T castApi(Class<T> cast) {
|
|
||||||
return (T) api;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 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.api.event;
|
||||||
|
|
||||||
|
import org.geysermc.event.bus.EventBus;
|
||||||
|
|
||||||
|
public interface FloodgateEventBus extends EventBus<Object, FloodgateSubscriber<?>> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 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.api.event;
|
||||||
|
|
||||||
|
import org.geysermc.event.subscribe.Subscriber;
|
||||||
|
|
||||||
|
public interface FloodgateSubscriber<T> extends Subscriber<T> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 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.api.event.skin;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.checkerframework.common.returnsreceiver.qual.This;
|
||||||
|
import org.geysermc.event.Cancellable;
|
||||||
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that's fired when Floodgate receives a player skin. The event will be cancelled by
|
||||||
|
* default when hasSkin is true, as Floodgate by default only applies skins when the player has no
|
||||||
|
* skin applied yet.
|
||||||
|
*/
|
||||||
|
public interface SkinApplyEvent extends Cancellable {
|
||||||
|
/**
|
||||||
|
* Returns the player that will receive the skin.
|
||||||
|
*/
|
||||||
|
@NonNull FloodgatePlayer player();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the skin texture currently applied to the player.
|
||||||
|
*/
|
||||||
|
@Nullable SkinData currentSkin();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the skin texture to be applied to the player.
|
||||||
|
*/
|
||||||
|
@NonNull SkinData newSkin();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the skin texture to be applied to the player
|
||||||
|
*
|
||||||
|
* @param skinData the skin to apply
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
@This SkinApplyEvent newSkin(@NonNull SkinData skinData);
|
||||||
|
|
||||||
|
interface SkinData {
|
||||||
|
/**
|
||||||
|
* Returns the value of the skin texture.
|
||||||
|
*/
|
||||||
|
@NonNull String value();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the signature of the skin texture.
|
||||||
|
*/
|
||||||
|
@NonNull String signature();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,7 +48,7 @@ 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.SkinApplier;
|
import org.geysermc.floodgate.skin.SkinApplier;
|
||||||
import org.geysermc.floodgate.skin.SkinData;
|
import org.geysermc.floodgate.skin.SkinDataImpl;
|
||||||
import org.geysermc.floodgate.util.LanguageManager;
|
import org.geysermc.floodgate.util.LanguageManager;
|
||||||
import org.geysermc.floodgate.util.ReflectionUtils;
|
import org.geysermc.floodgate.util.ReflectionUtils;
|
||||||
|
|
||||||
@@ -130,8 +130,8 @@ public final class BungeeListener implements Listener {
|
|||||||
// To fix the February 2 2022 Mojang authentication changes
|
// To fix the February 2 2022 Mojang authentication changes
|
||||||
if (!config.isSendFloodgateData()) {
|
if (!config.isSendFloodgateData()) {
|
||||||
FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId());
|
FloodgatePlayer player = api.getPlayer(event.getPlayer().getUniqueId());
|
||||||
if (player != null && !player.isLinked() && !skinApplier.hasSkin(player)) {
|
if (player != null && !player.isLinked()) {
|
||||||
skinApplier.applySkin(player, new SkinData("", ""));
|
skinApplier.applySkin(player, new SkinDataImpl("", ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ public final class BungeePlatformModule extends AbstractModule {
|
|||||||
bind(PlatformUtils.class).to(BungeePlatformUtils.class);
|
bind(PlatformUtils.class).to(BungeePlatformUtils.class);
|
||||||
bind(Logger.class).annotatedWith(Names.named("logger")).toInstance(plugin.getLogger());
|
bind(Logger.class).annotatedWith(Names.named("logger")).toInstance(plugin.getLogger());
|
||||||
bind(FloodgateLogger.class).to(JavaUtilFloodgateLogger.class);
|
bind(FloodgateLogger.class).to(JavaUtilFloodgateLogger.class);
|
||||||
|
bind(SkinApplier.class).to(BungeeSkinApplier.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -121,12 +122,6 @@ public final class BungeePlatformModule extends AbstractModule {
|
|||||||
return new BungeePluginMessageRegistration();
|
return new BungeePluginMessageRegistration();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public SkinApplier skinApplier(FloodgateLogger logger) {
|
|
||||||
return new BungeeSkinApplier(logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DebugAddon / PlatformInjector
|
DebugAddon / PlatformInjector
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -26,68 +26,55 @@
|
|||||||
package org.geysermc.floodgate.pluginmessage;
|
package org.geysermc.floodgate.pluginmessage;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static org.geysermc.floodgate.util.ReflectionUtils.getConstructor;
|
|
||||||
import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType;
|
import static org.geysermc.floodgate.util.ReflectionUtils.getFieldOfType;
|
||||||
import static org.geysermc.floodgate.util.ReflectionUtils.getMethodByName;
|
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
import com.google.inject.Inject;
|
||||||
import java.lang.reflect.Constructor;
|
import com.google.inject.Singleton;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.util.ArrayList;
|
||||||
import lombok.RequiredArgsConstructor;
|
import java.util.List;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.connection.InitialHandler;
|
import net.md_5.bungee.connection.InitialHandler;
|
||||||
import net.md_5.bungee.connection.LoginResult;
|
import net.md_5.bungee.connection.LoginResult;
|
||||||
import net.md_5.bungee.protocol.Property;
|
import net.md_5.bungee.protocol.Property;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
|
||||||
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.event.EventBus;
|
||||||
|
import org.geysermc.floodgate.event.skin.SkinApplyEventImpl;
|
||||||
import org.geysermc.floodgate.skin.SkinApplier;
|
import org.geysermc.floodgate.skin.SkinApplier;
|
||||||
import org.geysermc.floodgate.skin.SkinData;
|
import org.geysermc.floodgate.skin.SkinDataImpl;
|
||||||
import org.geysermc.floodgate.util.ReflectionUtils;
|
import org.geysermc.floodgate.util.ReflectionUtils;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@Singleton
|
||||||
public final class BungeeSkinApplier implements SkinApplier {
|
public final class BungeeSkinApplier implements SkinApplier {
|
||||||
private static final Constructor<?> LOGIN_RESULT_CONSTRUCTOR;
|
|
||||||
private static final Field LOGIN_RESULT_FIELD;
|
private static final Field LOGIN_RESULT_FIELD;
|
||||||
private static final Method SET_PROPERTIES_METHOD;
|
|
||||||
|
|
||||||
private static final Class<?> PROPERTY_CLASS;
|
|
||||||
private static final Constructor<?> PROPERTY_CONSTRUCTOR;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
PROPERTY_CLASS = ReflectionUtils.getClassOrFallbackPrefixed(
|
|
||||||
"protocol.Property", "connection.LoginResult$Property"
|
|
||||||
);
|
|
||||||
|
|
||||||
LOGIN_RESULT_CONSTRUCTOR = getConstructor(
|
|
||||||
LoginResult.class, true,
|
|
||||||
String.class, String.class, Array.newInstance(PROPERTY_CLASS, 0).getClass()
|
|
||||||
);
|
|
||||||
|
|
||||||
LOGIN_RESULT_FIELD = getFieldOfType(InitialHandler.class, LoginResult.class);
|
LOGIN_RESULT_FIELD = getFieldOfType(InitialHandler.class, LoginResult.class);
|
||||||
checkNotNull(LOGIN_RESULT_FIELD, "LoginResult field cannot be null");
|
checkNotNull(LOGIN_RESULT_FIELD, "LoginResult field cannot be null");
|
||||||
|
|
||||||
SET_PROPERTIES_METHOD = getMethodByName(LoginResult.class, "setProperties", true);
|
|
||||||
|
|
||||||
PROPERTY_CONSTRUCTOR = ReflectionUtils.getConstructor(
|
|
||||||
PROPERTY_CLASS, true,
|
|
||||||
String.class, String.class, String.class
|
|
||||||
);
|
|
||||||
checkNotNull(PROPERTY_CONSTRUCTOR, "Property constructor cannot be null");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final FloodgateLogger logger;
|
private final ProxyServer server = ProxyServer.getInstance();
|
||||||
|
|
||||||
|
@Inject private EventBus eventBus;
|
||||||
|
@Inject private FloodgateLogger logger;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applySkin(FloodgatePlayer uuid, SkinData skinData) {
|
public void applySkin(@NonNull FloodgatePlayer floodgatePlayer, @NonNull SkinData skinData) {
|
||||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(uuid.getCorrectUniqueId());
|
ProxiedPlayer player = server.getPlayer(floodgatePlayer.getCorrectUniqueId());
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InitialHandler handler = getHandler(player);
|
InitialHandler handler;
|
||||||
if (handler == null) {
|
try {
|
||||||
|
handler = (InitialHandler) player.getPendingConnection();
|
||||||
|
} catch (Exception exception) {
|
||||||
|
logger.error("Incompatible Bungeecord fork detected", exception);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,57 +82,46 @@ public final class BungeeSkinApplier implements SkinApplier {
|
|||||||
// expected to be null since LoginResult is the data from hasJoined,
|
// expected to be null since LoginResult is the data from hasJoined,
|
||||||
// which Floodgate players don't have
|
// which Floodgate players don't have
|
||||||
if (loginResult == null) {
|
if (loginResult == null) {
|
||||||
// id and name are unused and properties will be overridden
|
// id and name are unused
|
||||||
loginResult = (LoginResult) ReflectionUtils.newInstance(
|
loginResult = new LoginResult(null, null, new Property[0]);
|
||||||
LOGIN_RESULT_CONSTRUCTOR, null, null, null
|
|
||||||
);
|
|
||||||
ReflectionUtils.setValue(handler, LOGIN_RESULT_FIELD, loginResult);
|
ReflectionUtils.setValue(handler, LOGIN_RESULT_FIELD, loginResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object property = ReflectionUtils.newInstance(
|
Property[] properties = loginResult.getProperties();
|
||||||
PROPERTY_CONSTRUCTOR,
|
|
||||||
"textures", skinData.getValue(), skinData.getSignature()
|
|
||||||
);
|
|
||||||
|
|
||||||
Object propertyArray = Array.newInstance(PROPERTY_CLASS, 1);
|
SkinData currentSkin = currentSkin(properties);
|
||||||
Array.set(propertyArray, 0, property);
|
|
||||||
|
|
||||||
ReflectionUtils.invoke(loginResult, SET_PROPERTIES_METHOD, propertyArray);
|
SkinApplyEvent event = new SkinApplyEventImpl(floodgatePlayer, currentSkin, skinData);
|
||||||
|
event.setCancelled(floodgatePlayer.isLinked());
|
||||||
|
|
||||||
|
eventBus.fire(event);
|
||||||
|
|
||||||
|
if (event.isCancelled()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
loginResult.setProperties(replaceSkin(properties, event.newSkin()));
|
||||||
public boolean hasSkin(FloodgatePlayer fPlayer) {
|
|
||||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(fPlayer.getCorrectUniqueId());
|
|
||||||
if (player == null) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InitialHandler handler = getHandler(player);
|
private SkinData currentSkin(Property[] properties) {
|
||||||
if (handler == null) {
|
for (Property property : properties) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LoginResult loginResult = handler.getLoginProfile();
|
|
||||||
if (loginResult == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Property property : loginResult.getProperties()) {
|
|
||||||
if (property.getName().equals("textures")) {
|
if (property.getName().equals("textures")) {
|
||||||
if (!property.getValue().isEmpty()) {
|
if (!property.getValue().isEmpty()) {
|
||||||
return true;
|
return new SkinDataImpl(property.getValue(), property.getSignature());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private InitialHandler getHandler(ProxiedPlayer player) {
|
|
||||||
try {
|
|
||||||
return (InitialHandler) player.getPendingConnection();
|
|
||||||
} catch (Exception exception) {
|
|
||||||
logger.error("Incompatible Bungeecord fork detected", exception);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Property[] replaceSkin(Property[] properties, SkinData skinData) {
|
||||||
|
List<Property> list = new ArrayList<>();
|
||||||
|
for (Property property : properties) {
|
||||||
|
if (!property.getName().equals("textures")) {
|
||||||
|
list.add(property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list.add(new Property("textures", skinData.value(), skinData.signature()));
|
||||||
|
return list.toArray(new Property[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,15 @@ import com.google.inject.Module;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
import org.geysermc.floodgate.api.InstanceHolder;
|
import org.geysermc.floodgate.api.InstanceHolder;
|
||||||
|
import org.geysermc.floodgate.api.event.FloodgateEventBus;
|
||||||
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
||||||
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
||||||
import org.geysermc.floodgate.api.link.PlayerLink;
|
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||||
import org.geysermc.floodgate.api.packet.PacketHandlers;
|
import org.geysermc.floodgate.api.packet.PacketHandlers;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.event.EventBus;
|
import org.geysermc.floodgate.event.EventBus;
|
||||||
import org.geysermc.floodgate.event.PostEnableEvent;
|
import org.geysermc.floodgate.event.lifecycle.PostEnableEvent;
|
||||||
import org.geysermc.floodgate.event.ShutdownEvent;
|
import org.geysermc.floodgate.event.lifecycle.ShutdownEvent;
|
||||||
import org.geysermc.floodgate.module.PostInitializeModule;
|
import org.geysermc.floodgate.module.PostInitializeModule;
|
||||||
|
|
||||||
public class FloodgatePlatform {
|
public class FloodgatePlatform {
|
||||||
@@ -52,9 +53,13 @@ public class FloodgatePlatform {
|
|||||||
public void init(
|
public void init(
|
||||||
FloodgateApi api,
|
FloodgateApi api,
|
||||||
PlayerLink link,
|
PlayerLink link,
|
||||||
|
FloodgateEventBus eventBus,
|
||||||
PacketHandlers packetHandlers,
|
PacketHandlers packetHandlers,
|
||||||
HandshakeHandlers handshakeHandlers) {
|
HandshakeHandlers handshakeHandlers
|
||||||
InstanceHolder.set(api, link, this.injector, packetHandlers, handshakeHandlers, KEY);
|
) {
|
||||||
|
InstanceHolder.set(
|
||||||
|
api, link, eventBus, this.injector, packetHandlers, handshakeHandlers, KEY
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enable(Module... postInitializeModules) throws RuntimeException {
|
public void enable(Module... postInitializeModules) throws RuntimeException {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.event;
|
package org.geysermc.floodgate.event;
|
||||||
|
|
||||||
|
import com.google.inject.Singleton;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
@@ -32,9 +33,13 @@ import org.geysermc.event.PostOrder;
|
|||||||
import org.geysermc.event.bus.impl.EventBusImpl;
|
import org.geysermc.event.bus.impl.EventBusImpl;
|
||||||
import org.geysermc.event.subscribe.Subscribe;
|
import org.geysermc.event.subscribe.Subscribe;
|
||||||
import org.geysermc.event.subscribe.Subscriber;
|
import org.geysermc.event.subscribe.Subscriber;
|
||||||
|
import org.geysermc.floodgate.api.event.FloodgateEventBus;
|
||||||
|
import org.geysermc.floodgate.api.event.FloodgateSubscriber;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final class EventBus extends EventBusImpl<Object, EventSubscriber<?>> {
|
public final class EventBus extends EventBusImpl<Object, FloodgateSubscriber<?>>
|
||||||
|
implements FloodgateEventBus {
|
||||||
@Override
|
@Override
|
||||||
protected <H, T, B extends Subscriber<T>> B makeSubscription(
|
protected <H, T, B extends Subscriber<T>> B makeSubscription(
|
||||||
@NonNull Class<T> eventClass,
|
@NonNull Class<T> eventClass,
|
||||||
|
|||||||
@@ -30,8 +30,9 @@ import java.util.function.Consumer;
|
|||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.event.PostOrder;
|
import org.geysermc.event.PostOrder;
|
||||||
import org.geysermc.event.subscribe.impl.SubscriberImpl;
|
import org.geysermc.event.subscribe.impl.SubscriberImpl;
|
||||||
|
import org.geysermc.floodgate.api.event.FloodgateSubscriber;
|
||||||
|
|
||||||
public final class EventSubscriber<E> extends SubscriberImpl<E> {
|
public final class EventSubscriber<E> extends SubscriberImpl<E> implements FloodgateSubscriber<E> {
|
||||||
EventSubscriber(
|
EventSubscriber(
|
||||||
@NonNull Class<E> eventClass,
|
@NonNull Class<E> eventClass,
|
||||||
@NonNull Consumer<E> handler,
|
@NonNull Consumer<E> handler,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
* @link https://github.com/GeyserMC/Floodgate
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.floodgate.event;
|
package org.geysermc.floodgate.event.lifecycle;
|
||||||
|
|
||||||
public class PostEnableEvent {
|
public class PostEnableEvent {
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
* @link https://github.com/GeyserMC/Floodgate
|
* @link https://github.com/GeyserMC/Floodgate
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.geysermc.floodgate.event;
|
package org.geysermc.floodgate.event.lifecycle;
|
||||||
|
|
||||||
public class ShutdownEvent {
|
public class ShutdownEvent {
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2022 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.event.skin;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.geysermc.event.util.AbstractCancellable;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent;
|
||||||
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
|
|
||||||
|
public class SkinApplyEventImpl extends AbstractCancellable implements SkinApplyEvent {
|
||||||
|
private final FloodgatePlayer player;
|
||||||
|
private final SkinData currentSkin;
|
||||||
|
private SkinData newSkin;
|
||||||
|
|
||||||
|
public SkinApplyEventImpl(
|
||||||
|
@NonNull FloodgatePlayer player,
|
||||||
|
@Nullable SkinData currentSkin,
|
||||||
|
@NonNull SkinData newSkin
|
||||||
|
) {
|
||||||
|
this.player = Objects.requireNonNull(player);
|
||||||
|
this.currentSkin = currentSkin;
|
||||||
|
this.newSkin = Objects.requireNonNull(newSkin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull FloodgatePlayer player() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable SkinData currentSkin() {
|
||||||
|
return currentSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull SkinData newSkin() {
|
||||||
|
return newSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkinApplyEventImpl newSkin(@NonNull SkinData skinData) {
|
||||||
|
this.newSkin = Objects.requireNonNull(skinData);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
|||||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.database.config.DatabaseConfig;
|
import org.geysermc.floodgate.database.config.DatabaseConfig;
|
||||||
import org.geysermc.floodgate.database.config.DatabaseConfigLoader;
|
import org.geysermc.floodgate.database.config.DatabaseConfigLoader;
|
||||||
import org.geysermc.floodgate.event.ShutdownEvent;
|
import org.geysermc.floodgate.event.lifecycle.ShutdownEvent;
|
||||||
import org.geysermc.floodgate.util.InjectorHolder;
|
import org.geysermc.floodgate.util.InjectorHolder;
|
||||||
|
|
||||||
@Listener
|
@Listener
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ import org.geysermc.floodgate.api.link.PlayerLink;
|
|||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfig.PlayerLinkConfig;
|
import org.geysermc.floodgate.config.FloodgateConfig.PlayerLinkConfig;
|
||||||
import org.geysermc.floodgate.event.ShutdownEvent;
|
import org.geysermc.floodgate.event.lifecycle.ShutdownEvent;
|
||||||
import org.geysermc.floodgate.util.Constants;
|
import org.geysermc.floodgate.util.Constants;
|
||||||
import org.geysermc.floodgate.util.InjectorHolder;
|
import org.geysermc.floodgate.util.InjectorHolder;
|
||||||
import org.geysermc.floodgate.util.Utils;
|
import org.geysermc.floodgate.util.Utils;
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import org.geysermc.event.PostOrder;
|
|||||||
import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl;
|
import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
import org.geysermc.floodgate.api.SimpleFloodgateApi;
|
||||||
|
import org.geysermc.floodgate.api.event.FloodgateEventBus;
|
||||||
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
|
||||||
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
import org.geysermc.floodgate.api.inject.PlatformInjector;
|
||||||
import org.geysermc.floodgate.api.link.PlayerLink;
|
import org.geysermc.floodgate.api.link.PlayerLink;
|
||||||
@@ -57,14 +58,13 @@ import org.geysermc.floodgate.crypto.Base64Topping;
|
|||||||
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
import org.geysermc.floodgate.crypto.FloodgateCipher;
|
||||||
import org.geysermc.floodgate.crypto.KeyProducer;
|
import org.geysermc.floodgate.crypto.KeyProducer;
|
||||||
import org.geysermc.floodgate.event.EventBus;
|
import org.geysermc.floodgate.event.EventBus;
|
||||||
import org.geysermc.floodgate.event.ShutdownEvent;
|
import org.geysermc.floodgate.event.lifecycle.ShutdownEvent;
|
||||||
import org.geysermc.floodgate.event.util.ListenerAnnotationMatcher;
|
import org.geysermc.floodgate.event.util.ListenerAnnotationMatcher;
|
||||||
import org.geysermc.floodgate.inject.CommonPlatformInjector;
|
import org.geysermc.floodgate.inject.CommonPlatformInjector;
|
||||||
import org.geysermc.floodgate.link.PlayerLinkHolder;
|
import org.geysermc.floodgate.link.PlayerLinkHolder;
|
||||||
import org.geysermc.floodgate.packet.PacketHandlersImpl;
|
import org.geysermc.floodgate.packet.PacketHandlersImpl;
|
||||||
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
|
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
|
||||||
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
|
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
|
||||||
import org.geysermc.floodgate.skin.SkinApplier;
|
|
||||||
import org.geysermc.floodgate.skin.SkinUploadManager;
|
import org.geysermc.floodgate.skin.SkinUploadManager;
|
||||||
import org.geysermc.floodgate.util.Constants;
|
import org.geysermc.floodgate.util.Constants;
|
||||||
import org.geysermc.floodgate.util.HttpClient;
|
import org.geysermc.floodgate.util.HttpClient;
|
||||||
@@ -77,6 +77,7 @@ public class CommonModule extends AbstractModule {
|
|||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
bind(EventBus.class).toInstance(eventBus);
|
bind(EventBus.class).toInstance(eventBus);
|
||||||
|
bind(FloodgateEventBus.class).to(EventBus.class);
|
||||||
// register every class that has the Listener annotation
|
// register every class that has the Listener annotation
|
||||||
bindListener(new ListenerAnnotationMatcher(), new TypeListener() {
|
bindListener(new ListenerAnnotationMatcher(), new TypeListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -164,17 +165,6 @@ public class CommonModule extends AbstractModule {
|
|||||||
return new PluginMessageManager();
|
return new PluginMessageManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public SkinUploadManager skinUploadManager(
|
|
||||||
FloodgateApi api,
|
|
||||||
SkinApplier skinApplier,
|
|
||||||
FloodgateLogger logger) {
|
|
||||||
SkinUploadManager manager = new SkinUploadManager(api, skinApplier, logger);
|
|
||||||
eventBus.register(manager);
|
|
||||||
return manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named("gitBranch")
|
@Named("gitBranch")
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import org.geysermc.event.Listener;
|
|||||||
import org.geysermc.event.subscribe.Subscribe;
|
import org.geysermc.event.subscribe.Subscribe;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.command.util.Permission;
|
import org.geysermc.floodgate.command.util.Permission;
|
||||||
import org.geysermc.floodgate.event.ShutdownEvent;
|
import org.geysermc.floodgate.event.lifecycle.ShutdownEvent;
|
||||||
import org.geysermc.floodgate.news.data.AnnouncementData;
|
import org.geysermc.floodgate.news.data.AnnouncementData;
|
||||||
import org.geysermc.floodgate.news.data.BuildSpecificData;
|
import org.geysermc.floodgate.news.data.BuildSpecificData;
|
||||||
import org.geysermc.floodgate.news.data.CheckAfterData;
|
import org.geysermc.floodgate.news.data.CheckAfterData;
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import lombok.AccessLevel;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
import org.geysermc.floodgate.api.InstanceHolder;
|
|
||||||
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
import org.geysermc.floodgate.api.ProxyFloodgateApi;
|
||||||
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
import org.geysermc.floodgate.api.handshake.HandshakeData;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
@@ -72,7 +71,7 @@ public final class FloodgatePlayerImpl implements FloodgatePlayer {
|
|||||||
private Map<String, PropertyKey> stringToPropertyKey;
|
private Map<String, PropertyKey> stringToPropertyKey;
|
||||||
|
|
||||||
static FloodgatePlayerImpl from(BedrockData data, HandshakeData handshakeData) {
|
static FloodgatePlayerImpl from(BedrockData data, HandshakeData handshakeData) {
|
||||||
FloodgateApi api = InstanceHolder.getApi();
|
FloodgateApi api = FloodgateApi.getInstance();
|
||||||
|
|
||||||
UUID javaUniqueId = Utils.getJavaUuid(data.getXuid());
|
UUID javaUniqueId = Utils.getJavaUuid(data.getXuid());
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.pluginmessage.channel;
|
package org.geysermc.floodgate.pluginmessage.channel;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -36,7 +35,7 @@ import org.geysermc.floodgate.config.FloodgateConfig;
|
|||||||
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
import org.geysermc.floodgate.config.ProxyFloodgateConfig;
|
||||||
import org.geysermc.floodgate.pluginmessage.PluginMessageChannel;
|
import org.geysermc.floodgate.pluginmessage.PluginMessageChannel;
|
||||||
import org.geysermc.floodgate.skin.SkinApplier;
|
import org.geysermc.floodgate.skin.SkinApplier;
|
||||||
import org.geysermc.floodgate.skin.SkinData;
|
import org.geysermc.floodgate.skin.SkinDataImpl;
|
||||||
|
|
||||||
public class SkinChannel implements PluginMessageChannel {
|
public class SkinChannel implements PluginMessageChannel {
|
||||||
@Inject private FloodgateApi api;
|
@Inject private FloodgateApi api;
|
||||||
@@ -89,18 +88,10 @@ public class SkinChannel implements PluginMessageChannel {
|
|||||||
return Result.kick("Got invalid skin data");
|
return Result.kick("Got invalid skin data");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (floodgatePlayer.isLinked() || skinApplier.hasSkin(floodgatePlayer)) {
|
|
||||||
return Result.handled();
|
|
||||||
}
|
|
||||||
|
|
||||||
String value = split[0];
|
String value = split[0];
|
||||||
String signature = split[1];
|
String signature = split[1];
|
||||||
|
|
||||||
JsonObject result = new JsonObject();
|
SkinDataImpl skinData = new SkinDataImpl(value, signature);
|
||||||
result.addProperty("value", value);
|
|
||||||
result.addProperty("signature", signature);
|
|
||||||
|
|
||||||
SkinData skinData = new SkinData(value, signature);
|
|
||||||
|
|
||||||
floodgatePlayer.addProperty(PropertyKey.SKIN_UPLOADED, skinData);
|
floodgatePlayer.addProperty(PropertyKey.SKIN_UPLOADED, skinData);
|
||||||
skinApplier.applySkin(floodgatePlayer, skinData);
|
skinApplier.applySkin(floodgatePlayer, skinData);
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.skin;
|
package org.geysermc.floodgate.skin;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
|
|
||||||
public interface SkinApplier {
|
public interface SkinApplier {
|
||||||
@@ -34,14 +36,5 @@ public interface SkinApplier {
|
|||||||
* @param floodgatePlayer player to apply skin to
|
* @param floodgatePlayer player to apply skin to
|
||||||
* @param skinData data for skin to apply to player
|
* @param skinData data for skin to apply to player
|
||||||
*/
|
*/
|
||||||
void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData);
|
void applySkin(@NonNull FloodgatePlayer floodgatePlayer, @NonNull SkinData skinData);
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a {@link FloodgatePlayer player} currently
|
|
||||||
* has a skin applied.
|
|
||||||
*
|
|
||||||
* @param floodgatePlayer player to check skin of
|
|
||||||
* @return if player has a skin
|
|
||||||
*/
|
|
||||||
boolean hasSkin(FloodgatePlayer floodgatePlayer);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,22 +26,33 @@
|
|||||||
package org.geysermc.floodgate.skin;
|
package org.geysermc.floodgate.skin;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import lombok.Getter;
|
import java.util.Objects;
|
||||||
import lombok.RequiredArgsConstructor;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
|
||||||
|
|
||||||
@Getter
|
public class SkinDataImpl implements SkinData {
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class SkinData {
|
|
||||||
private final String value;
|
private final String value;
|
||||||
private final String signature;
|
private final String signature;
|
||||||
|
|
||||||
|
public SkinDataImpl(@NonNull String value, @NonNull String signature) {
|
||||||
|
this.value = Objects.requireNonNull(value);
|
||||||
|
this.signature = Objects.requireNonNull(signature);
|
||||||
|
}
|
||||||
|
|
||||||
public static SkinData from(JsonObject data) {
|
public static SkinData from(JsonObject data) {
|
||||||
if (data.has("signature") && !data.get("signature").isJsonNull()) {
|
return new SkinDataImpl(
|
||||||
return new SkinData(
|
|
||||||
data.get("value").getAsString(),
|
data.get("value").getAsString(),
|
||||||
data.get("signature").getAsString()
|
data.get("signature").getAsString()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return new SkinData(data.get("value").getAsString(), null);
|
|
||||||
|
@Override
|
||||||
|
public @NonNull String value() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull String signature() {
|
||||||
|
return signature;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,25 +25,26 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.skin;
|
package org.geysermc.floodgate.skin;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.geysermc.event.Listener;
|
import org.geysermc.event.Listener;
|
||||||
import org.geysermc.event.subscribe.Subscribe;
|
import org.geysermc.event.subscribe.Subscribe;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.event.ShutdownEvent;
|
import org.geysermc.floodgate.event.lifecycle.ShutdownEvent;
|
||||||
|
|
||||||
@Listener
|
@Listener
|
||||||
@AllArgsConstructor
|
@Singleton
|
||||||
public final class SkinUploadManager {
|
public final class SkinUploadManager {
|
||||||
private final Int2ObjectMap<SkinUploadSocket> connections =
|
private final Int2ObjectMap<SkinUploadSocket> connections =
|
||||||
Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>());
|
Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>());
|
||||||
|
|
||||||
private final FloodgateApi api;
|
@Inject private FloodgateApi api;
|
||||||
private final SkinApplier applier;
|
@Inject private SkinApplier applier;
|
||||||
private final FloodgateLogger logger;
|
@Inject private FloodgateLogger logger;
|
||||||
|
|
||||||
public void addConnectionIfNeeded(int id, String verifyCode) {
|
public void addConnectionIfNeeded(int id, String verifyCode) {
|
||||||
connections.computeIfAbsent(id, (ignored) -> {
|
connections.computeIfAbsent(id, (ignored) -> {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import java.net.URI;
|
|||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.geysermc.floodgate.api.FloodgateApi;
|
import org.geysermc.floodgate.api.FloodgateApi;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
|
||||||
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.api.player.PropertyKey;
|
import org.geysermc.floodgate.api.player.PropertyKey;
|
||||||
@@ -61,8 +62,8 @@ final class SkinUploadSocket extends WebSocketClient {
|
|||||||
SkinUploadManager uploadManager,
|
SkinUploadManager uploadManager,
|
||||||
FloodgateApi api,
|
FloodgateApi api,
|
||||||
SkinApplier applier,
|
SkinApplier applier,
|
||||||
FloodgateLogger logger) {
|
FloodgateLogger logger
|
||||||
|
) {
|
||||||
super(getWebsocketUri(id, verifyCode));
|
super(getWebsocketUri(id, verifyCode));
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.verifyCode = verifyCode;
|
this.verifyCode = verifyCode;
|
||||||
@@ -83,7 +84,7 @@ final class SkinUploadSocket extends WebSocketClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOpen(ServerHandshake handshakedata) {
|
public void onOpen(ServerHandshake ignored) {
|
||||||
setConnectionLostTimeout(11);
|
setConnectionLostTimeout(11);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,10 +115,14 @@ final class SkinUploadSocket extends WebSocketClient {
|
|||||||
player.getCorrectUsername());
|
player.getCorrectUsername());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!player.isLinked() && !applier.hasSkin(player)) {
|
|
||||||
SkinData skinData = SkinData.from(message.getAsJsonObject("data"));
|
SkinData skinData = SkinDataImpl.from(message.getAsJsonObject("data"));
|
||||||
player.addProperty(PropertyKey.SKIN_UPLOADED, skinData);
|
|
||||||
applier.applySkin(player, skinData);
|
applier.applySkin(player, skinData);
|
||||||
|
|
||||||
|
// legacy stuff,
|
||||||
|
// will be removed shortly after or during the Floodgate-Geyser integration
|
||||||
|
if (!player.isLinked()) {
|
||||||
|
player.addProperty(PropertyKey.SKIN_UPLOADED, skinData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import org.geysermc.event.Listener;
|
|||||||
import org.geysermc.event.subscribe.Subscribe;
|
import org.geysermc.event.subscribe.Subscribe;
|
||||||
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
import org.geysermc.floodgate.api.logger.FloodgateLogger;
|
||||||
import org.geysermc.floodgate.config.FloodgateConfig;
|
import org.geysermc.floodgate.config.FloodgateConfig;
|
||||||
import org.geysermc.floodgate.event.PostEnableEvent;
|
import org.geysermc.floodgate.event.lifecycle.PostEnableEvent;
|
||||||
|
|
||||||
@AutoBind
|
@AutoBind
|
||||||
@Listener
|
@Listener
|
||||||
|
|||||||
@@ -61,9 +61,11 @@ public final class SpigotPlatformModule extends AbstractModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
|
bind(SpigotPlugin.class).toInstance(plugin);
|
||||||
bind(PlatformUtils.class).to(SpigotPlatformUtils.class);
|
bind(PlatformUtils.class).to(SpigotPlatformUtils.class);
|
||||||
bind(Logger.class).annotatedWith(Names.named("logger")).toInstance(plugin.getLogger());
|
bind(Logger.class).annotatedWith(Names.named("logger")).toInstance(plugin.getLogger());
|
||||||
bind(FloodgateLogger.class).to(JavaUtilFloodgateLogger.class);
|
bind(FloodgateLogger.class).to(JavaUtilFloodgateLogger.class);
|
||||||
|
bind(SkinApplier.class).to(SpigotSkinApplier.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -142,12 +144,6 @@ public final class SpigotPlatformModule extends AbstractModule {
|
|||||||
return new SpigotPluginMessageRegistration(plugin);
|
return new SpigotPluginMessageRegistration(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public SkinApplier skinApplier(SpigotVersionSpecificMethods versionSpecificMethods) {
|
|
||||||
return new SpigotSkinApplier(versionSpecificMethods, plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
public SpigotVersionSpecificMethods versionSpecificMethods() {
|
public SpigotVersionSpecificMethods versionSpecificMethods() {
|
||||||
|
|||||||
@@ -25,71 +25,48 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.pluginmessage;
|
package org.geysermc.floodgate.pluginmessage;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
import com.mojang.authlib.properties.Property;
|
import com.mojang.authlib.properties.Property;
|
||||||
import com.mojang.authlib.properties.PropertyMap;
|
import com.mojang.authlib.properties.PropertyMap;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.floodgate.SpigotPlugin;
|
import org.geysermc.floodgate.SpigotPlugin;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
|
import org.geysermc.floodgate.event.EventBus;
|
||||||
|
import org.geysermc.floodgate.event.skin.SkinApplyEventImpl;
|
||||||
import org.geysermc.floodgate.skin.SkinApplier;
|
import org.geysermc.floodgate.skin.SkinApplier;
|
||||||
import org.geysermc.floodgate.skin.SkinData;
|
import org.geysermc.floodgate.skin.SkinDataImpl;
|
||||||
import org.geysermc.floodgate.util.ClassNames;
|
import org.geysermc.floodgate.util.ClassNames;
|
||||||
import org.geysermc.floodgate.util.ReflectionUtils;
|
import org.geysermc.floodgate.util.ReflectionUtils;
|
||||||
import org.geysermc.floodgate.util.SpigotVersionSpecificMethods;
|
import org.geysermc.floodgate.util.SpigotVersionSpecificMethods;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
public final class SpigotSkinApplier implements SkinApplier {
|
public final class SpigotSkinApplier implements SkinApplier {
|
||||||
private final SpigotVersionSpecificMethods versionSpecificMethods;
|
@Inject private SpigotVersionSpecificMethods versionSpecificMethods;
|
||||||
private final SpigotPlugin plugin;
|
@Inject private SpigotPlugin plugin;
|
||||||
|
@Inject private EventBus eventBus;
|
||||||
public SpigotSkinApplier(
|
|
||||||
SpigotVersionSpecificMethods versionSpecificMethods,
|
|
||||||
SpigotPlugin plugin) {
|
|
||||||
this.versionSpecificMethods = versionSpecificMethods;
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData) {
|
public void applySkin(@NonNull FloodgatePlayer floodgatePlayer, @NonNull SkinData skinData) {
|
||||||
applySkin0(floodgatePlayer, skinData, true);
|
applySkin0(floodgatePlayer, skinData, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasSkin(FloodgatePlayer floodgatePlayer) {
|
|
||||||
Player player = Bukkit.getPlayer(floodgatePlayer.getCorrectUniqueId());
|
|
||||||
|
|
||||||
if (player == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GameProfile profile = ReflectionUtils.castedInvoke(player, ClassNames.GET_PROFILE_METHOD);
|
|
||||||
if (profile == null) {
|
|
||||||
throw new IllegalStateException("The GameProfile cannot be null! " + player.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need to be careful here - getProperties() returns an authlib PropertyMap, which extends
|
|
||||||
// MultiMap from Guava. Floodgate relocates Guava.
|
|
||||||
for (Property textures : profile.getProperties().get("textures")) {
|
|
||||||
if (!textures.getValue().isEmpty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applySkin0(FloodgatePlayer floodgatePlayer, SkinData skinData, boolean firstTry) {
|
private void applySkin0(FloodgatePlayer floodgatePlayer, SkinData skinData, boolean firstTry) {
|
||||||
Player player = Bukkit.getPlayer(floodgatePlayer.getCorrectUniqueId());
|
Player player = Bukkit.getPlayer(floodgatePlayer.getCorrectUniqueId());
|
||||||
|
|
||||||
// player is probably not logged in yet
|
// player is probably not logged in yet
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
if (firstTry) {
|
if (firstTry) {
|
||||||
Bukkit.getScheduler().runTaskLater(plugin,
|
Bukkit.getScheduler().runTaskLater(
|
||||||
() -> {
|
plugin,
|
||||||
if (!hasSkin(floodgatePlayer)) {
|
() -> applySkin0(floodgatePlayer, skinData, false),
|
||||||
applySkin0(floodgatePlayer, skinData, false);
|
10 * 20
|
||||||
}
|
);
|
||||||
},
|
|
||||||
10 * 20);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -100,11 +77,22 @@ public final class SpigotSkinApplier implements SkinApplier {
|
|||||||
throw new IllegalStateException("The GameProfile cannot be null! " + player.getName());
|
throw new IllegalStateException("The GameProfile cannot be null! " + player.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Need to be careful here - getProperties() returns an authlib PropertyMap, which extends
|
||||||
|
// MultiMap from Guava. Floodgate relocates Guava.
|
||||||
PropertyMap properties = profile.getProperties();
|
PropertyMap properties = profile.getProperties();
|
||||||
|
|
||||||
properties.removeAll("textures");
|
SkinData currentSkin = currentSkin(properties);
|
||||||
Property property = new Property("textures", skinData.getValue(), skinData.getSignature());
|
|
||||||
properties.put("textures", property);
|
SkinApplyEvent event = new SkinApplyEventImpl(floodgatePlayer, currentSkin, skinData);
|
||||||
|
event.setCancelled(floodgatePlayer.isLinked());
|
||||||
|
|
||||||
|
eventBus.fire(event);
|
||||||
|
|
||||||
|
if (event.isCancelled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
replaceSkin(properties, event.newSkin());
|
||||||
|
|
||||||
// By running as a task, we don't run into async issues
|
// By running as a task, we don't run into async issues
|
||||||
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||||
@@ -116,4 +104,19 @@ public final class SpigotSkinApplier implements SkinApplier {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SkinData currentSkin(PropertyMap properties) {
|
||||||
|
for (Property texture : properties.get("textures")) {
|
||||||
|
if (!texture.getValue().isEmpty()) {
|
||||||
|
return new SkinDataImpl(texture.getValue(), texture.getSignature());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void replaceSkin(PropertyMap properties, SkinData skinData) {
|
||||||
|
properties.removeAll("textures");
|
||||||
|
Property property = new Property("textures", skinData.value(), skinData.signature());
|
||||||
|
properties.put("textures", property);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ public final class VelocityPlatformModule extends AbstractModule {
|
|||||||
bind(CommandUtil.class).to(VelocityCommandUtil.class);
|
bind(CommandUtil.class).to(VelocityCommandUtil.class);
|
||||||
bind(PlatformUtils.class).to(VelocityPlatformUtils.class);
|
bind(PlatformUtils.class).to(VelocityPlatformUtils.class);
|
||||||
bind(FloodgateLogger.class).to(Slf4jFloodgateLogger.class);
|
bind(FloodgateLogger.class).to(Slf4jFloodgateLogger.class);
|
||||||
|
bind(SkinApplier.class).to(VelocitySkinApplier.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -112,12 +113,6 @@ public final class VelocityPlatformModule extends AbstractModule {
|
|||||||
return new VelocityPluginMessageRegistration(proxy);
|
return new VelocityPluginMessageRegistration(proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
public SkinApplier skinApplier(ProxyServer server) {
|
|
||||||
return new VelocitySkinApplier(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DebugAddon / PlatformInjector
|
DebugAddon / PlatformInjector
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -25,43 +25,60 @@
|
|||||||
|
|
||||||
package org.geysermc.floodgate.util;
|
package org.geysermc.floodgate.util;
|
||||||
|
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
import com.velocitypowered.api.proxy.ProxyServer;
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
import com.velocitypowered.api.util.GameProfile.Property;
|
import com.velocitypowered.api.util.GameProfile.Property;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent;
|
||||||
|
import org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData;
|
||||||
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
import org.geysermc.floodgate.api.player.FloodgatePlayer;
|
||||||
|
import org.geysermc.floodgate.event.EventBus;
|
||||||
|
import org.geysermc.floodgate.event.skin.SkinApplyEventImpl;
|
||||||
import org.geysermc.floodgate.skin.SkinApplier;
|
import org.geysermc.floodgate.skin.SkinApplier;
|
||||||
import org.geysermc.floodgate.skin.SkinData;
|
import org.geysermc.floodgate.skin.SkinDataImpl;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@Singleton
|
||||||
public class VelocitySkinApplier implements SkinApplier {
|
public class VelocitySkinApplier implements SkinApplier {
|
||||||
private final ProxyServer server;
|
@Inject private ProxyServer server;
|
||||||
|
@Inject private EventBus eventBus;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applySkin(FloodgatePlayer floodgatePlayer, SkinData skinData) {
|
public void applySkin(@NonNull FloodgatePlayer floodgatePlayer, @NonNull SkinData skinData) {
|
||||||
server.getPlayer(floodgatePlayer.getCorrectUniqueId()).ifPresent(player -> {
|
server.getPlayer(floodgatePlayer.getCorrectUniqueId()).ifPresent(player -> {
|
||||||
List<Property> properties = new ArrayList<>(player.getGameProfileProperties());
|
List<Property> properties = new ArrayList<>(player.getGameProfileProperties());
|
||||||
properties.add(new Property("textures", skinData.getValue(), skinData.getSignature()));
|
|
||||||
|
SkinData currentSkin = currentSkin(properties);
|
||||||
|
|
||||||
|
SkinApplyEvent event = new SkinApplyEventImpl(floodgatePlayer, currentSkin, skinData);
|
||||||
|
event.setCancelled(floodgatePlayer.isLinked());
|
||||||
|
|
||||||
|
eventBus.fire(event);
|
||||||
|
|
||||||
|
if (event.isCancelled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
replaceSkin(properties, event.newSkin());
|
||||||
player.setGameProfileProperties(properties);
|
player.setGameProfileProperties(properties);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private SkinData currentSkin(List<Property> properties) {
|
||||||
public boolean hasSkin(FloodgatePlayer floodgatePlayer) {
|
for (Property property : properties) {
|
||||||
Optional<Player> player = server.getPlayer(floodgatePlayer.getCorrectUniqueId());
|
|
||||||
|
|
||||||
if (player.isPresent()) {
|
|
||||||
for (Property property : player.get().getGameProfileProperties()) {
|
|
||||||
if (property.getName().equals("textures")) {
|
if (property.getName().equals("textures")) {
|
||||||
if (!property.getValue().isEmpty()) {
|
if (!property.getValue().isEmpty()) {
|
||||||
return true;
|
return new SkinDataImpl(property.getValue(), property.getSignature());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
private void replaceSkin(List<Property> properties, SkinData skinData) {
|
||||||
|
properties.removeIf(property -> property.getName().equals("textures"));
|
||||||
|
properties.add(new Property("textures", skinData.value(), skinData.signature()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user