From a2704a165a4f0199829c701d3d053579f1b59147 Mon Sep 17 00:00:00 2001 From: CreepyCre Date: Thu, 25 Feb 2021 20:01:24 +0100 Subject: [PATCH] RiftRegistry partial parallelization of serialization --- .../pockets/generator/SchematicGenerator.java | 4 +- .../dimdoors/rift/registry/RiftRegistry.java | 105 ++++++++++-------- 2 files changed, 60 insertions(+), 49 deletions(-) diff --git a/src/main/java/org/dimdev/dimdoors/pockets/generator/SchematicGenerator.java b/src/main/java/org/dimdev/dimdoors/pockets/generator/SchematicGenerator.java index 85ee3ca9..d001169c 100644 --- a/src/main/java/org/dimdev/dimdoors/pockets/generator/SchematicGenerator.java +++ b/src/main/java/org/dimdev/dimdoors/pockets/generator/SchematicGenerator.java @@ -40,7 +40,7 @@ public class SchematicGenerator extends LazyPocketGenerator{ private String id; private Identifier templateID; - BlockPlacementType placementType = BlockPlacementType.SECTION_NO_UPDATE; + private BlockPlacementType placementType = BlockPlacementType.SECTION_NO_UPDATE; private final List rifts = new ArrayList<>(); private BlockPos origin; @@ -84,7 +84,7 @@ public class SchematicGenerator extends LazyPocketGenerator{ int[] originInts = tag.getIntArray("origin"); this.origin = new BlockPos(originInts[0], originInts[1], originInts[2]); } - if (tag.contains("placement_type")) placementType = BlockPlacementType.getFromId(tag.getString("placement_type")); + if (tag.contains("placement_type", NbtType.STRING)) placementType = BlockPlacementType.getFromId(tag.getString("placement_type")); return this; } diff --git a/src/main/java/org/dimdev/dimdoors/rift/registry/RiftRegistry.java b/src/main/java/org/dimdev/dimdoors/rift/registry/RiftRegistry.java index f055ffe7..1adf1a3f 100644 --- a/src/main/java/org/dimdev/dimdoors/rift/registry/RiftRegistry.java +++ b/src/main/java/org/dimdev/dimdoors/rift/registry/RiftRegistry.java @@ -1,13 +1,11 @@ package org.dimdev.dimdoors.rift.registry; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; +import net.fabricmc.fabric.api.util.NbtType; +import net.minecraft.util.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.dimdev.dimdoors.util.GraphUtils; @@ -37,30 +35,31 @@ public class RiftRegistry { protected Map lastPrivatePocketExits = new HashMap<>(); // Player UUID -> last rift used to enter pocket protected Map overworldRifts = new HashMap<>(); // Player UUID -> rift used to exit the overworld - // TODO: async public static RiftRegistry fromTag(Map, PocketDirectory> pocketRegistry, CompoundTag nbt) { // Read rifts in this dimension RiftRegistry riftRegistry = new RiftRegistry(); - ListTag riftsNBT = (ListTag) nbt.get("rifts"); - for (Tag riftNBT : riftsNBT) { - Rift rift = Rift.fromTag((CompoundTag) riftNBT); + ListTag riftsNBT = nbt.getList("rifts", NbtType.COMPOUND); + CompletableFuture> futureRifts = CompletableFuture.supplyAsync(() -> riftsNBT.parallelStream().unordered().map(CompoundTag.class::cast).map(Rift::fromTag).collect(Collectors.toList())); + + ListTag pocketsNBT = nbt.getList("pockets", NbtType.COMPOUND); + CompletableFuture> futurePockets = CompletableFuture.supplyAsync(() -> pocketsNBT.stream().map(CompoundTag.class::cast).map(PocketEntrancePointer::fromTag).collect(Collectors.toList())); + + futureRifts.join().forEach(rift -> { riftRegistry.graph.addVertex(rift); riftRegistry.uuidMap.put(rift.id, rift); riftRegistry.locationMap.put(rift.location, rift); - } + }); - ListTag pocketsNBT = (ListTag) nbt.get("pockets"); - for (Tag pocketNBT : pocketsNBT) { - PocketEntrancePointer pocket = PocketEntrancePointer.fromTag((CompoundTag) pocketNBT); + futurePockets.join().forEach(pocket -> { riftRegistry.graph.addVertex(pocket); riftRegistry.uuidMap.put(pocket.id, pocket); riftRegistry.pocketEntranceMap.put(pocketRegistry.get(pocket.world).getPocket(pocket.pocketId), pocket); - } + }); // Read the connections between links that have a source or destination in this dimension - ListTag linksNBT = (ListTag) nbt.get("links"); + ListTag linksNBT = nbt.getList("links", NbtType.COMPOUND); for (Tag linkNBT : linksNBT) { RegistryVertex from = riftRegistry.uuidMap.get(((CompoundTag) linkNBT).getUuid("from")); RegistryVertex to = riftRegistry.uuidMap.get(((CompoundTag) linkNBT).getUuid("to")); @@ -70,51 +69,62 @@ public class RiftRegistry { } } - riftRegistry.lastPrivatePocketEntrances = riftRegistry.readPlayerRiftPointers((ListTag) nbt.get("lastPrivatePocketEntrances")); - riftRegistry.lastPrivatePocketExits = riftRegistry.readPlayerRiftPointers((ListTag) nbt.get("lastPrivatePocketExits")); - riftRegistry.overworldRifts = riftRegistry.readPlayerRiftPointers((ListTag) nbt.get("overworldRifts")); + riftRegistry.lastPrivatePocketEntrances = riftRegistry.readPlayerRiftPointers(nbt.getList("last_private_pocket_entrances", NbtType.COMPOUND)); + riftRegistry.lastPrivatePocketExits = riftRegistry.readPlayerRiftPointers(nbt.getList("last_private_pocket_exits", NbtType.COMPOUND)); + riftRegistry.overworldRifts = riftRegistry.readPlayerRiftPointers(nbt.getList("overworld_rifts", NbtType.COMPOUND)); return riftRegistry; } - // TODO: async public CompoundTag toTag() { CompoundTag tag = new CompoundTag(); // Write rifts in this dimension - ListTag riftsNBT = new ListTag(); - ListTag pocketsNBT = new ListTag(); - for (RegistryVertex vertex : this.graph.vertexSet()) { - CompoundTag vertexNBT = RegistryVertex.toTag(vertex); - if (vertex instanceof Rift) { - riftsNBT.add(vertexNBT); - } else if (vertex instanceof PocketEntrancePointer) { - pocketsNBT.add(vertexNBT); - } else if (!(vertex instanceof PlayerRiftPointer)) { - throw new RuntimeException("Unsupported registry vertex type " + vertex.getClass().getName()); - } - } - tag.put("rifts", riftsNBT); - tag.put("pockets", pocketsNBT); + CompletableFuture> futureRiftsAndPocketsNBT = CompletableFuture.supplyAsync(() -> { + Map> vertices = this.graph.vertexSet().parallelStream().unordered().filter(vertex -> vertex instanceof Rift || vertex instanceof PocketEntrancePointer) + .collect(Collectors.partitioningBy(Rift.class::isInstance)); + + CompletableFuture> futureRiftsNBT = CompletableFuture.supplyAsync(() -> vertices.get(true).parallelStream().map(RegistryVertex::toTag).collect(Collectors.toList())); + CompletableFuture> futurePocketsNBT = CompletableFuture.supplyAsync(() -> vertices.get(false).parallelStream().map(RegistryVertex::toTag).collect(Collectors.toList())); + + ListTag riftsNBT = new ListTag(); + ListTag pocketsNBT = new ListTag(); + + riftsNBT.addAll(futureRiftsNBT.join()); + pocketsNBT.addAll(futurePocketsNBT.join()); + + return new Pair<>(riftsNBT, pocketsNBT); + }); + // Write the connections between links that have a source or destination in this dimension - ListTag linksNBT = new ListTag(); - for (DefaultEdge edge : this.graph.edgeSet()) { - RegistryVertex from = this.graph.getEdgeSource(edge); - RegistryVertex to = this.graph.getEdgeTarget(edge); - CompoundTag linkNBT = new CompoundTag(); - linkNBT.putUuid("from", from.id); - linkNBT.putUuid("to", to.id); - linksNBT.add(linkNBT); - } - tag.put("links", linksNBT); + CompletableFuture futureLinksNBT = CompletableFuture.supplyAsync(() -> { + ListTag linksNBT = new ListTag(); + for (DefaultEdge edge : this.graph.edgeSet()) { + RegistryVertex from = this.graph.getEdgeSource(edge); + RegistryVertex to = this.graph.getEdgeTarget(edge); + CompoundTag linkNBT = new CompoundTag(); + linkNBT.putUuid("from", from.id); + linkNBT.putUuid("to", to.id); + linksNBT.add(linkNBT); + } + return linksNBT; + }); + // Subregistries are written automatically when the worlds are saved. - tag.put("lastPrivatePocketEntrances", this.writePlayerRiftPointers(this.lastPrivatePocketEntrances)); - tag.put("lastPrivatePocketExits", this.writePlayerRiftPointers(this.lastPrivatePocketExits)); - tag.put("overworldRifts", this.writePlayerRiftPointers(this.overworldRifts)); + tag.put("last_private_pocket_entrances", this.writePlayerRiftPointers(this.lastPrivatePocketEntrances)); + tag.put("last_private_pocket_exits", this.writePlayerRiftPointers(this.lastPrivatePocketExits)); + tag.put("overworld_rifts", this.writePlayerRiftPointers(this.overworldRifts)); + + Pair riftsAndPocketsNBT = futureRiftsAndPocketsNBT.join(); + tag.put("rifts", riftsAndPocketsNBT.getLeft()); + tag.put("pockets", riftsAndPocketsNBT.getRight()); + + tag.put("links", futureLinksNBT.join()); return tag; } + // TODO: parallelization private Map readPlayerRiftPointers(ListTag tag) { Map pointerMap = new HashMap<>(); for (Tag entryNBT : tag) { @@ -129,6 +139,7 @@ public class RiftRegistry { return pointerMap; } + // TODO: parallelization private ListTag writePlayerRiftPointers(Map playerRiftPointerMap) { ListTag pointers = new ListTag(); for (Map.Entry entry : playerRiftPointerMap.entrySet()) {