1
1
package cat .nyaa .nyaacore .utils ;
2
2
3
+ import cat .nyaa .nyaacore .NyaaCoreLoader ;
4
+ import cat .nyaa .nyaacore .http .client .HttpClient ;
5
+ import com .google .common .collect .BiMap ;
6
+ import com .google .common .collect .HashBiMap ;
7
+ import com .google .common .collect .ImmutableBiMap ;
8
+ import com .google .gson .Gson ;
9
+ import com .google .gson .reflect .TypeToken ;
10
+ import io .netty .handler .codec .http .FullHttpResponse ;
3
11
import org .bukkit .Bukkit ;
4
12
import org .bukkit .OfflinePlayer ;
5
13
import org .bukkit .event .EventHandler ;
8
16
import org .bukkit .event .player .PlayerJoinEvent ;
9
17
import org .bukkit .event .player .PlayerQuitEvent ;
10
18
11
- import java .util .Arrays ;
12
- import java .util .Comparator ;
13
- import java .util .Locale ;
14
- import java .util .Map ;
19
+ import java .util .*;
20
+ import java .util .concurrent .CompletableFuture ;
21
+ import java .util .concurrent .ConcurrentMap ;
15
22
import java .util .function .BinaryOperator ;
16
23
import java .util .function .Function ;
24
+ import java .util .logging .Level ;
17
25
import java .util .stream .Collectors ;
26
+ import java .util .stream .Stream ;
27
+
28
+ import static java .nio .charset .StandardCharsets .UTF_8 ;
18
29
19
30
public class OfflinePlayerUtils {
20
- private static Map <String , OfflinePlayer > playerCache ;
31
+ private static ConcurrentMap <String , OfflinePlayer > playerCache ;
32
+ private static ConcurrentMap <UUID , String > nameCache ;
33
+ private static TypeToken <List <Map <String , Object >>> typeTokenListMap = new TypeToken <List <Map <String , Object >>>() {
34
+ };
35
+ private static final String UNDASHED = "(\\ w{8})(\\ w{4})(\\ w{4})(\\ w{4})(\\ w{12})" ;
36
+ private static final String DASHED = "$1-$2-$3-$4-$5" ;
21
37
22
38
private OfflinePlayerUtils () {
23
39
}
24
40
25
41
public static void init () {
26
42
playerCache = Arrays .stream (Bukkit .getOfflinePlayers ())
27
43
.filter (p -> p .getName () != null )
28
- .collect (Collectors .toMap (p -> p .getName ().toLowerCase (Locale .ENGLISH ), Function .identity (), BinaryOperator .maxBy (Comparator .comparing (OfflinePlayer ::getLastPlayed ))));
44
+ .collect (Collectors .toConcurrentMap (p -> p .getName ().toLowerCase (Locale .ENGLISH ), Function .identity (), BinaryOperator .maxBy (Comparator .comparing (OfflinePlayer ::getLastPlayed ))));
45
+ nameCache = playerCache .entrySet ().stream ().collect (Collectors .toConcurrentMap (e -> e .getValue ().getUniqueId (), Map .Entry ::getKey ));
29
46
}
30
47
31
48
public static OfflinePlayer lookupPlayer (String name ) {
@@ -34,6 +51,63 @@ public static OfflinePlayer lookupPlayer(String name) {
34
51
return playerCache .get (name .toLowerCase (Locale .ENGLISH ));
35
52
}
36
53
54
+ public static CompletableFuture <BiMap <String , UUID >> lookupPlayerNamesOnline (String ... names ) {
55
+ List <String > nameList = new LinkedList <>(Arrays .asList (names ));
56
+ BiMap <String , UUID > ret = HashBiMap .create ();
57
+ Iterator <String > iterator = nameList .iterator ();
58
+ while (iterator .hasNext ()) {
59
+ String n = iterator .next ();
60
+ OfflinePlayer player = playerCache .get (n .toLowerCase (Locale .ENGLISH ));
61
+ if (player != null ) {
62
+ iterator .remove ();
63
+ ret .put (n , player .getUniqueId ());
64
+ }
65
+ }
66
+ CompletableFuture <FullHttpResponse > response = HttpClient .postJson ("https://api.mojang.com/profiles/minecraft" , Collections .emptyMap (), new Gson ().toJson (Stream .of (names ).collect (Collectors .toList ())));
67
+ return response .thenApply ((r ) -> {
68
+ NyaaCoreLoader .getInstance ().getLogger ().log (Level .FINER , "request name -> uuid api " + r .status ().code ());
69
+ if (r .status ().code () > 299 || r .content () == null ) {
70
+ return HashBiMap .<UUID , String >create ();
71
+ }
72
+ List <Map <String , Object >> result = new Gson ().fromJson (r .content ().toString (UTF_8 ), typeTokenListMap .getType ());
73
+ return result .stream ().collect (ImmutableBiMap .toImmutableBiMap (m -> {
74
+ m .get ("id" );
75
+ return UUID .fromString (((String ) m .get ("id" )).replaceAll (UNDASHED , DASHED ));
76
+ },
77
+ m -> (String ) m .get ("name" )));
78
+ }).thenApply (u -> {
79
+ nameCache .putAll (u );
80
+ ret .putAll (u .inverse ());
81
+ return ret ;
82
+ }).exceptionally ((e ) -> {
83
+ NyaaCoreLoader .getInstance ().getLogger ().log (Level .INFO , "failed to request name -> uuid api" , e );
84
+ return ret ;
85
+ });
86
+ }
87
+
88
+ public static CompletableFuture <String > lookupPlayerNameByUuidOnline (UUID uuid ) {
89
+ String s = nameCache .get (uuid );
90
+ if (s != null ) {
91
+ return CompletableFuture .completedFuture (s );
92
+ }
93
+ CompletableFuture <FullHttpResponse > response = HttpClient .get ("https://api.mojang.com/user/profiles/" + uuid .toString ().toLowerCase ().replace ("-" , "" ) + "/names" , Collections .emptyMap ());
94
+ return response .thenApply ((r ) -> {
95
+ NyaaCoreLoader .getInstance ().getLogger ().log (Level .FINER , "request uuid -> name api " + r .status ().code ());
96
+ if (r .status ().code () > 299 || r .content () == null ) {
97
+ return null ;
98
+ }
99
+ List <Map <String , Object >> nameMapsList = new Gson ().fromJson (r .content ().toString (UTF_8 ), typeTokenListMap .getType ());
100
+ if (nameMapsList .isEmpty ()){
101
+ return null ;
102
+ }
103
+ nameCache .put (uuid , nameMapsList .get (nameMapsList .size () - 1 ).get ("name" ).toString ());
104
+ return nameCache .get (uuid );
105
+ }).exceptionally ((e ) -> {
106
+ NyaaCoreLoader .getInstance ().getLogger ().log (Level .INFO , "failed to request uuid -> name api" , e );
107
+ return null ;
108
+ });
109
+ }
110
+
37
111
public static class _Listener implements Listener {
38
112
@ EventHandler (priority = EventPriority .MONITOR )
39
113
public void onPlayerJoin (PlayerJoinEvent event ) {
0 commit comments