added LazyCompatibleModifier

lazy schematic gen now marks placed blocks for update
This commit is contained in:
CreepyCre 2021-02-22 14:28:20 +01:00
parent d9fd741db3
commit 08e772d2cb
7 changed files with 89 additions and 21 deletions

View file

@ -7,6 +7,7 @@ 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;
import org.dimdev.dimdoors.world.level.DimensionalRegistry;
import org.dimdev.dimdoors.world.pocket.type.LazyGenerationPocket;
@ -21,6 +22,7 @@ public class ChunkLoadListener implements ServerChunkEvents.Load {
if (LazyPocketGenerator.currentlyGenerating) {
LazyPocketGenerator.generationQueue.add(chunk);
} else {
LazyCompatibleModifier.runQueuedModifications(chunk);
((LazyGenerationPocket) pocket).chunkLoaded(chunk);
}
}

View file

@ -12,6 +12,7 @@ import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.registry.Registry;
@ -29,9 +30,10 @@ import org.dimdev.dimdoors.util.PocketGenerationParameters;
import org.dimdev.dimdoors.util.TagEquations;
import org.dimdev.dimdoors.util.math.Equation;
import org.dimdev.dimdoors.util.math.Equation.EquationParseException;
import org.dimdev.dimdoors.world.pocket.type.LazyGenerationPocket;
import org.dimdev.dimdoors.world.pocket.type.Pocket;
public class DimensionalDoorModifier implements Modifier {
public class DimensionalDoorModifier implements LazyCompatibleModifier {
private static final Logger LOGGER = LogManager.getLogger();
public static final String KEY = "door";
@ -88,7 +90,7 @@ public class DimensionalDoorModifier implements Modifier {
@Override
public CompoundTag toTag(CompoundTag tag) {
Modifier.super.toTag(tag);
LazyCompatibleModifier.super.toTag(tag);
tag.putString("facing", facing.asString());
tag.putString("door_type", doorTypeString);
@ -134,11 +136,8 @@ public class DimensionalDoorModifier implements Modifier {
BlockPos pocketOrigin = manager.getPocket().getOrigin();
BlockPos pos = new BlockPos(xEquation.apply(variableMap) + pocketOrigin.getX(), yEquation.apply(variableMap) + pocketOrigin.getY(), zEquation.apply(variableMap) + pocketOrigin.getZ());
ServerWorld world = parameters.getWorld();
BlockState lower = doorType.getDefaultState().with(DimensionalDoorBlock.HALF, DoubleBlockHalf.LOWER).with(DimensionalDoorBlock.FACING, facing);
world.setBlockState(pos, lower);
world.setBlockState(pos.up(), doorType.getDefaultState().with(DimensionalDoorBlock.HALF, DoubleBlockHalf.UPPER).with(DimensionalDoorBlock.FACING, facing));
BlockState upper = doorType.getDefaultState().with(DimensionalDoorBlock.HALF, DoubleBlockHalf.UPPER).with(DimensionalDoorBlock.FACING, facing);
EntranceRiftBlockEntity rift = ModBlockEntityTypes.ENTRANCE_RIFT.instantiate(pos, lower);
if (doorData == null) {
@ -150,7 +149,24 @@ public class DimensionalDoorModifier implements Modifier {
manager.add(rift);
world.addBlockEntity(rift);
if (manager.getPocket() instanceof LazyGenerationPocket) {
// queue two separate tasks, Cubic Chunks may cause the positions to be in different chunks.
queueChunkModificationTask(new ChunkPos(pos), chunk -> {
chunk.setBlockState(pos, lower, false);
chunk.setBlockEntity(rift);
});
queueChunkModificationTask(new ChunkPos(pos.up()), chunk -> {
chunk.setBlockState(pos.up(), upper, false);
});
} else {
ServerWorld world = parameters.getWorld();
world.setBlockState(pos, lower);
world.setBlockState(pos.up(), upper);
world.addBlockEntity(rift);
}
}
@Override

View file

@ -0,0 +1,41 @@
package org.dimdev.dimdoors.pockets.modifier;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import java.util.*;
import java.util.function.Consumer;
public interface LazyCompatibleModifier extends Modifier {
LinkedHashMap<ChunkPos, Queue<Consumer<Chunk>>> chunkModificationQueue = new LinkedHashMap<>();
static void runQueuedModifications(Chunk chunk) {
Queue<Consumer<Chunk>> tasks = chunkModificationQueue.remove(chunk.getPos());
if (tasks == null) return;
Iterator<Consumer<Chunk>> iterator = tasks.iterator();
while (iterator.hasNext()) {
Consumer<Chunk> task = iterator.next();
iterator.remove();
task.accept(chunk);
}
}
static void runLeftoverModifications(World world) {
new HashSet<>(chunkModificationQueue.keySet()).forEach(chunkPos -> world.getChunk(chunkPos.getStartPos())); // seems safest for Cubic Chunks reasons;
}
default void queueChunkModificationTask(ChunkPos pos, Consumer<Chunk> task) {
chunkModificationQueue.compute(pos, ((chunkPos, chunkTaskQueue) -> {
if (chunkTaskQueue == null) chunkTaskQueue = new LinkedList<>();
chunkTaskQueue.add(task);
return chunkTaskQueue;
}));
}
@Override
default CompoundTag toTag(CompoundTag tag) {
return Modifier.super.toTag(tag);
}
}

View file

@ -52,13 +52,11 @@ public class RiftManager {
return true;
}
// TODO: should we register the rift here?
return false;
}
public boolean consume(int id, Predicate<RiftBlockEntity> consumer) {
if (map.containsKey(id) && consumer.test(map.get(id))) {
// TODO: should we register the rift here?
map.remove(id);
return true;
}

View file

@ -16,6 +16,7 @@ import org.apache.logging.log4j.Logger;
import org.dimdev.dimdoors.DimensionalDoorsInitializer;
import org.dimdev.dimdoors.pockets.generator.LazyPocketGenerator;
import org.dimdev.dimdoors.pockets.generator.PocketGenerator;
import org.dimdev.dimdoors.pockets.modifier.LazyCompatibleModifier;
import org.dimdev.dimdoors.pockets.modifier.LazyModifier;
import org.dimdev.dimdoors.pockets.modifier.Modifier;
import org.dimdev.dimdoors.pockets.modifier.RiftManager;
@ -142,7 +143,7 @@ public abstract class PocketGeneratorReference extends VirtualSingularPocket {
generator.applyModifiers(parameters, manager);
this.applyModifiers(parameters, manager);
generator.setup(pocket, manager, parameters, setupLoot != null ? setupLoot : generator.isSetupLoot());
if (pocket instanceof LazyGenerationPocket) {
if (!(generator instanceof LazyPocketGenerator)) throw new RuntimeException("pocket was instance of LazyGenerationPocket but generator was not instance of LazyPocketGenerator");
LazyGenerationPocket lazyPocket = (LazyGenerationPocket) pocket;
@ -155,21 +156,22 @@ public abstract class PocketGeneratorReference extends VirtualSingularPocket {
LazyPocketGenerator.currentlyGenerating = false;
/*
TODO: some sort of generationQueueMap where some non lazy modifications can be stored as Consumer<Chunk> so that they can be accessed by ChunkLoadListener
We want (mostly) everything to be placed during chunk load with lazy gen so that we don't experience any breakage with redstone or modded multiblocks/ cable stuff.
*/
while (!LazyPocketGenerator.generationQueue.isEmpty()) {
Chunk chunk = LazyPocketGenerator.generationQueue.remove();
LazyCompatibleModifier.runQueuedModifications(chunk);
MinecraftServer server = DimensionalDoorsInitializer.getServer();
DimensionalDoorsInitializer.getServer().send(new ServerTask(server.getTicks(), () -> (lazyPocket).chunkLoaded(chunk)));
}
LazyCompatibleModifier.runLeftoverModifications(DimensionalDoorsInitializer.getWorld(lazyPocket.getWorld()));
} else {
LazyPocketGenerator.generationQueue.clear();
LazyPocketGenerator.currentlyGenerating = false;
LazyPocketGenerator.generationQueue.clear();
}
generator.setup(pocket, manager, parameters, setupLoot != null ? setupLoot : generator.isSetupLoot());
return pocket;
}

View file

@ -7,6 +7,7 @@ import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.Maps;
import net.minecraft.block.*;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.*;
import net.minecraft.world.chunk.Chunk;
import org.dimdev.dimdoors.block.entity.RiftBlockEntity;
@ -128,7 +129,7 @@ public class RelativeBlockSample implements BlockView, ModifiableWorld {
}
}
public void place(BlockPos origin, StructureWorldAccess world, Chunk chunk, boolean biomes) {
public void place(BlockPos origin, ServerWorld world, Chunk chunk, boolean biomes) {
ChunkPos pos = chunk.getPos();
BlockBox chunkBox = BlockBox.create(pos.getStartX(), chunk.getBottomY(), pos.getStartZ(), pos.getEndX(), chunk.getTopY(), pos.getEndZ());
BlockBox schemBox = BlockBox.create(origin.getX(), origin.getY(), origin.getZ(), origin.getX() + schematic.getWidth() - 1, origin.getY() + schematic.getHeight() - 1, origin.getZ() + schematic.getLength() - 1);
@ -136,7 +137,13 @@ public class RelativeBlockSample implements BlockView, ModifiableWorld {
if (!BlockBoxUtil.isRealBox(intersection)) return;
BlockPos.stream(intersection).forEach(blockPos -> {
if(chunk.getBlockState(blockPos).isAir()) chunk.setBlockState(blockPos, this.blockContainer.get(blockPos.subtract(origin)), false);
if(chunk.getBlockState(blockPos).isAir()) {
BlockState newState = this.blockContainer.get(blockPos.subtract(origin));
if (!newState.isAir()) {
chunk.setBlockState(blockPos, newState, false);
world.getChunkManager().markForUpdate(blockPos);
}
}
});
// TODO: depending on size of blockEntityContainer it might be faster to iterate over BlockPos.stream(intersection) instead
@ -171,7 +178,7 @@ public class RelativeBlockSample implements BlockView, ModifiableWorld {
}));
}
public List<RiftBlockEntity> placeRiftsOnly(BlockPos origin, StructureWorldAccess world) {
public List<RiftBlockEntity> placeRiftsOnly(BlockPos origin, ServerWorld world) {
List<RiftBlockEntity> rifts = new ArrayList<>();
this.blockEntityContainer.forEach( (blockPos, tag) -> {
BlockPos actualPos = origin.add(blockPos);
@ -184,6 +191,7 @@ public class RelativeBlockSample implements BlockView, ModifiableWorld {
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);
}

View file

@ -4,6 +4,7 @@ import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.chunk.Chunk;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -37,7 +38,7 @@ public final class SchematicPlacer {
blockSample.place(origin, world, false);
}
public static List<RiftBlockEntity> placeRiftsOnly(Schematic schematic, StructureWorldAccess world, BlockPos origin) {
public static List<RiftBlockEntity> placeRiftsOnly(Schematic schematic, ServerWorld world, BlockPos origin) {
LOGGER.debug("Placing schematic rifts only: {}", schematic.getMetadata().getName());
for (String id : schematic.getMetadata().getRequiredMods()) {
if (!FabricLoader.getInstance().isModLoaded(id)) {
@ -48,7 +49,7 @@ public final class SchematicPlacer {
return blockSample.placeRiftsOnly(origin, world);
}
public static void place(Schematic schematic, StructureWorldAccess world, Chunk chunk, BlockPos origin) {
public static void place(Schematic schematic, ServerWorld world, Chunk chunk, BlockPos origin) {
LOGGER.debug("Placing schematic: {}", schematic.getMetadata().getName());
for (String id : schematic.getMetadata().getRequiredMods()) {
if (!FabricLoader.getInstance().isModLoaded(id)) {