make SchematicGenerator properly lazy

This commit is contained in:
CreepyCre 2021-02-24 12:42:36 +01:00
parent b19942dfa6
commit 2146400d7e
10 changed files with 157 additions and 28 deletions

View file

@ -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;

View file

@ -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<RiftBlockEntity> placeRiftsOnly(Pocket pocket) {
public Map<BlockPos, RiftBlockEntity> 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<BlockPos, RiftBlockEntity> 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) {

View file

@ -29,7 +29,7 @@ public abstract class LazyPocketGenerator extends PocketGenerator {
public static Queue<Chunk> generationQueue = new LinkedList<>();
private List<LazyModifier> lazyModifierList = new ArrayList<>();
protected List<LazyModifier> lazyModifierList = new ArrayList<>();
public void generateChunk(LazyGenerationPocket pocket, Chunk chunk) {
lazyModifierList.forEach(modifier -> modifier.applyToChunk(pocket, chunk));

View file

@ -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<PocketGenerationParame
}
});
}
manager.getRifts().forEach(rift -> 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);
}

View file

@ -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<RiftBlockEntity> 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<BlockPos, RiftBlockEntity> absoluteRifts = template.getAbsoluteRifts(pocket);
rifts.addAll(absoluteRifts.values());
queuedRiftBlockEntities = new AbsoluteRiftBlockEntityModifier(absoluteRifts);
} else {
template.place(pocket, blockUpdate);
}

View file

@ -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<BlockPos, RiftBlockEntity> rifts;
private Map<BlockPos, CompoundTag> serializedRifts;
public AbsoluteRiftBlockEntityModifier() {
}
public AbsoluteRiftBlockEntityModifier(Map<BlockPos, RiftBlockEntity> 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<? extends Modifier> 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));
});
}
}
}

View file

@ -47,6 +47,7 @@ public interface Modifier {
ModifierType<RiftDataModifier> RIFT_DATA_MODIFIER_TYPE = register(new Identifier("dimdoors", RiftDataModifier.KEY), RiftDataModifier::new);
ModifierType<RelativeReferenceModifier> RELATIVE_REFERENCE_MODIFIER_TYPE = register(new Identifier("dimdoors", RelativeReferenceModifier.KEY), RelativeReferenceModifier::new);
ModifierType<OffsetModifier> OFFSET_MODIFIER_TYPE = register(new Identifier("dimdoors", OffsetModifier.KEY), OffsetModifier::new);
ModifierType<AbsoluteRiftBlockEntityModifier> ABSOLUTE_RIFT_BLOCK_ENTITY_MODIFIER_TYPE = register(new Identifier("dimdoors", AbsoluteRiftBlockEntityModifier.KEY), AbsoluteRiftBlockEntityModifier::new);
Modifier fromTag(CompoundTag tag);

View file

@ -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<RiftBlockEntity> getRifts() {
return rifts;
}
public boolean isPocketLazy() {
return pocket instanceof LazyGenerationPocket;
}
}

View file

@ -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<RiftBlockEntity> placeRiftsOnly(BlockPos origin, ServerWorld world) {
List<RiftBlockEntity> rifts = new ArrayList<>();
public Map<BlockPos, RiftBlockEntity> getAbsoluteRifts(BlockPos origin) {
Map<BlockPos, RiftBlockEntity> 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;

View file

@ -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<RiftBlockEntity> placeRiftsOnly(Schematic schematic, ServerWorld world, BlockPos origin) {
LOGGER.debug("Placing schematic rifts only: {}", schematic.getMetadata().getName());
public static Map<BlockPos, RiftBlockEntity> 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) {