From 2146400d7eac8231a7b7675d427f48c6d9d6ad70 Mon Sep 17 00:00:00 2001 From: CreepyCre Date: Wed, 24 Feb 2021 12:42:36 +0100 Subject: [PATCH] make SchematicGenerator properly lazy --- .../dimdoors/listener/ChunkLoadListener.java | 3 - .../dimdoors/pockets/PocketTemplate.java | 13 ++- .../generator/LazyPocketGenerator.java | 2 +- .../pockets/generator/PocketGenerator.java | 5 +- .../pockets/generator/SchematicGenerator.java | 17 ++- .../AbsoluteRiftBlockEntityModifier.java | 104 ++++++++++++++++++ .../dimdoors/pockets/modifier/Modifier.java | 1 + .../pockets/modifier/RiftManager.java | 5 + .../util/schematic/RelativeBlockSample.java | 27 +++-- .../util/schematic/SchematicPlacer.java | 8 +- 10 files changed, 157 insertions(+), 28 deletions(-) create mode 100644 src/main/java/org/dimdev/dimdoors/pockets/modifier/AbsoluteRiftBlockEntityModifier.java diff --git a/src/main/java/org/dimdev/dimdoors/listener/ChunkLoadListener.java b/src/main/java/org/dimdev/dimdoors/listener/ChunkLoadListener.java index 4a880c9e..442e89d1 100644 --- a/src/main/java/org/dimdev/dimdoors/listener/ChunkLoadListener.java +++ b/src/main/java/org/dimdev/dimdoors/listener/ChunkLoadListener.java @@ -1,11 +1,8 @@ package org.dimdev.dimdoors.listener; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.ServerTask; import net.minecraft.server.world.ServerWorld; import net.minecraft.world.chunk.WorldChunk; -import org.dimdev.dimdoors.DimensionalDoorsInitializer; import org.dimdev.dimdoors.pockets.generator.LazyPocketGenerator; import org.dimdev.dimdoors.pockets.modifier.LazyCompatibleModifier; import org.dimdev.dimdoors.world.ModDimensions; diff --git a/src/main/java/org/dimdev/dimdoors/pockets/PocketTemplate.java b/src/main/java/org/dimdev/dimdoors/pockets/PocketTemplate.java index 90865bb6..a1265eab 100644 --- a/src/main/java/org/dimdev/dimdoors/pockets/PocketTemplate.java +++ b/src/main/java/org/dimdev/dimdoors/pockets/PocketTemplate.java @@ -1,5 +1,7 @@ package org.dimdev.dimdoors.pockets; +import net.minecraft.block.BlockState; +import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -13,7 +15,7 @@ import org.dimdev.dimdoors.world.pocket.type.Pocket; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; -import java.util.List; +import java.util.Map; public class PocketTemplate { private static final Logger LOGGER = LogManager.getLogger(); @@ -66,11 +68,12 @@ public class PocketTemplate { SchematicPlacer.place(this.schematic, world, origin, blockUpdate); } - public List placeRiftsOnly(Pocket pocket) { + public Map getAbsoluteRifts(Pocket pocket) { pocket.setSize(schematic.getWidth(), schematic.getHeight(), schematic.getLength()); - ServerWorld world = DimensionalDoorsInitializer.getWorld(pocket.getWorld()); - BlockPos origin = pocket.getOrigin(); - return SchematicPlacer.placeRiftsOnly(this.schematic, world, origin); + Map absoluteRifts = SchematicPlacer.getAbsoluteRifts(this.schematic, pocket.getOrigin()); + World world = DimensionalDoorsInitializer.getWorld(pocket.getWorld()); + absoluteRifts.values().forEach(rift -> rift.setWorld(world)); + return absoluteRifts; } public void place(LazyGenerationPocket pocket, Chunk chunk, BlockPos originalOrigin, boolean blockUpdate) { diff --git a/src/main/java/org/dimdev/dimdoors/pockets/generator/LazyPocketGenerator.java b/src/main/java/org/dimdev/dimdoors/pockets/generator/LazyPocketGenerator.java index 1d1407a1..633f9904 100644 --- a/src/main/java/org/dimdev/dimdoors/pockets/generator/LazyPocketGenerator.java +++ b/src/main/java/org/dimdev/dimdoors/pockets/generator/LazyPocketGenerator.java @@ -29,7 +29,7 @@ public abstract class LazyPocketGenerator extends PocketGenerator { public static Queue generationQueue = new LinkedList<>(); - private List lazyModifierList = new ArrayList<>(); + protected List lazyModifierList = new ArrayList<>(); public void generateChunk(LazyGenerationPocket pocket, Chunk chunk) { lazyModifierList.forEach(modifier -> modifier.applyToChunk(pocket, chunk)); diff --git a/src/main/java/org/dimdev/dimdoors/pockets/generator/PocketGenerator.java b/src/main/java/org/dimdev/dimdoors/pockets/generator/PocketGenerator.java index 3e46fcf3..f22afaed 100644 --- a/src/main/java/org/dimdev/dimdoors/pockets/generator/PocketGenerator.java +++ b/src/main/java/org/dimdev/dimdoors/pockets/generator/PocketGenerator.java @@ -15,11 +15,8 @@ import net.minecraft.util.math.Vec3i; import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.RegistryKey; import net.minecraft.util.registry.SimpleRegistry; -import net.minecraft.world.chunk.Chunk; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.dimdev.dimdoors.DimensionalDoorsInitializer; -import org.dimdev.dimdoors.block.entity.RiftBlockEntity; import org.dimdev.dimdoors.pockets.TemplateUtils; import org.dimdev.dimdoors.pockets.modifier.Modifier; import org.dimdev.dimdoors.pockets.modifier.RiftManager; @@ -182,7 +179,7 @@ public abstract class PocketGenerator implements Weighted rift.getDestination().setLocation(new Location((ServerWorld) Objects.requireNonNull(rift.getWorld()), rift.getPos()))); + manager.getRifts().forEach(rift -> rift.getDestination().setLocation(new Location(world, rift.getPos()))); TemplateUtils.registerRifts(manager.getRifts(), parameters.getLinkTo(), parameters.getLinkProperties(), pocket); } 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 268b9565..2b4c3d49 100644 --- a/src/main/java/org/dimdev/dimdoors/pockets/generator/SchematicGenerator.java +++ b/src/main/java/org/dimdev/dimdoors/pockets/generator/SchematicGenerator.java @@ -1,6 +1,7 @@ package org.dimdev.dimdoors.pockets.generator; import net.fabricmc.fabric.api.util.NbtType; +import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Identifier; @@ -12,6 +13,7 @@ import org.apache.logging.log4j.Logger; import org.dimdev.dimdoors.block.entity.RiftBlockEntity; import org.dimdev.dimdoors.pockets.PocketLoader; import org.dimdev.dimdoors.pockets.PocketTemplate; +import org.dimdev.dimdoors.pockets.modifier.AbsoluteRiftBlockEntityModifier; import org.dimdev.dimdoors.pockets.modifier.RiftManager; import org.dimdev.dimdoors.util.PocketGenerationParameters; import org.dimdev.dimdoors.util.schematic.Schematic; @@ -43,6 +45,8 @@ public class SchematicGenerator extends LazyPocketGenerator{ private final List rifts = new ArrayList<>(); private BlockPos origin; + private AbsoluteRiftBlockEntityModifier queuedRiftBlockEntities; + public SchematicGenerator() { } @@ -106,6 +110,14 @@ public class SchematicGenerator extends LazyPocketGenerator{ return manager; } + @Override + public LazyPocketGenerator cloneWithLazyModifiers(BlockPos originalOrigin) { + LazyPocketGenerator generator = super.cloneWithLazyModifiers(originalOrigin); + generator.lazyModifierList.add(0, queuedRiftBlockEntities); + + return generator; + } + @Override public LazyPocketGenerator cloneWithEmptyModifiers(BlockPos originalOrigin) { SchematicGenerator generator = (SchematicGenerator) super.cloneWithEmptyModifiers(originalOrigin); @@ -134,7 +146,10 @@ public class SchematicGenerator extends LazyPocketGenerator{ LOGGER.info("Generating pocket from template " + templateID + " at location " + pocket.getOrigin()); if (pocket instanceof LazyGenerationPocket) { - rifts.addAll(template.placeRiftsOnly(pocket)); + Map absoluteRifts = template.getAbsoluteRifts(pocket); + rifts.addAll(absoluteRifts.values()); + + queuedRiftBlockEntities = new AbsoluteRiftBlockEntityModifier(absoluteRifts); } else { template.place(pocket, blockUpdate); } diff --git a/src/main/java/org/dimdev/dimdoors/pockets/modifier/AbsoluteRiftBlockEntityModifier.java b/src/main/java/org/dimdev/dimdoors/pockets/modifier/AbsoluteRiftBlockEntityModifier.java new file mode 100644 index 00000000..1afd8e54 --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/pockets/modifier/AbsoluteRiftBlockEntityModifier.java @@ -0,0 +1,104 @@ +package org.dimdev.dimdoors.pockets.modifier; + +import net.fabricmc.fabric.api.util.NbtType; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.util.math.BlockBox; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import org.dimdev.dimdoors.DimensionalDoorsInitializer; +import org.dimdev.dimdoors.block.entity.RiftBlockEntity; +import org.dimdev.dimdoors.util.PocketGenerationParameters; +import org.dimdev.dimdoors.world.pocket.type.LazyGenerationPocket; +import org.dimdev.dimdoors.world.pocket.type.Pocket; + +import java.util.Map; +import java.util.stream.Collectors; + +public class AbsoluteRiftBlockEntityModifier implements LazyModifier { + public static final String KEY = "block_entity"; + + private Map rifts; + private Map serializedRifts; + + public AbsoluteRiftBlockEntityModifier() { + } + + public AbsoluteRiftBlockEntityModifier(Map rifts) { + this.rifts = rifts; + + } + + @Override + public Modifier fromTag(CompoundTag tag) { + serializedRifts = tag.getList("rifts", NbtType.COMPOUND).parallelStream().unordered().map(CompoundTag.class::cast) + .collect(Collectors.toConcurrentMap(compound -> { + int[] ints = compound.getIntArray("Pos"); + return new BlockPos(ints[0], ints[1], ints[2]); + }, compound -> compound)); + + return this; + } + + @Override + public CompoundTag toTag(CompoundTag tag) { + LazyModifier.super.toTag(tag); + + ListTag riftsTag; + if (rifts != null) { + riftsTag = rifts.values().parallelStream().unordered().map(rift -> rift.toTag(new CompoundTag())).collect(Collectors.toCollection(ListTag::new)); + } else { + riftsTag = new ListTag(); + riftsTag.addAll(serializedRifts.values()); + } + tag.put("rifts", riftsTag); + + return tag; + } + + @Override + public ModifierType getType() { + return ModifierType.ABSOLUTE_RIFT_BLOCK_ENTITY_MODIFIER_TYPE; + } + + @Override + public String getKey() { + return KEY; + } + + @Override + public void apply(PocketGenerationParameters parameters, RiftManager manager) { + if (!manager.isPocketLazy()) { // rifts is guaranteed to exist at this stage since this modifier is not supposed to be loaded from json + World world = DimensionalDoorsInitializer.getWorld(manager.getPocket().getWorld()); + rifts.values().forEach(world::addBlockEntity); + } + } + + @Override + public void apply(PocketGenerationParameters parameters, Pocket.PocketBuilder builder) { + + } + + @Override + public void applyToChunk(LazyGenerationPocket pocket, Chunk chunk) { + ChunkPos chunkPos = chunk.getPos(); + BlockBox chunkBox = BlockBox.create(chunkPos.getStartX(), chunk.getBottomY(), chunkPos.getStartZ(), chunkPos.getEndX(), chunk.getTopY(), chunkPos.getEndZ()); + + if (rifts != null) { + rifts.entrySet().stream().unordered().filter(entry -> chunkBox.contains(entry.getKey())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) + .forEach((pos, rift) -> { + rifts.remove(pos); + chunk.setBlockEntity(rift); + }); + } else { + serializedRifts.entrySet().stream().unordered().filter(entry -> chunkBox.contains(entry.getKey())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)) + .forEach((pos, riftTag) -> { + rifts.remove(pos); + chunk.setBlockEntity(BlockEntity.createFromTag(pos, chunk.getBlockState(pos), riftTag)); + }); + } + } +} diff --git a/src/main/java/org/dimdev/dimdoors/pockets/modifier/Modifier.java b/src/main/java/org/dimdev/dimdoors/pockets/modifier/Modifier.java index 9f46faf6..15cdc2ab 100644 --- a/src/main/java/org/dimdev/dimdoors/pockets/modifier/Modifier.java +++ b/src/main/java/org/dimdev/dimdoors/pockets/modifier/Modifier.java @@ -47,6 +47,7 @@ public interface Modifier { ModifierType RIFT_DATA_MODIFIER_TYPE = register(new Identifier("dimdoors", RiftDataModifier.KEY), RiftDataModifier::new); ModifierType RELATIVE_REFERENCE_MODIFIER_TYPE = register(new Identifier("dimdoors", RelativeReferenceModifier.KEY), RelativeReferenceModifier::new); ModifierType OFFSET_MODIFIER_TYPE = register(new Identifier("dimdoors", OffsetModifier.KEY), OffsetModifier::new); + ModifierType ABSOLUTE_RIFT_BLOCK_ENTITY_MODIFIER_TYPE = register(new Identifier("dimdoors", AbsoluteRiftBlockEntityModifier.KEY), AbsoluteRiftBlockEntityModifier::new); Modifier fromTag(CompoundTag tag); diff --git a/src/main/java/org/dimdev/dimdoors/pockets/modifier/RiftManager.java b/src/main/java/org/dimdev/dimdoors/pockets/modifier/RiftManager.java index c9972c93..d21e3ba9 100644 --- a/src/main/java/org/dimdev/dimdoors/pockets/modifier/RiftManager.java +++ b/src/main/java/org/dimdev/dimdoors/pockets/modifier/RiftManager.java @@ -7,6 +7,7 @@ import java.util.stream.Collectors; import org.dimdev.dimdoors.block.entity.RiftBlockEntity; import org.dimdev.dimdoors.rift.targets.IdMarker; +import org.dimdev.dimdoors.world.pocket.type.LazyGenerationPocket; import org.dimdev.dimdoors.world.pocket.type.Pocket; public class RiftManager { @@ -90,4 +91,8 @@ public class RiftManager { public List getRifts() { return rifts; } + + public boolean isPocketLazy() { + return pocket instanceof LazyGenerationPocket; + } } diff --git a/src/main/schematics/org/dimdev/dimdoors/util/schematic/RelativeBlockSample.java b/src/main/schematics/org/dimdev/dimdoors/util/schematic/RelativeBlockSample.java index 76bec42b..861ad734 100644 --- a/src/main/schematics/org/dimdev/dimdoors/util/schematic/RelativeBlockSample.java +++ b/src/main/schematics/org/dimdev/dimdoors/util/schematic/RelativeBlockSample.java @@ -11,6 +11,7 @@ import net.minecraft.server.world.ServerChunkManager; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.*; import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkSection; import org.dimdev.dimdoors.block.entity.RiftBlockEntity; import org.dimdev.dimdoors.util.BlockBoxUtil; import org.jetbrains.annotations.Nullable; @@ -145,12 +146,22 @@ public class RelativeBlockSample implements BlockView, ModifiableWorld { ServerChunkManager serverChunkManager = world.getChunkManager(); + ChunkSection[] sections = chunk.getSectionArray(); BlockPos.stream(intersection).forEach(blockPos -> { - if(chunk.getBlockState(blockPos).isAir()) { + int x = Math.floorMod(blockPos.getX(), 16); + int y = Math.floorMod(blockPos.getY(), 16); + int z = Math.floorMod(blockPos.getZ(), 16); + int sectionY = chunk.getSectionIndex(blockPos.getY()); + ChunkSection section = sections[sectionY]; + if (section == null) { + section = new ChunkSection(sectionY); + sections[sectionY] = section; + } + if(section.getBlockState(x, y, z).isAir()) { BlockState newState = this.blockContainer.get(blockPos.subtract(origin)); if (!newState.isAir()) { - chunk.setBlockState(blockPos, newState, false); + section.setBlockState(x, y, z, newState, false); if (blockUpdate) serverChunkManager.markForUpdate(blockPos); } } @@ -191,8 +202,8 @@ public class RelativeBlockSample implements BlockView, ModifiableWorld { })); } - public List placeRiftsOnly(BlockPos origin, ServerWorld world) { - List rifts = new ArrayList<>(); + public Map getAbsoluteRifts(BlockPos origin) { + Map rifts = new HashMap<>(); this.blockEntityContainer.forEach( (blockPos, tag) -> { BlockPos actualPos = origin.add(blockPos); @@ -203,13 +214,7 @@ public class RelativeBlockSample implements BlockView, ModifiableWorld { BlockState state = getBlockState(blockPos); BlockEntity blockEntity = BlockEntity.createFromTag(actualPos, state, tag); if (blockEntity instanceof RiftBlockEntity) { - world.setBlockState(actualPos, state, 0); - world.getChunkManager().markForUpdate(blockPos); - if (state.getBlock() instanceof DoorBlock) { - world.setBlockState(actualPos.up(), getBlockState(blockPos.up()), 0); - } - world.toServerWorld().addBlockEntity(blockEntity); - rifts.add((RiftBlockEntity) blockEntity); + rifts.put(actualPos, (RiftBlockEntity) blockEntity); } }); return rifts; diff --git a/src/main/schematics/org/dimdev/dimdoors/util/schematic/SchematicPlacer.java b/src/main/schematics/org/dimdev/dimdoors/util/schematic/SchematicPlacer.java index a8bec282..204e49a3 100644 --- a/src/main/schematics/org/dimdev/dimdoors/util/schematic/SchematicPlacer.java +++ b/src/main/schematics/org/dimdev/dimdoors/util/schematic/SchematicPlacer.java @@ -1,9 +1,11 @@ package org.dimdev.dimdoors.util.schematic; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.stream.Stream; +import net.minecraft.block.BlockState; import net.minecraft.server.world.ServerWorld; import net.minecraft.world.chunk.Chunk; import org.apache.logging.log4j.LogManager; @@ -38,15 +40,15 @@ public final class SchematicPlacer { blockSample.place(origin, world, blockUpdate, false); } - public static List placeRiftsOnly(Schematic schematic, ServerWorld world, BlockPos origin) { - LOGGER.debug("Placing schematic rifts only: {}", schematic.getMetadata().getName()); + public static Map getAbsoluteRifts(Schematic schematic, BlockPos origin) { + LOGGER.debug("Placing schematic: {}", schematic.getMetadata().getName()); for (String id : schematic.getMetadata().getRequiredMods()) { if (!FabricLoader.getInstance().isModLoaded(id)) { LOGGER.warn("Schematic \"" + schematic.getMetadata().getName() + "\" depends on mod \"" + id + "\", which is missing!"); } } RelativeBlockSample blockSample = Schematic.getBlockSample(schematic); - return blockSample.placeRiftsOnly(origin, world); + return blockSample.getAbsoluteRifts(origin); } public static void place(Schematic schematic, ServerWorld world, Chunk chunk, BlockPos origin, boolean blockUpdate) {