1717import org .mvplugins .multiverse .inventories .profile .ProfileDataSource ;
1818import org .mvplugins .multiverse .inventories .profile .key .GlobalProfileKey ;
1919import org .mvplugins .multiverse .inventories .profile .key .ProfileKey ;
20- import org .mvplugins .multiverse .inventories .profile .key .ProfileType ;
2120import org .mvplugins .multiverse .inventories .profile .key .ProfileTypes ;
2221import org .mvplugins .multiverse .inventories .profile .key .ContainerType ;
2322import org .mvplugins .multiverse .inventories .profile .ProfileFilesLocator ;
24- import org .mvplugins .multiverse .inventories .util .ItemStackConverter ;
2523
2624import java .io .File ;
2725import java .nio .charset .StandardCharsets ;
2826import java .util .ArrayList ;
29- import java .util .HashMap ;
27+ import java .util .Arrays ;
3028import java .util .HashSet ;
3129import java .util .List ;
32- import java .util .Map ;
3330import java .util .Set ;
3431import java .util .UUID ;
3532import java .util .concurrent .CompletableFuture ;
@@ -62,11 +59,6 @@ final class MigrateInventorySerializationCommand extends InventoriesCommand {
6259 @ Subcommand ("bulkedit migrate inventory-serialization nbt" )
6360 @ CommandPermission ("multiverse.inventories.bulkedit" )
6461 void onNbtCommand (MVCommandIssuer issuer ) {
65- if (!ItemStackConverter .hasByteSerializeSupport ()) {
66- issuer .sendMessage ("NBT serialization is only supported on PaperMC 1.20.2 or higher!" );
67- issuer .sendMessage ("Conversion to NBT is not possible on your current server version." );
68- return ;
69- }
7062 commandQueueManager .addToQueue (CommandQueuePayload .issuer (issuer )
7163 .prompt (Message .of ("Are you sure you want to migrate all player data to NBT?" ))
7264 .action (() -> doMigration (issuer , true )));
@@ -81,35 +73,29 @@ void onBukkitCommand(MVCommandIssuer issuer) {
8173 }
8274
8375 private void doMigration (MVCommandIssuer issuer , boolean useByteSerialization ) {
84- issuer .sendMessage ("Updating config and clearing caches..." );
8576 inventoriesConfig .setUseByteSerializationForInventoryData (useByteSerialization );
8677 inventoriesConfig .save ();
87- profileCacheManager .clearAllCache ();
8878
8979 long startTime = System .nanoTime ();
9080 AtomicLong profileCounter = new AtomicLong (0 );
9181
92- Map <ContainerType , List <String >> containerNames = new HashMap <>();
93- for (ContainerType type : ContainerType .values ()) {
94- containerNames .put (type , profileDataSource .listContainerDataNames (type ));
95- }
96-
97- Set <String > playerIdentifiers = new HashSet <>();
9882 // Scan global files
83+ Set <String > fileNamesSet = new HashSet <>();
9984 profileFilesLocator .listGlobalFiles ().forEach (file ->
100- playerIdentifiers .add (Files .getNameWithoutExtension (file .getName ())));
85+ fileNamesSet .add (Files .getNameWithoutExtension (file .getName ())));
10186
10287 // Scan world and group files
10388 for (ContainerType type : ContainerType .values ()) {
10489 for (File folder : profileFilesLocator .listProfileContainerFolders (type )) {
10590 profileFilesLocator .listPlayerProfileFiles (type , folder .getName ()).forEach (file ->
106- playerIdentifiers .add (Files .getNameWithoutExtension (file .getName ())));
91+ fileNamesSet .add (Files .getNameWithoutExtension (file .getName ())));
10792 }
10893 }
10994
110- issuer .sendMessage ("Found " + playerIdentifiers .size () + " unique player identifiers to migrate." );
95+ List <String > fileNames = new ArrayList <>(fileNamesSet );
96+ issuer .sendMessage ("Found " + fileNames .size () + " unique players to migrate." );
11197
112- migrateNextPlayer (issuer , new ArrayList <>( playerIdentifiers ) , 0 , containerNames , profileCounter )
98+ migrateNextPlayer (issuer , fileNames , 0 , profileCounter )
11399 .thenRun (() -> {
114100 long timeDuration = (System .nanoTime () - startTime ) / 1000000 ;
115101 issuer .sendMessage ("Updated " + profileCounter .get () + " player profiles." );
@@ -119,76 +105,59 @@ private void doMigration(MVCommandIssuer issuer, boolean useByteSerialization) {
119105
120106 private CompletableFuture <Void > migrateNextPlayer (
121107 MVCommandIssuer issuer ,
122- List <String > playerIdentifiers ,
108+ List <String > fileNames ,
123109 int index ,
124- Map <ContainerType , List <String >> containerNames ,
125110 AtomicLong profileCounter
126111 ) {
127- if (index >= playerIdentifiers .size ()) {
112+ if (index >= fileNames .size ()) {
128113 return CompletableFuture .completedFuture (null );
129114 }
130115
131- String playerIdentifier = playerIdentifiers .get (index );
116+ String fileName = fileNames .get (index );
132117 UUID playerUUID ;
133118 try {
134- playerUUID = UUID .fromString (playerIdentifier );
119+ playerUUID = UUID .fromString (fileName );
135120 } catch (IllegalArgumentException e ) {
136- playerUUID = UUID .nameUUIDFromBytes (("OfflinePlayer:" + playerIdentifier ).getBytes (StandardCharsets .UTF_8 ));
121+ // Fall back to parsing it as an offline mode UUID
122+ playerUUID = UUID .nameUUIDFromBytes (("OfflinePlayer:" + fileName ).getBytes (StandardCharsets .UTF_8 ));
137123 }
138124
139- if (index % 50 == 0 && index > 0 ) {
125+ if (index % 100 == 0 ) {
140126 issuer .sendMessage ("Processed " + index + " players..." );
141127 }
142128
143- return profileDataSource .getGlobalProfile (GlobalProfileKey .of (playerUUID , playerIdentifier ))
144- .thenCompose (profile -> run (issuer , profile , containerNames , profileCounter ))
129+ return profileDataSource .getGlobalProfile (GlobalProfileKey .of (playerUUID , fileName ))
130+ .thenCompose (profile -> run (profile , profileCounter ))
145131 .exceptionally (throwable -> {
146- issuer .sendMessage ("Error updating player " + playerIdentifier + ": " + throwable .getMessage ());
132+ issuer .sendMessage ("Error updating player " + fileName + ": " + throwable .getMessage ());
147133 return null ;
148134 })
149- .thenCompose (v -> migrateNextPlayer (issuer , playerIdentifiers , index + 1 , containerNames , profileCounter ));
135+ .thenCompose (v -> migrateNextPlayer (issuer , fileNames , index + 1 , profileCounter ));
150136 }
151137
152- private CompletableFuture <Void > run (
153- MVCommandIssuer issuer ,
154- GlobalProfile profile ,
155- Map <ContainerType , List <String >> containerNames ,
156- AtomicLong profileCounter
157- ) {
138+ private CompletableFuture <Void > run (GlobalProfile profile , AtomicLong profileCounter ) {
158139 String playerName = profile .getLastKnownName ();
159140 if (playerName == null || playerName .isEmpty ()) {
160141 playerName = profile .getPlayerUUID ().toString ();
161142 }
162-
163- CompletableFuture <Void > future = CompletableFuture .completedFuture (null );
164- for (ContainerType containerType : ContainerType .values ()) {
165- List <String > dataNames = containerNames .get (containerType );
166- for (String dataName : dataNames ) {
167- for (ProfileType profileType : ProfileTypes .getTypes ()) {
168- ProfileKey profileKey = ProfileKey .of (
169- containerType ,
170- dataName ,
171- profileType ,
172- profile .getPlayerUUID (),
173- playerName
174- );
175- future = future .thenCompose (v -> profileDataSource .getPlayerProfile (profileKey )
176- .thenCompose (playerProfile -> {
177- if (playerProfile .getData ().isEmpty ()) {
178- return CompletableFuture .completedFuture (null );
179- }
180- profileCounter .incrementAndGet ();
181- return profileDataSource .updatePlayerProfile (playerProfile );
182- })
183- .exceptionally (throwable -> {
184- issuer .sendMessage (String .format ("Error migrating profile %s %s/%s for player %s: %s" ,
185- containerType , dataName , profileType , profile .getPlayerUUID (), throwable .getMessage ()));
186- return null ;
187- })
188- );
189- }
190- }
191- }
192- return future ;
143+ String finalPlayerName = playerName ;
144+
145+ return CompletableFuture .allOf (Arrays .stream (ContainerType .values ())
146+ .flatMap (containerType -> profileDataSource .listContainerDataNames (containerType ).stream ()
147+ .flatMap (dataName -> ProfileTypes .getTypes ().stream ()
148+ .map (profileType -> profileDataSource .getPlayerProfile (ProfileKey .of (
149+ containerType ,
150+ dataName ,
151+ profileType ,
152+ profile .getPlayerUUID (),
153+ finalPlayerName
154+ )).thenCompose (playerProfile -> {
155+ if (playerProfile .getData ().isEmpty ()) {
156+ return CompletableFuture .completedFuture (null );
157+ }
158+ profileCounter .incrementAndGet ();
159+ return profileDataSource .updatePlayerProfile (playerProfile );
160+ }))))
161+ .toArray (CompletableFuture []::new ));
193162 }
194163}
0 commit comments