51
51
import java .lang .reflect .Method ;
52
52
import java .time .Duration ;
53
53
import java .time .Instant ;
54
+ import java .util .ArrayList ;
54
55
import java .util .Date ;
56
+ import java .util .HashSet ;
57
+ import java .util .List ;
55
58
import java .util .Map ;
59
+ import java .util .Set ;
56
60
import java .util .UUID ;
57
61
import java .util .concurrent .ConcurrentHashMap ;
58
62
61
65
*
62
66
* @author Kristian
63
67
*/
64
- class SerializedOfflinePlayer implements OfflinePlayer , Serializable {
68
+ abstract class SerializedOfflinePlayer implements OfflinePlayer , Serializable {
65
69
66
70
/**
67
71
* Generated by Eclipse.
@@ -84,11 +88,25 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
84
88
private long lastSeen ;
85
89
86
90
private static final Constructor <?> proxyPlayerConstructor = setupProxyPlayerConstructor ();
91
+ private static final Constructor <? extends SerializedOfflinePlayer > CLASS_CONSTRUCTOR = setupClassConstructor ();
92
+
93
+ public static SerializedOfflinePlayer init (OfflinePlayer player ) {
94
+ try {
95
+ CLASS_CONSTRUCTOR .setAccessible (true );
96
+ return CLASS_CONSTRUCTOR .newInstance (player );
97
+ } catch (IllegalAccessException e ) {
98
+ throw new RuntimeException ("Cannot access reflection." , e );
99
+ } catch (InstantiationException e ) {
100
+ throw new RuntimeException ("Cannot instantiate object." , e );
101
+ } catch (InvocationTargetException e ) {
102
+ throw new RuntimeException ("Error in invocation." , e );
103
+ }
104
+ }
87
105
88
106
/**
89
107
* Constructor used by serialization.
90
108
*/
91
- public SerializedOfflinePlayer () {
109
+ protected SerializedOfflinePlayer () {
92
110
// Do nothing
93
111
}
94
112
@@ -97,7 +115,7 @@ public SerializedOfflinePlayer() {
97
115
*
98
116
* @param offline - another player.
99
117
*/
100
- public SerializedOfflinePlayer (OfflinePlayer offline ) {
118
+ protected SerializedOfflinePlayer (OfflinePlayer offline ) {
101
119
this .name = offline .getName ();
102
120
this .uuid = offline .getUniqueId ();
103
121
this .firstPlayed = offline .getFirstPlayed ();
@@ -342,6 +360,47 @@ public Player getProxyPlayer() {
342
360
}
343
361
}
344
362
363
+ private static Constructor <? extends SerializedOfflinePlayer > setupClassConstructor () {
364
+ final Method [] existingMethods = SerializedOfflinePlayer .class .getDeclaredMethods ();
365
+ final Set <String > existingMethodNames = new HashSet <>();
366
+
367
+ for (int idx = 0 ; idx < existingMethods .length ; idx ++) {
368
+ existingMethodNames .add (existingMethods [idx ].getName ());
369
+ }
370
+
371
+ final Method [] offlinePlayerMethods = OfflinePlayer .class .getMethods ();
372
+ final List <String > methodNamesToAdd = new ArrayList <>();
373
+
374
+ for (int idx = 0 ; idx < offlinePlayerMethods .length ; idx ++) {
375
+ final String name = offlinePlayerMethods [idx ].getName ();
376
+
377
+ if (!existingMethodNames .contains (name )) {
378
+ methodNamesToAdd .add (name );
379
+ }
380
+ }
381
+
382
+ final ElementMatcher .Junction <ByteCodeElement > missingMethods =
383
+ ElementMatchers .namedOneOf (methodNamesToAdd .toArray (new String [methodNamesToAdd .size ()]));
384
+
385
+ final InvocationHandlerAdapter throwException = InvocationHandlerAdapter .of ((obj , method , args ) -> {
386
+ throw new UnsupportedOperationException (
387
+ "The method " + method .getName () + " is not supported." );
388
+ });
389
+
390
+ try {
391
+ return ByteBuddyFactory .getInstance ()
392
+ .createSubclass (SerializedOfflinePlayer .class )
393
+ .method (missingMethods )
394
+ .intercept (throwException )
395
+ .make ()
396
+ .load (ByteBuddyFactory .getInstance ().getClassLoader (), ClassLoadingStrategy .Default .INJECTION )
397
+ .getLoaded ()
398
+ .getConstructor (OfflinePlayer .class );
399
+ } catch (NoSuchMethodException ex ) {
400
+ throw new RuntimeException ("Failed to find SerializedOfflinePlayer constructor!" , ex );
401
+ }
402
+ }
403
+
345
404
private static Constructor <? extends Player > setupProxyPlayerConstructor () {
346
405
final Method [] offlinePlayerMethods = OfflinePlayer .class .getMethods ();
347
406
final String [] methodNames = new String [offlinePlayerMethods .length ];
0 commit comments