Compare commits
3 Commits
b5b5de889e
...
95f2a0f3a2
Author | SHA1 | Date |
---|---|---|
quang | 95f2a0f3a2 | |
Dan Mulloy | e1255edb32 | |
Trần Nguyễn Ngọc Quang | cd45943cdd |
|
@ -527,7 +527,7 @@ public class PacketEvent extends EventObject implements Cancellable {
|
||||||
|
|
||||||
// Write the name of the player (or NULL if it's not set)
|
// Write the name of the player (or NULL if it's not set)
|
||||||
Player player = getPlayer();
|
Player player = getPlayer();
|
||||||
output.writeObject(player != null ? new SerializedOfflinePlayer(player) : null);
|
output.writeObject(player != null ? SerializedOfflinePlayer.init(player) : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readObject(ObjectInputStream input) throws ClassNotFoundException, IOException {
|
private void readObject(ObjectInputStream input) throws ClassNotFoundException, IOException {
|
||||||
|
|
|
@ -51,8 +51,12 @@ import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@ -61,7 +65,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
*
|
*
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
|
abstract class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generated by Eclipse.
|
* Generated by Eclipse.
|
||||||
|
@ -84,11 +88,33 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
|
||||||
private long lastSeen;
|
private long lastSeen;
|
||||||
|
|
||||||
private static final Constructor<?> proxyPlayerConstructor = setupProxyPlayerConstructor();
|
private static final Constructor<?> proxyPlayerConstructor = setupProxyPlayerConstructor();
|
||||||
|
private static final Constructor<? extends SerializedOfflinePlayer> CLASS_CONSTRUCTOR = setupClassConstructor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a serializable offline player object from another offline player.
|
||||||
|
* <p>
|
||||||
|
* All other methods cause an exception.
|
||||||
|
*
|
||||||
|
* @param player - another offline player.
|
||||||
|
* @return A serializable offline player object.
|
||||||
|
*/
|
||||||
|
public static SerializedOfflinePlayer init(OfflinePlayer player) {
|
||||||
|
try {
|
||||||
|
CLASS_CONSTRUCTOR.setAccessible(true);
|
||||||
|
return CLASS_CONSTRUCTOR.newInstance(player);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new RuntimeException("Cannot access reflection.", e);
|
||||||
|
} catch (InstantiationException e) {
|
||||||
|
throw new RuntimeException("Cannot instantiate object.", e);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw new RuntimeException("Error in invocation.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor used by serialization.
|
* Constructor used by serialization.
|
||||||
*/
|
*/
|
||||||
public SerializedOfflinePlayer() {
|
protected SerializedOfflinePlayer() {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +123,7 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
|
||||||
*
|
*
|
||||||
* @param offline - another player.
|
* @param offline - another player.
|
||||||
*/
|
*/
|
||||||
public SerializedOfflinePlayer(OfflinePlayer offline) {
|
protected SerializedOfflinePlayer(OfflinePlayer offline) {
|
||||||
this.name = offline.getName();
|
this.name = offline.getName();
|
||||||
this.uuid = offline.getUniqueId();
|
this.uuid = offline.getUniqueId();
|
||||||
this.firstPlayed = offline.getFirstPlayed();
|
this.firstPlayed = offline.getFirstPlayed();
|
||||||
|
@ -145,6 +171,16 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
|
||||||
return lastSeen;
|
return lastSeen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location getRespawnLocation() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location getLocation() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO do we need to implement this?
|
// TODO do we need to implement this?
|
||||||
|
|
||||||
public void incrementStatistic(Statistic statistic) throws IllegalArgumentException {
|
public void incrementStatistic(Statistic statistic) throws IllegalArgumentException {
|
||||||
|
@ -342,6 +378,47 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Constructor<? extends SerializedOfflinePlayer> setupClassConstructor() {
|
||||||
|
final Method[] existingMethods = SerializedOfflinePlayer.class.getDeclaredMethods();
|
||||||
|
final Set<String> existingMethodNames = new HashSet<>();
|
||||||
|
|
||||||
|
for (int idx = 0; idx < existingMethods.length; idx++) {
|
||||||
|
existingMethodNames.add(existingMethods[idx].getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
final Method[] offlinePlayerMethods = OfflinePlayer.class.getMethods();
|
||||||
|
final List<String> methodNamesToAdd = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int idx = 0; idx < offlinePlayerMethods.length; idx++) {
|
||||||
|
final String name = offlinePlayerMethods[idx].getName();
|
||||||
|
|
||||||
|
if (!existingMethodNames.contains(name)) {
|
||||||
|
methodNamesToAdd.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final ElementMatcher.Junction<ByteCodeElement> missingMethods =
|
||||||
|
ElementMatchers.namedOneOf(methodNamesToAdd.toArray(new String[methodNamesToAdd.size()]));
|
||||||
|
|
||||||
|
final InvocationHandlerAdapter throwException = InvocationHandlerAdapter.of((obj, method, args) -> {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"The method " + method.getName() + " is not supported.");
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
return ByteBuddyFactory.getInstance()
|
||||||
|
.createSubclass(SerializedOfflinePlayer.class)
|
||||||
|
.method(missingMethods)
|
||||||
|
.intercept(throwException)
|
||||||
|
.make()
|
||||||
|
.load(ByteBuddyFactory.getInstance().getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
|
||||||
|
.getLoaded()
|
||||||
|
.getConstructor(OfflinePlayer.class);
|
||||||
|
} catch (NoSuchMethodException ex) {
|
||||||
|
throw new RuntimeException("Failed to find SerializedOfflinePlayer constructor!", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Constructor<? extends Player> setupProxyPlayerConstructor() {
|
private static Constructor<? extends Player> setupProxyPlayerConstructor() {
|
||||||
final Method[] offlinePlayerMethods = OfflinePlayer.class.getMethods();
|
final Method[] offlinePlayerMethods = OfflinePlayer.class.getMethods();
|
||||||
final String[] methodNames = new String[offlinePlayerMethods.length];
|
final String[] methodNames = new String[offlinePlayerMethods.length];
|
||||||
|
|
|
@ -39,7 +39,7 @@ public class SerializedOfflinePlayerTest {
|
||||||
when(offlinePlayer.hasPlayedBefore()).thenReturn(playedBefore);
|
when(offlinePlayer.hasPlayedBefore()).thenReturn(playedBefore);
|
||||||
when(offlinePlayer.isWhitelisted()).thenReturn(whitelisted);
|
when(offlinePlayer.isWhitelisted()).thenReturn(whitelisted);
|
||||||
|
|
||||||
serializedOfflinePlayer = new SerializedOfflinePlayer(offlinePlayer);
|
serializedOfflinePlayer = SerializedOfflinePlayer.init(offlinePlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue