Improved Wrapping of PlayerInfoData and support chat session data (#2361)
* Improved Wrapping of PlayerInfoData and support chat session data * added constructor for unambiguous creation of playerinfodata without signature
This commit is contained in:
parent
448e9369de
commit
08ea2da642
|
@ -961,7 +961,7 @@ public abstract class AbstractStructure {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a read/write structure for profile public keys in 1.9
|
* Retrieve a read/write structure for profile public keys in 1.19
|
||||||
* @return The Structure Modifier
|
* @return The Structure Modifier
|
||||||
*/
|
*/
|
||||||
public StructureModifier<WrappedProfilePublicKey> getProfilePublicKeys() {
|
public StructureModifier<WrappedProfilePublicKey> getProfilePublicKeys() {
|
||||||
|
@ -971,13 +971,24 @@ public abstract class AbstractStructure {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a read/write structure for profile public key data in 1.9
|
* Retrieve a read/write structure for profile public key data in 1.19
|
||||||
* @return The Structure Modifier
|
* @return The Structure Modifier
|
||||||
*/
|
*/
|
||||||
public StructureModifier<WrappedProfileKeyData> getProfilePublicKeyData() {
|
public StructureModifier<WrappedProfileKeyData> getProfilePublicKeyData() {
|
||||||
return structureModifier.withType(
|
return structureModifier.withType(
|
||||||
MinecraftReflection.getProfilePublicKeyDataClass(),
|
MinecraftReflection.getProfilePublicKeyDataClass(),
|
||||||
BukkitConverters.getWrappedPublicKeyDataConverter());
|
BukkitConverters.getWrappedPublicKeyDataConverter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves read/write structure for remote chat session data in 1.19.3
|
||||||
|
* @return The Structure Modifier
|
||||||
|
*/
|
||||||
|
public StructureModifier<WrappedRemoteChatSessionData> getRemoteChatSessionData() {
|
||||||
|
return structureModifier.withType(
|
||||||
|
MinecraftReflection.getRemoteChatSessionDataClass(),
|
||||||
|
BukkitConverters.getWrappedRemoteChatSessionDataConverter()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1621,6 +1621,10 @@ public final class MinecraftReflection {
|
||||||
return getMinecraftClass("network.chat.RemoteChatSession");
|
return getMinecraftClass("network.chat.RemoteChatSession");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Class<?> getRemoteChatSessionDataClass() {
|
||||||
|
return getRemoteChatSessionClass().getClasses()[0];
|
||||||
|
}
|
||||||
|
|
||||||
public static Class<?> getFastUtilClass(String className) {
|
public static Class<?> getFastUtilClass(String className) {
|
||||||
return getLibraryClass("it.unimi.dsi.fastutil." + className);
|
return getLibraryClass("it.unimi.dsi.fastutil." + className);
|
||||||
}
|
}
|
||||||
|
|
|
@ -604,6 +604,10 @@ public class BukkitConverters {
|
||||||
return ignoreNull(handle(WrappedProfileKeyData::getHandle, WrappedProfileKeyData::new, WrappedProfileKeyData.class));
|
return ignoreNull(handle(WrappedProfileKeyData::getHandle, WrappedProfileKeyData::new, WrappedProfileKeyData.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static EquivalentConverter<WrappedRemoteChatSessionData> getWrappedRemoteChatSessionDataConverter() {
|
||||||
|
return ignoreNull(handle(WrappedRemoteChatSessionData::getHandle, WrappedRemoteChatSessionData::new, WrappedRemoteChatSessionData.class));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return converter for cryptographic signature data that are used in login and chat packets
|
* @return converter for cryptographic signature data that are used in login and chat packets
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -30,6 +30,8 @@ import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
|
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an immutable PlayerInfoData in the PLAYER_INFO packet.
|
* Represents an immutable PlayerInfoData in the PLAYER_INFO packet.
|
||||||
* @author dmulloy2
|
* @author dmulloy2
|
||||||
|
@ -43,6 +45,9 @@ public class PlayerInfoData {
|
||||||
private final NativeGameMode gameMode;
|
private final NativeGameMode gameMode;
|
||||||
private final WrappedGameProfile profile;
|
private final WrappedGameProfile profile;
|
||||||
private final WrappedChatComponent displayName;
|
private final WrappedChatComponent displayName;
|
||||||
|
@Nullable
|
||||||
|
private final WrappedRemoteChatSessionData remoteChatSessionData;
|
||||||
|
@Nullable
|
||||||
private final WrappedProfileKeyData profileKeyData;
|
private final WrappedProfileKeyData profileKeyData;
|
||||||
|
|
||||||
// This is the same order as the NMS class, minus the packet (which isn't a field)
|
// This is the same order as the NMS class, minus the packet (which isn't a field)
|
||||||
|
@ -54,7 +59,35 @@ public class PlayerInfoData {
|
||||||
this(profile.getUUID(), latency, true, gameMode, profile, displayName, keyData);
|
this(profile.getUUID(), latency, true, gameMode, profile, displayName, keyData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerInfoData(UUID profileId, int latency, boolean listed, NativeGameMode gameMode, WrappedGameProfile profile, WrappedChatComponent displayName, WrappedProfileKeyData profileKeyData) {
|
/**
|
||||||
|
* Constructs a new PlayerInfoData for Minecraft 1.19 or later without signature data
|
||||||
|
* @see PlayerInfoData#PlayerInfoData(UUID, int, boolean, NativeGameMode, WrappedGameProfile, WrappedChatComponent, WrappedRemoteChatSessionData)
|
||||||
|
*
|
||||||
|
* @param profileId the id of the profile (has to be non-null)
|
||||||
|
* @param latency the latency in milliseconds
|
||||||
|
* @param listed whether the player is listed in the tab list
|
||||||
|
* @param gameMode the game mode
|
||||||
|
* @param profile the game profile
|
||||||
|
* @param displayName display name in tab list (optional)
|
||||||
|
*/
|
||||||
|
public PlayerInfoData(UUID profileId, int latency, boolean listed, NativeGameMode gameMode, WrappedGameProfile profile, WrappedChatComponent displayName) {
|
||||||
|
this(profileId, latency, listed, gameMode, profile, displayName, (WrappedRemoteChatSessionData) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new PlayerInfoData for Minecraft 1.19. This is incompatible on 1.19.3.
|
||||||
|
* @see PlayerInfoData#PlayerInfoData(UUID, int, boolean, NativeGameMode, WrappedGameProfile, WrappedChatComponent, WrappedRemoteChatSessionData)
|
||||||
|
*
|
||||||
|
* @param profileId the id of the profile (has to be non-null)
|
||||||
|
* @param latency the latency in milliseconds
|
||||||
|
* @param listed whether the player is listed in the tab list
|
||||||
|
* @param gameMode the game mode
|
||||||
|
* @param profile the game profile
|
||||||
|
* @param displayName display name in tab list (optional)
|
||||||
|
* @param profileKeyData the public key for the profile or null
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public PlayerInfoData(UUID profileId, int latency, boolean listed, NativeGameMode gameMode, WrappedGameProfile profile, WrappedChatComponent displayName, @Nullable WrappedProfileKeyData profileKeyData) {
|
||||||
this.profileId = profileId;
|
this.profileId = profileId;
|
||||||
this.latency = latency;
|
this.latency = latency;
|
||||||
this.listed = listed;
|
this.listed = listed;
|
||||||
|
@ -62,6 +95,29 @@ public class PlayerInfoData {
|
||||||
this.profile = profile;
|
this.profile = profile;
|
||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
this.profileKeyData = profileKeyData;
|
this.profileKeyData = profileKeyData;
|
||||||
|
this.remoteChatSessionData = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new PlayerInfoData for Minecraft 1.19.3 or later.
|
||||||
|
*
|
||||||
|
* @param profileId the id of the profile (has to be non-null)
|
||||||
|
* @param latency the latency in milliseconds
|
||||||
|
* @param listed whether the player is listed in the tab list
|
||||||
|
* @param gameMode the game mode
|
||||||
|
* @param profile the game profile
|
||||||
|
* @param displayName display name in tab list (optional)
|
||||||
|
* @param remoteChatSession the remote chat session for this profile or null
|
||||||
|
*/
|
||||||
|
public PlayerInfoData(UUID profileId, int latency, boolean listed, NativeGameMode gameMode, WrappedGameProfile profile, WrappedChatComponent displayName, @Nullable WrappedRemoteChatSessionData remoteChatSession) {
|
||||||
|
this.profileId = profileId;
|
||||||
|
this.latency = latency;
|
||||||
|
this.listed = listed;
|
||||||
|
this.gameMode = gameMode;
|
||||||
|
this.profile = profile;
|
||||||
|
this.displayName = displayName;
|
||||||
|
this.profileKeyData = null;
|
||||||
|
this.remoteChatSessionData = remoteChatSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -69,6 +125,9 @@ public class PlayerInfoData {
|
||||||
* @return the id of the profile
|
* @return the id of the profile
|
||||||
*/
|
*/
|
||||||
public UUID getProfileId() {
|
public UUID getProfileId() {
|
||||||
|
if(profileId == null && profile != null) {
|
||||||
|
return profile.getUUID(); // Ensure forward compatability
|
||||||
|
}
|
||||||
return profileId;
|
return profileId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +156,7 @@ public class PlayerInfoData {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets if the player is listed on the client.
|
* Gets if the player is listed on the client (since 1.19.3)
|
||||||
* @return if the player is listed
|
* @return if the player is listed
|
||||||
*/
|
*/
|
||||||
public boolean isListed() {
|
public boolean isListed() {
|
||||||
|
@ -121,11 +180,21 @@ public class PlayerInfoData {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the profile key data of the player represented by this data, null if not present.
|
* Returns the public key of the profile (since 1.19). Returns the public key of the remote chat session since 1.19.3
|
||||||
* @return The profile key data
|
* @return The public key of the profile.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
public WrappedProfileKeyData getProfileKeyData() {
|
public WrappedProfileKeyData getProfileKeyData() {
|
||||||
return this.profileKeyData;
|
return this.profileKeyData != null ? this.profileKeyData : (this.remoteChatSessionData != null ? this.remoteChatSessionData.getProfilePublicKey() : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the remoteChatSessionData (since 1.19.3)
|
||||||
|
* @return The remote chat sesion data or null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public WrappedRemoteChatSessionData getRemoteChatSessionData() {
|
||||||
|
return this.remoteChatSessionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -157,8 +226,7 @@ public class PlayerInfoData {
|
||||||
args.add(MinecraftReflection.getIChatBaseComponentClass());
|
args.add(MinecraftReflection.getIChatBaseComponentClass());
|
||||||
|
|
||||||
if (MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
|
if (MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
|
||||||
// RemoteChatSession$a...
|
args.add(MinecraftReflection.getRemoteChatSessionDataClass());
|
||||||
args.add(MinecraftReflection.getRemoteChatSessionClass().getClasses()[0]);
|
|
||||||
} else if (MinecraftVersion.WILD_UPDATE.atOrAbove()) {
|
} else if (MinecraftVersion.WILD_UPDATE.atOrAbove()) {
|
||||||
args.add(MinecraftReflection.getProfilePublicKeyDataClass());
|
args.add(MinecraftReflection.getProfilePublicKeyDataClass());
|
||||||
}
|
}
|
||||||
|
@ -175,26 +243,28 @@ public class PlayerInfoData {
|
||||||
Object gameMode = EnumWrappers.getGameModeConverter().getGeneric(specific.gameMode);
|
Object gameMode = EnumWrappers.getGameModeConverter().getGeneric(specific.gameMode);
|
||||||
Object displayName = specific.displayName != null ? specific.displayName.handle : null;
|
Object displayName = specific.displayName != null ? specific.displayName.handle : null;
|
||||||
|
|
||||||
|
Object profile = specific.profile != null ? specific.profile.handle : null;
|
||||||
if (MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
|
if (MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
|
||||||
return constructor.newInstance(
|
return constructor.newInstance(
|
||||||
specific.profileId,
|
specific.profileId,
|
||||||
specific.profile.handle,
|
profile,
|
||||||
specific.listed,
|
specific.listed,
|
||||||
specific.latency,
|
specific.latency,
|
||||||
gameMode,
|
gameMode,
|
||||||
displayName,
|
displayName,
|
||||||
null); // TODO: do we want to support this?
|
specific.remoteChatSessionData != null ? BukkitConverters.getWrappedRemoteChatSessionDataConverter().getGeneric(specific.remoteChatSessionData) : null
|
||||||
|
);
|
||||||
} else if (MinecraftVersion.WILD_UPDATE.atOrAbove()) {
|
} else if (MinecraftVersion.WILD_UPDATE.atOrAbove()) {
|
||||||
return constructor.newInstance(
|
return constructor.newInstance(
|
||||||
specific.profile.handle,
|
profile,
|
||||||
specific.latency,
|
specific.latency,
|
||||||
gameMode,
|
gameMode,
|
||||||
displayName,
|
displayName,
|
||||||
specific.profileKeyData == null ? null : specific.profileKeyData.handle);
|
specific.profileKeyData == null ? null : specific.profileKeyData.handle);
|
||||||
} else if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
} else if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||||
return constructor.newInstance(specific.profile.handle, specific.latency, gameMode, displayName);
|
return constructor.newInstance(profile, specific.latency, gameMode, displayName);
|
||||||
} else {
|
} else {
|
||||||
return constructor.newInstance(null, specific.profile.handle, specific.latency, gameMode, displayName);
|
return constructor.newInstance(null, profile, specific.latency, gameMode, displayName);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Failed to construct PlayerInfoData.", e);
|
throw new RuntimeException("Failed to construct PlayerInfoData.", e);
|
||||||
|
@ -222,8 +292,18 @@ public class PlayerInfoData {
|
||||||
MinecraftReflection.getIChatBaseComponentClass(), BukkitConverters.getWrappedChatComponentConverter());
|
MinecraftReflection.getIChatBaseComponentClass(), BukkitConverters.getWrappedChatComponentConverter());
|
||||||
WrappedChatComponent displayName = displayNames.read(0);
|
WrappedChatComponent displayName = displayNames.read(0);
|
||||||
|
|
||||||
|
if(MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
|
||||||
|
return new PlayerInfoData(modifier.<UUID>withType(UUID.class).read(0),
|
||||||
|
latency,
|
||||||
|
modifier.<Boolean>withType(boolean.class).read(0),
|
||||||
|
gameMode,
|
||||||
|
gameProfile,
|
||||||
|
displayName,
|
||||||
|
modifier.withType(MinecraftReflection.getRemoteChatSessionDataClass(), BukkitConverters.getWrappedRemoteChatSessionDataConverter()).read(0)
|
||||||
|
);
|
||||||
|
}
|
||||||
WrappedProfileKeyData key = null;
|
WrappedProfileKeyData key = null;
|
||||||
if (MinecraftVersion.WILD_UPDATE.atOrAbove() && !MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
|
if (MinecraftVersion.WILD_UPDATE.atOrAbove()) {
|
||||||
StructureModifier<WrappedProfileKeyData> keyData = modifier.withType(
|
StructureModifier<WrappedProfileKeyData> keyData = modifier.withType(
|
||||||
MinecraftReflection.getProfilePublicKeyDataClass(), BukkitConverters.getWrappedPublicKeyDataConverter());
|
MinecraftReflection.getProfilePublicKeyDataClass(), BukkitConverters.getWrappedPublicKeyDataConverter());
|
||||||
key = keyData.read(0);
|
key = keyData.read(0);
|
||||||
|
@ -253,20 +333,34 @@ public class PlayerInfoData {
|
||||||
// Only compare objects of similar type
|
// Only compare objects of similar type
|
||||||
if (obj instanceof PlayerInfoData) {
|
if (obj instanceof PlayerInfoData) {
|
||||||
PlayerInfoData other = (PlayerInfoData) obj;
|
PlayerInfoData other = (PlayerInfoData) obj;
|
||||||
return profile.equals(other.profile) && latency == other.latency && gameMode == other.gameMode
|
return Objects.equals(profile, other.profile)
|
||||||
&& Objects.equals(displayName, other.displayName);
|
&& Objects.equals(profileId, other.profileId)
|
||||||
|
&& latency == other.latency
|
||||||
|
&& gameMode == other.gameMode
|
||||||
|
&& Objects.equals(displayName, other.displayName)
|
||||||
|
&& listed == other.listed
|
||||||
|
&& Objects.equals(remoteChatSessionData, other.remoteChatSessionData)
|
||||||
|
&& Objects.equals(profileKeyData, other.profileKeyData);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(latency, gameMode, profile, displayName);
|
return Objects.hash(latency, gameMode, profile, displayName, profileKeyData, remoteChatSessionData, listed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
if(MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) {
|
||||||
|
return String.format("PlayerInfoData[latency=%s, listed=%b, gameMode=%s, profile=%s, displayName=%s, remoteChatSession=%s]",
|
||||||
|
latency, listed, gameMode, profile, displayName, remoteChatSessionData);
|
||||||
|
}
|
||||||
|
if(MinecraftVersion.WILD_UPDATE.atOrAbove()) {
|
||||||
|
return String.format("PlayerInfoData[latency=%s, listed=%b, gameMode=%s, profile=%s, displayName=%s, profilePublicKey=%s]",
|
||||||
|
latency, listed, gameMode, profile, displayName, profileKeyData);
|
||||||
|
}
|
||||||
return String.format("PlayerInfoData[latency=%s, gameMode=%s, profile=%s, displayName=%s]",
|
return String.format("PlayerInfoData[latency=%s, gameMode=%s, profile=%s, displayName=%s]",
|
||||||
latency, gameMode, profile, displayName);
|
latency, gameMode, profile, displayName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
package com.comphenix.protocol.wrappers;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||||
|
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper around the remote chat session.
|
||||||
|
*
|
||||||
|
* @since 1.19.3
|
||||||
|
*/
|
||||||
|
public class WrappedRemoteChatSessionData extends AbstractWrapper {
|
||||||
|
private final static Class<?> HANDLE_TYPE = MinecraftReflection.getRemoteChatSessionDataClass();
|
||||||
|
private static ConstructorAccessor CONSTRUCTOR;
|
||||||
|
private StructureModifier<Object> modifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new profile public key wrapper directly from a nms RemoteChatSession.Data/RemoteChatSession.a object.
|
||||||
|
*
|
||||||
|
* @param handle the handle to create the wrapper from.
|
||||||
|
*/
|
||||||
|
public WrappedRemoteChatSessionData(Object handle) {
|
||||||
|
super(HANDLE_TYPE);
|
||||||
|
this.setHandle(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WrappedRemoteChatSessionData(UUID sessionId, WrappedProfilePublicKey.WrappedProfileKeyData profilePublicKey) {
|
||||||
|
super(HANDLE_TYPE);
|
||||||
|
if (CONSTRUCTOR == null) {
|
||||||
|
CONSTRUCTOR = Accessors.getConstructorAccessor(
|
||||||
|
this.getHandleType(),
|
||||||
|
UUID.class, MinecraftReflection.getProfilePublicKeyDataClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setHandle(CONSTRUCTOR.invoke(sessionId, profilePublicKey.getHandle()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the id of the current session
|
||||||
|
* @return session id
|
||||||
|
*/
|
||||||
|
public UUID getSessionID() {
|
||||||
|
return this.modifier.<UUID>withType(UUID.class).read(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the id for this session
|
||||||
|
* @param sessionId new session id
|
||||||
|
*/
|
||||||
|
public void setSessionID(UUID sessionId) {
|
||||||
|
this.modifier.<UUID>withType(UUID.class).write(0, sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the ProfileKeyData
|
||||||
|
* @return the public key data for this session
|
||||||
|
*/
|
||||||
|
public WrappedProfilePublicKey.WrappedProfileKeyData getProfilePublicKey() {
|
||||||
|
return this.modifier.withType(MinecraftReflection.getProfilePublicKeyDataClass(), BukkitConverters.getWrappedPublicKeyDataConverter()).read(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the profile key data for this session
|
||||||
|
* @param data ProfileKeyData
|
||||||
|
*/
|
||||||
|
public void setProfilePublicKey(WrappedProfilePublicKey.WrappedProfileKeyData data) {
|
||||||
|
this.modifier.withType(MinecraftReflection.getProfilePublicKeyDataClass(), BukkitConverters.getWrappedPublicKeyDataConverter()).write(0, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setHandle(Object handle) {
|
||||||
|
super.setHandle(handle);
|
||||||
|
this.modifier = new StructureModifier<>(HANDLE_TYPE).withTarget(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if(obj instanceof WrappedRemoteChatSessionData) {
|
||||||
|
return handle.equals(((WrappedRemoteChatSessionData) obj).getHandle());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return handle.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return handle.hashCode();
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,26 +40,13 @@ import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||||
import com.comphenix.protocol.reflect.cloning.SerializableCloner;
|
import com.comphenix.protocol.reflect.cloning.SerializableCloner;
|
||||||
import com.comphenix.protocol.utility.MinecraftMethods;
|
import com.comphenix.protocol.utility.MinecraftMethods;
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
import com.comphenix.protocol.wrappers.*;
|
||||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
|
||||||
import com.comphenix.protocol.wrappers.ComponentConverter;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
|
import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
|
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.Hand;
|
import com.comphenix.protocol.wrappers.EnumWrappers.Hand;
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
|
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.SoundCategory;
|
import com.comphenix.protocol.wrappers.EnumWrappers.SoundCategory;
|
||||||
import com.comphenix.protocol.wrappers.MovingObjectPositionBlock;
|
|
||||||
import com.comphenix.protocol.wrappers.Pair;
|
|
||||||
import com.comphenix.protocol.wrappers.PlayerInfoData;
|
|
||||||
import com.comphenix.protocol.wrappers.WrappedBlockData;
|
|
||||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
|
||||||
import com.comphenix.protocol.wrappers.WrappedDataValue;
|
|
||||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
|
||||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
|
||||||
import com.comphenix.protocol.wrappers.WrappedEnumEntityUseAction;
|
|
||||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
|
||||||
import com.comphenix.protocol.wrappers.WrappedRegistry;
|
|
||||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
@ -768,7 +755,7 @@ public class PacketContainerTest {
|
||||||
NativeGameMode.CREATIVE,
|
NativeGameMode.CREATIVE,
|
||||||
new WrappedGameProfile(new UUID(0, 0), "system"),
|
new WrappedGameProfile(new UUID(0, 0), "system"),
|
||||||
null,
|
null,
|
||||||
null);
|
(WrappedRemoteChatSessionData) null);
|
||||||
updatePlayerInfoActions.getPlayerInfoDataLists().write(1, Collections.singletonList(data));
|
updatePlayerInfoActions.getPlayerInfoDataLists().write(1, Collections.singletonList(data));
|
||||||
|
|
||||||
Set<EnumWrappers.PlayerInfoAction> readActions = updatePlayerInfoActions.getPlayerInfoActions().read(0);
|
Set<EnumWrappers.PlayerInfoAction> readActions = updatePlayerInfoActions.getPlayerInfoActions().read(0);
|
||||||
|
@ -871,7 +858,6 @@ public class PacketContainerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
// gives some indication which cloning process fails as the checks itself are happening outside this method
|
// gives some indication which cloning process fails as the checks itself are happening outside this method
|
||||||
System.out.println("Cloning " + type);
|
|
||||||
|
|
||||||
// Clone the packet all three ways
|
// Clone the packet all three ways
|
||||||
PacketContainer shallowCloned = constructed.shallowClone();
|
PacketContainer shallowCloned = constructed.shallowClone();
|
||||||
|
@ -886,8 +872,8 @@ public class PacketContainerTest {
|
||||||
serializedCloned.getLongs().write(0, 0L);
|
serializedCloned.getLongs().write(0, 0L);
|
||||||
}
|
}
|
||||||
this.assertPacketsEqualAndSerializable(constructed, serializedCloned);
|
this.assertPacketsEqualAndSerializable(constructed, serializedCloned);
|
||||||
} catch (Exception ex) {
|
} catch (Throwable t) {
|
||||||
Assertions.fail("Unable to clone " + type, ex);
|
Assertions.fail("Unable to clone " + type, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,15 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.wrappers.WrappedProfilePublicKey;
|
||||||
|
import com.comphenix.protocol.wrappers.WrappedRemoteChatSessionData;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
@ -49,4 +57,17 @@ public class TestUtils {
|
||||||
public static void setFinalField(Object obj, Field field, Object newValue) {
|
public static void setFinalField(Object obj, Field field, Object newValue) {
|
||||||
Accessors.getFieldAccessor(field).set(obj, newValue);
|
Accessors.getFieldAccessor(field).set(obj, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static KeyPair generateKeyPair() throws Exception {
|
||||||
|
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||||
|
keyPairGenerator.initialize(1024);
|
||||||
|
return keyPairGenerator.generateKeyPair();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WrappedRemoteChatSessionData creteDummyRemoteChatSessionData() throws Exception {
|
||||||
|
byte[] signature = new byte[256];
|
||||||
|
new Random().nextBytes(signature);
|
||||||
|
|
||||||
|
return new WrappedRemoteChatSessionData(UUID.randomUUID(), new WrappedProfilePublicKey.WrappedProfileKeyData(Instant.now(), TestUtils.generateKeyPair().getPublic(), signature));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
package com.comphenix.protocol.wrappers;
|
package com.comphenix.protocol.wrappers;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.BukkitInitialization;
|
import com.comphenix.protocol.BukkitInitialization;
|
||||||
import com.comphenix.protocol.PacketType;
|
import com.comphenix.protocol.PacketType;
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||||
|
import com.comphenix.protocol.utility.TestUtils;
|
||||||
import com.comphenix.protocol.wrappers.Either.Left;
|
import com.comphenix.protocol.wrappers.Either.Left;
|
||||||
|
|
||||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
|
@ -20,37 +16,50 @@ import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.security.KeyFactory;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.spec.EncodedKeySpec;
|
||||||
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
public class BukkitConvertersTest {
|
public class BukkitConvertersTest {
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void beforeClass() {
|
public static void beforeClass() {
|
||||||
BukkitInitialization.initializeAll();
|
BukkitInitialization.initializeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testItemStacks() {
|
public void testItemStacks() {
|
||||||
ItemStack item = new ItemStack(Material.DIAMOND_SWORD, 16);
|
ItemStack item = new ItemStack(Material.DIAMOND_SWORD, 16);
|
||||||
item.addEnchantment(Enchantment.DAMAGE_ALL, 4);
|
item.addEnchantment(Enchantment.DAMAGE_ALL, 4);
|
||||||
ItemMeta meta = item.getItemMeta();
|
ItemMeta meta = item.getItemMeta();
|
||||||
meta.setDisplayName(ChatColor.GREEN + "Diamond Sword");
|
meta.setDisplayName(ChatColor.GREEN + "Diamond Sword");
|
||||||
item.setItemMeta(meta);
|
item.setItemMeta(meta);
|
||||||
|
|
||||||
EquivalentConverter<ItemStack> converter = BukkitConverters.getItemStackConverter();
|
EquivalentConverter<ItemStack> converter = BukkitConverters.getItemStackConverter();
|
||||||
Object nmsStack = converter.getGeneric(item);
|
Object nmsStack = converter.getGeneric(item);
|
||||||
ItemStack back = converter.getSpecific(nmsStack);
|
ItemStack back = converter.getSpecific(nmsStack);
|
||||||
|
|
||||||
assertEquals(item.getType(), back.getType());
|
assertEquals(item.getType(), back.getType());
|
||||||
assertEquals(item.getDurability(), back.getDurability());
|
assertEquals(item.getDurability(), back.getDurability());
|
||||||
assertEquals(item.hasItemMeta(), back.hasItemMeta());
|
assertEquals(item.hasItemMeta(), back.hasItemMeta());
|
||||||
assertTrue(Bukkit.getItemFactory().equals(item.getItemMeta(), back.getItemMeta()));
|
assertTrue(Bukkit.getItemFactory().equals(item.getItemMeta(), back.getItemMeta()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEither() {
|
public void testEither() {
|
||||||
Either<String, String> test = new Left<>("bla");
|
Either<String, String> test = new Left<>("bla");
|
||||||
|
|
||||||
EquivalentConverter<Either<String, String>> converter = BukkitConverters.getEitherConverter(
|
EquivalentConverter<Either<String, String>> converter = BukkitConverters.getEitherConverter(
|
||||||
Converters.passthrough(String.class), Converters.passthrough(String.class)
|
Converters.passthrough(String.class), Converters.passthrough(String.class)
|
||||||
);
|
);
|
||||||
|
|
||||||
com.mojang.datafixers.util.Either<String, String> nmsEither = (com.mojang.datafixers.util.Either<String, String>) converter.getGeneric(test);
|
com.mojang.datafixers.util.Either<String, String> nmsEither = (com.mojang.datafixers.util.Either<String, String>) converter.getGeneric(test);
|
||||||
|
@ -60,16 +69,26 @@ public class BukkitConvertersTest {
|
||||||
assertEquals(wrapped.right(), nmsEither.right());
|
assertEquals(wrapped.right(), nmsEither.right());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPacketContainerConverter() {
|
public void testPacketContainerConverter() {
|
||||||
for (PacketType type : PacketType.values()) {
|
for (PacketType type : PacketType.values()) {
|
||||||
if(!type.isSupported()) {
|
if (!type.isSupported()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
PacketContainer container = new PacketContainer(type);
|
PacketContainer container = new PacketContainer(type);
|
||||||
Object generic = BukkitConverters.getPacketContainerConverter().getGeneric(container);
|
Object generic = BukkitConverters.getPacketContainerConverter().getGeneric(container);
|
||||||
Object specific = BukkitConverters.getPacketContainerConverter().getSpecific(generic);
|
Object specific = BukkitConverters.getPacketContainerConverter().getSpecific(generic);
|
||||||
assertTrue(EqualsBuilder.reflectionEquals(container, specific)); // PacketContainer does not properly implement equals(.)
|
assertTrue(EqualsBuilder.reflectionEquals(container, specific)); // PacketContainer does not properly implement equals(.)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoteChatSessionDataConverter() throws Exception {
|
||||||
|
WrappedRemoteChatSessionData wrappedRemoteChatSessionData = TestUtils.creteDummyRemoteChatSessionData();
|
||||||
|
Object generic = BukkitConverters.getWrappedRemoteChatSessionDataConverter().getGeneric(wrappedRemoteChatSessionData);
|
||||||
|
|
||||||
|
WrappedRemoteChatSessionData specific = BukkitConverters.getWrappedRemoteChatSessionDataConverter().getSpecific(generic);
|
||||||
|
assertEquals(wrappedRemoteChatSessionData, specific);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ package com.comphenix.protocol.wrappers;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
import com.comphenix.protocol.BukkitInitialization;
|
import com.comphenix.protocol.BukkitInitialization;
|
||||||
|
import com.comphenix.protocol.utility.TestUtils;
|
||||||
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
|
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
@ -33,14 +34,19 @@ public class PlayerInfoDataTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void test() throws Exception {
|
||||||
WrappedGameProfile profile = new WrappedGameProfile(UUID.randomUUID(), "Name");
|
WrappedGameProfile profile = new WrappedGameProfile(UUID.randomUUID(), "Name");
|
||||||
WrappedChatComponent displayName = WrappedChatComponent.fromText("Name's Name");
|
WrappedChatComponent displayName = WrappedChatComponent.fromText("Name's Name");
|
||||||
|
|
||||||
PlayerInfoData data = new PlayerInfoData(profile, 42, NativeGameMode.CREATIVE, displayName);
|
testWriteBack(new PlayerInfoData(profile, 42, NativeGameMode.CREATIVE, displayName));
|
||||||
|
testWriteBack(new PlayerInfoData(profile.getUUID(), 42, false, NativeGameMode.CREATIVE, profile, displayName, TestUtils.creteDummyRemoteChatSessionData()));
|
||||||
|
testWriteBack(new PlayerInfoData(profile.getUUID(), 42, false, NativeGameMode.CREATIVE, null, null, TestUtils.creteDummyRemoteChatSessionData()));
|
||||||
|
testWriteBack(new PlayerInfoData(profile.getUUID(), 42, true, NativeGameMode.CREATIVE, null, displayName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testWriteBack(PlayerInfoData data) {
|
||||||
Object generic = PlayerInfoData.getConverter().getGeneric(data);
|
Object generic = PlayerInfoData.getConverter().getGeneric(data);
|
||||||
PlayerInfoData back = PlayerInfoData.getConverter().getSpecific(generic);
|
PlayerInfoData back = PlayerInfoData.getConverter().getSpecific(generic);
|
||||||
|
|
||||||
assertEquals(data, back);
|
assertEquals(data, back);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue