4
4
import com .earth2me .essentials .config .EssentialsConfiguration ;
5
5
import com .earth2me .essentials .config .EssentialsUserConfiguration ;
6
6
import com .earth2me .essentials .craftbukkit .BanLookup ;
7
+ import com .earth2me .essentials .userstorage .ModernUUIDCache ;
7
8
import com .earth2me .essentials .utils .StringUtil ;
8
9
import com .google .common .base .Charsets ;
9
- import com .google .common .collect .Maps ;
10
10
import com .google .common .io .Files ;
11
11
import com .google .gson .reflect .TypeToken ;
12
12
import net .ess3 .api .IEssentials ;
31
31
import java .math .BigInteger ;
32
32
import java .security .DigestInputStream ;
33
33
import java .security .MessageDigest ;
34
- import java .text .DecimalFormat ;
35
34
import java .util .ArrayList ;
36
35
import java .util .Collections ;
37
36
import java .util .Date ;
37
+ import java .util .HashMap ;
38
38
import java .util .HashSet ;
39
39
import java .util .List ;
40
40
import java .util .Locale ;
47
47
import java .util .concurrent .TimeUnit ;
48
48
import java .util .concurrent .atomic .AtomicInteger ;
49
49
import java .util .logging .Level ;
50
- import java .util .regex .Matcher ;
51
50
import java .util .regex .Pattern ;
52
51
53
52
import static com .earth2me .essentials .I18n .tl ;
54
53
55
54
public class EssentialsUpgrade {
56
- private static final FileFilter YML_FILTER = pathname -> pathname .isFile () && pathname .getName ().endsWith (".yml" );
55
+ public static final FileFilter YML_FILTER = pathname -> pathname .isFile () && pathname .getName ().endsWith (".yml" );
57
56
private static final String PATTERN_CONFIG_UUID_REGEX = "(?mi)^uuid:\\ s*([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\\ s*$" ;
58
57
private static final Pattern PATTERN_CONFIG_UUID = Pattern .compile (PATTERN_CONFIG_UUID_REGEX );
59
58
private static final String PATTERN_CONFIG_NAME_REGEX = "(?mi)^lastAccountName:\\ s*[\" \' ]?(\\ w+)[\" \' ]?\\ s*$" ;
@@ -93,7 +92,6 @@ public static void uuidFileConvert(final IEssentials ess, final Boolean ignoreUF
93
92
final int showProgress = countFiles % 250 ;
94
93
95
94
if (showProgress == 0 ) {
96
- ess .getUserMap ().getUUIDMap ().forceWriteUUIDMap ();
97
95
ess .getLogger ().info ("Converted " + countFiles + "/" + userdir .list ().length );
98
96
}
99
97
@@ -103,7 +101,8 @@ public static void uuidFileConvert(final IEssentials ess, final Boolean ignoreUF
103
101
final EssentialsUserConfiguration config ;
104
102
UUID uuid = null ;
105
103
try {
106
- uuid = UUID .fromString (name );
104
+ //noinspection ResultOfMethodCallIgnored
105
+ UUID .fromString (name );
107
106
} catch (final IllegalArgumentException ex ) {
108
107
final File file = new File (userdir , string );
109
108
final EssentialsConfiguration conf = new EssentialsConfiguration (file );
@@ -115,38 +114,40 @@ public static void uuidFileConvert(final IEssentials ess, final Boolean ignoreUF
115
114
116
115
final String uuidString = conf .getString (uuidConf , null );
117
116
117
+ //noinspection ConstantConditions
118
118
for (int i = 0 ; i < 4 ; i ++) {
119
119
try {
120
120
uuid = UUID .fromString (uuidString );
121
121
countEssCache ++;
122
122
break ;
123
123
} catch (final Exception ex2 ) {
124
124
if (conf .getBoolean ("npc" , false )) {
125
- uuid = UUID .nameUUIDFromBytes (("NPC:" + name ).getBytes (Charsets .UTF_8 ));
125
+ uuid = UUID .nameUUIDFromBytes (("NPC:" + ( ess . getSettings (). isSafeUsermap () ? StringUtil . safeString ( name ) : name ) ).getBytes (Charsets .UTF_8 ));
126
126
break ;
127
127
}
128
128
129
129
final org .bukkit .OfflinePlayer player = ess .getServer ().getOfflinePlayer (name );
130
130
uuid = player .getUniqueId ();
131
131
}
132
132
133
+ //noinspection ConstantConditions
133
134
if (uuid != null ) {
134
135
countBukkit ++;
135
136
break ;
136
137
}
137
138
}
138
139
140
+ //noinspection ConstantConditions
139
141
if (uuid != null ) {
140
142
conf .blockingSave ();
141
143
config = new EssentialsUserConfiguration (name , uuid , new File (userdir , uuid + ".yml" ));
142
144
config .convertLegacyFile ();
143
- ess .getUserMap ().trackUUID (uuid , name , false );
145
+ ess .getUsers ().loadUncachedUser (uuid );
144
146
continue ;
145
147
}
146
148
countFails ++;
147
149
}
148
150
}
149
- ess .getUserMap ().getUUIDMap ().forceWriteUUIDMap ();
150
151
151
152
ess .getLogger ().info ("Converted " + countFiles + "/" + countFiles + ". Conversion complete." );
152
153
ess .getLogger ().info ("Converted via cache: " + countEssCache + " :: Converted via lookup: " + countBukkit + " :: Failed to convert: " + countFails );
@@ -913,74 +914,76 @@ private void updateBan(final String playerName, final String banReason, final Lo
913
914
Bukkit .getBanList (BanList .Type .NAME ).addBan (playerName , banReason , banTimeout == 0 ? null : new Date (banTimeout ), Console .NAME );
914
915
}
915
916
916
- private void repairUserMap () {
917
- if (doneFile .getBoolean ("userMapRepaired " , false )) {
917
+ public void generateUidCache () {
918
+ if (doneFile .getBoolean ("newUidCacheBuilt " , false )) {
918
919
return ;
919
920
}
920
- ess .getLogger ().info ("Starting usermap repair" );
921
921
922
+ final File usermapFile = new File (ess .getDataFolder (), "usermap.bin" );
923
+ final File uidsFile = new File (ess .getDataFolder (), "uuids.bin" );
922
924
final File userdataFolder = new File (ess .getDataFolder (), "userdata" );
923
- if (!userdataFolder .isDirectory ()) {
925
+
926
+ if (!userdataFolder .isDirectory () || usermapFile .exists () || uidsFile .exists ()) {
924
927
ess .getLogger ().warning ("Missing userdata folder, aborting" );
928
+ doneFile .setProperty ("newUidCacheBuilt" , true );
929
+ doneFile .save ();
925
930
return ;
926
931
}
927
- final File [] files = userdataFolder .listFiles (YML_FILTER );
928
932
929
- final DecimalFormat format = new DecimalFormat ("#0.00" );
930
- final Map <String , UUID > names = Maps .newHashMap ();
933
+ try {
934
+ if (!usermapFile .createNewFile () || !uidsFile .createNewFile ()) {
935
+ ess .getLogger ().warning ("Couldn't create usermap.bin or uuids.bin, aborting" );
936
+ return ;
937
+ }
931
938
932
- for (int index = 0 ; index < files .length ; index ++) {
933
- final File file = files [index ];
934
- try {
935
- UUID uuid = null ;
936
- final String filename = file .getName ();
937
- final String configData = new String (java .nio .file .Files .readAllBytes (file .toPath ()), Charsets .UTF_8 );
939
+ final Map <UUID , Long > uuids = new HashMap <>();
940
+ final Map <String , UUID > nameToUuidMap = new HashMap <>();
938
941
939
- if (filename .length () > 36 ) {
942
+ final File [] files = userdataFolder .listFiles (YML_FILTER );
943
+ if (files != null ) {
944
+ for (final File file : files ) {
940
945
try {
941
- // ".yml" ending has 4 chars...
942
- uuid = UUID .fromString (filename .substring (0 , filename .length () - 4 ));
943
- } catch ( final IllegalArgumentException ignored ) {
944
- }
945
- }
946
-
947
- final Matcher uuidMatcher = PATTERN_CONFIG_UUID . matcher ( configData );
948
- if ( uuidMatcher . find ()) {
949
- try {
950
- uuid = UUID . fromString ( uuidMatcher . group ( 1 ));
951
- } catch ( final IllegalArgumentException ignored ) {
952
- }
953
- }
954
-
955
- if ( uuid == null ) {
956
- // Don't import
957
- continue ;
958
- }
959
-
960
- final Matcher nameMatcher = PATTERN_CONFIG_NAME . matcher ( configData );
961
- if ( nameMatcher . find ()) {
962
- final String username = nameMatcher . group ( 1 );
963
- if ( username != null && username . length () > 0 ) {
964
- names . put ( StringUtil . safeString ( username ), uuid );
946
+ final String fileName = file . getName ();
947
+ final UUID uuid = UUID .fromString (fileName .substring (0 , fileName .length () - 4 ));
948
+ final EssentialsConfiguration config = new EssentialsConfiguration ( file );
949
+ config . load ();
950
+ String name = config . getString ( "last-account-name" , null );
951
+ name = ess . getSettings (). isSafeUsermap () ? StringUtil . safeString ( name ) : name ;
952
+ final long time = config . getLong ( "timestamps.logout" , 0L );
953
+
954
+ if ( name != null ) {
955
+ if ( nameToUuidMap . containsKey ( name )) {
956
+ final UUID oldUuid = nameToUuidMap . get ( name );
957
+ if ( oldUuid . version () < uuid . version () || ( oldUuid . version () == uuid . version () && uuids . get ( oldUuid ) < time )) {
958
+ ess . getLogger (). warning ( "New UUID found for " + name + ": " + uuid + " (old: " + oldUuid + "). Replacing." );
959
+ uuids . remove ( oldUuid );
960
+ } else {
961
+ ess . getLogger (). warning ( "Found UUID for " + name + ": " + uuid + " (old: " + oldUuid + "). Skipping." );
962
+ continue ;
963
+ }
964
+ }
965
+
966
+ uuids . put ( uuid , config . getLong ( "timestamps.logout" , 0L ));
967
+ nameToUuidMap . put ( name , uuid );
968
+ }
969
+ } catch ( IllegalArgumentException | IndexOutOfBoundsException ignored ) {
965
970
}
966
971
}
972
+ }
967
973
968
- if (index % 1000 == 0 ) {
969
- ess .getLogger ().info ("Reading: " + format .format ((100d * (double ) index ) / files .length )
970
- + "%" );
971
- }
972
- } catch (final IOException e ) {
973
- ess .getLogger ().log (Level .SEVERE , "Error while reading file: " , e );
974
- return ;
974
+ if (!nameToUuidMap .isEmpty ()) {
975
+ ModernUUIDCache .writeNameUuidMap (usermapFile , nameToUuidMap );
975
976
}
976
- }
977
977
978
- ess .getUserMap ().getNames ().putAll (names );
979
- ess .getUserMap ().reloadConfig ();
978
+ if (!uuids .isEmpty ()) {
979
+ ModernUUIDCache .writeUuidCache (uidsFile , uuids .keySet ());
980
+ }
980
981
981
- doneFile .setProperty ("userMapRepaired" , true );
982
- doneFile .save ();
983
- ess .getLogger ().info ("Completed usermap repair." );
982
+ doneFile .setProperty ("newUidCacheBuilt" , true );
983
+ doneFile .save ();
984
+ } catch (final IOException e ) {
985
+ ess .getLogger ().log (Level .SEVERE , "Error while generating initial uuids/names cache" , e );
986
+ }
984
987
}
985
988
986
989
public void beforeSettings () {
@@ -991,6 +994,10 @@ public void beforeSettings() {
991
994
moveMotdRulesToFile ("rules" );
992
995
}
993
996
997
+ public void preModules () {
998
+ generateUidCache ();
999
+ }
1000
+
994
1001
public void afterSettings () {
995
1002
sanitizeAllUserFilenames ();
996
1003
updateUsersPowerToolsFormat ();
@@ -1001,7 +1008,6 @@ public void afterSettings() {
1001
1008
uuidFileChange ();
1002
1009
banFormatChange ();
1003
1010
warnMetrics ();
1004
- repairUserMap ();
1005
1011
convertIgnoreList ();
1006
1012
convertStupidCamelCaseUserdataKeys ();
1007
1013
convertMailList ();
0 commit comments