This commit is contained in:
SD 2021-01-30 09:34:12 +05:30
parent f610f9039a
commit bf97807f02
No known key found for this signature in database
GPG key ID: E36B57EE08544BC5
5 changed files with 166 additions and 57 deletions

View file

@ -2,17 +2,14 @@ package org.dimdev.dimdoors.util.schematic.v2;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import io.github.boogiemonster1o1.libcbe.api.ConditionalBlockEntityProvider;
import org.jetbrains.annotations.Nullable;
import net.minecraft.block.Block;
import net.minecraft.block.BlockEntityProvider;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
@ -21,7 +18,6 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.fluid.FluidState;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.IntArrayTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.util.math.BlockPos;
@ -29,23 +25,29 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.BlockView;
import net.minecraft.world.ModifiableWorld;
import net.minecraft.world.StructureWorldAccess;
import net.minecraft.world.biome.Biome;
import net.fabricmc.fabric.api.util.NbtType;
public class RelativeBlockSample implements BlockView, ModifiableWorld {
public final Schematic schematic;
private final int[][][] blockData;
private final int[][] biomeData;
private final BiMap<BlockState, Integer> blockPalette;
private final BiMap<Biome, Integer> biomePalette;
private final Map<BlockPos, BlockState> blockContainer;
private final Map<BlockPos, Biome> biomeContainer;
private final Map<BlockPos, CompoundTag> blockEntityContainer;
private final BiMap<CompoundTag, Vec3d> entityContainer;
private StructureWorldAccess world;
public RelativeBlockSample(Schematic schematic) {
this.schematic = schematic;
this.blockData = SchematicPlacer.getBlockData(schematic);
this.biomeData = SchematicPlacer.getBiomeData(schematic);
this.blockPalette = ImmutableBiMap.copyOf(schematic.getBlockPalette());
this.biomePalette = ImmutableBiMap.copyOf(schematic.getBiomePalette());
this.blockContainer = Maps.newHashMap();
this.biomeContainer = Maps.newHashMap();
this.blockEntityContainer = Maps.newHashMap();
int width = schematic.getWidth();
int height = schematic.getHeight();
@ -54,10 +56,14 @@ public class RelativeBlockSample implements BlockView, ModifiableWorld {
for (int y = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
this.setBlockState(new BlockPos(x, y, z), this.blockPalette.inverse().get(this.blockData[x][y][z]), 2);
this.blockContainer.put(new BlockPos(x, y, z), this.blockPalette.inverse().get(this.blockData[x][y][z]));
}
}
}
for (int x = 0; x < width; x++) {
for (int z = 0; z < length; z++) {
this.biomeContainer.put(new BlockPos(x, 0, z), this.biomePalette.inverse().get(this.biomeData[x][z]));
}
}
for (CompoundTag blockEntityTag : schematic.getBlockEntities()) {
int[] arr = blockEntityTag.getIntArray("Pos");
BlockPos position = new BlockPos(arr[0], arr[1], arr[2]);
@ -73,15 +79,12 @@ public class RelativeBlockSample implements BlockView, ModifiableWorld {
@Override
public @Nullable BlockEntity getBlockEntity(BlockPos pos) {
Block block = this.getBlockState(pos).getBlock();
if (block.hasBlockEntity()) {
if (block instanceof ConditionalBlockEntityProvider && ((ConditionalBlockEntityProvider) block).hasBlockEntity(this.getBlockState(pos)) && ((ConditionalBlockEntityProvider) block).hasBlockEntity(pos, this)) {
return ((ConditionalBlockEntityProvider) block).createBlockEntity(this.world);
} else {
return ((BlockEntityProvider) block).createBlockEntity(this.world);
}
}
return null;
return Optional.of(this.getBlockState(pos))
.map(BlockState::getBlock)
.filter(BlockEntityProvider.class::isInstance)
.map(BlockEntityProvider.class::cast)
.map(bep -> bep.createBlockEntity(this))
.orElse(null);
}
@Override
@ -94,18 +97,15 @@ public class RelativeBlockSample implements BlockView, ModifiableWorld {
return this.blockContainer.get(pos).getFluidState();
}
public void place(BlockPos origin) {
if (this.world == null) {
throw new UnsupportedOperationException("Can not place in a null world!");
}
this.blockContainer.forEach((pos, state) -> this.world.setBlockState(origin.add(pos), state, 0b0000011));
public void place(BlockPos origin, StructureWorldAccess world, boolean biomes) {
this.blockContainer.forEach((pos, state) -> world.setBlockState(origin.add(pos), state, 0b0000011));
for (Map.Entry<BlockPos, CompoundTag> entry : this.blockEntityContainer.entrySet()) {
BlockPos pos = entry.getKey();
BlockPos actualPos = origin.add(entry.getKey());
BlockEntity blockEntity = BlockEntity.createFromTag(this.getBlockState(pos), entry.getValue());
if (blockEntity != null) {
this.world.toServerWorld().setBlockEntity(actualPos, blockEntity);
world.toServerWorld().setBlockEntity(actualPos, blockEntity);
}
}
for (Map.Entry<CompoundTag, Vec3d> entry : this.entityContainer.entrySet()) {
@ -116,8 +116,8 @@ public class RelativeBlockSample implements BlockView, ModifiableWorld {
doubles.set(1, NbtOps.INSTANCE.createDouble(vec.y));
doubles.set(2, NbtOps.INSTANCE.createDouble(vec.z));
tag.put("Pos", doubles);
Entity entity = EntityType.getEntityFromTag(tag, this.world.toServerWorld()).orElseThrow(NoSuchElementException::new);
this.world.spawnEntity(entity);
Entity entity = EntityType.getEntityFromTag(tag, world.toServerWorld()).orElseThrow(NoSuchElementException::new);
world.spawnEntity(entity);
}
}
@ -137,15 +137,6 @@ public class RelativeBlockSample implements BlockView, ModifiableWorld {
return this.blockEntityContainer;
}
public StructureWorldAccess getWorld() {
return this.world;
}
public RelativeBlockSample setWorld(StructureWorldAccess world) {
this.world = world;
return this;
}
@Override
public boolean setBlockState(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) {
this.blockContainer.put(pos, state);

View file

@ -2,6 +2,7 @@ package org.dimdev.dimdoors.util.schematic.v2;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@ -12,6 +13,8 @@ import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import com.google.gson.JsonObject;
import com.mojang.serialization.Codec;
import com.mojang.serialization.Dynamic;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.codecs.RecordCodecBuilder;
@ -22,25 +25,26 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.StructureWorldAccess;
import net.minecraft.world.biome.Biome;
public class Schematic {
private static final Consumer<String> PRINT_TO_STDERR = System.err::println;
public static final Codec<Schematic> CODEC = RecordCodecBuilder.create((instance) -> {
return instance.group(
Codec.INT.fieldOf("Version").forGetter(Schematic::getVersion),
Codec.INT.optionalFieldOf("Data Version", SharedConstants.getGameVersion().getWorldVersion()).forGetter(Schematic::getDataVersion),
SchematicMetadata.CODEC.optionalFieldOf("Metadata", SchematicMetadata.EMPTY).forGetter(Schematic::getMetadata),
Codec.SHORT.fieldOf("Width").forGetter(Schematic::getWidth),
Codec.SHORT.fieldOf("Height").forGetter(Schematic::getHeight),
Codec.SHORT.fieldOf("Length").forGetter(Schematic::getLength),
Vec3i.CODEC.fieldOf("Offset").forGetter(Schematic::getOffset),
Codec.INT.fieldOf("PaletteMax").forGetter(Schematic::getPaletteMax),
SchematicBlockPalette.CODEC.fieldOf("Palette").forGetter(Schematic::getBlockPalette),
Codec.BYTE_BUFFER.fieldOf("BlockData").forGetter(Schematic::getBlockData),
Codec.list(CompoundTag.CODEC).optionalFieldOf("BlockEntities", ImmutableList.of()).forGetter(Schematic::getBlockEntities),
Codec.list(CompoundTag.CODEC).optionalFieldOf("Entities", ImmutableList.of()).forGetter(Schematic::getEntities)
).apply(instance, Schematic::new);
});
public static final Codec<Schematic> CODEC = RecordCodecBuilder.create((instance) -> instance.group(
Codec.INT.fieldOf("Version").forGetter(Schematic::getVersion),
Codec.INT.optionalFieldOf("Data Version", SharedConstants.getGameVersion().getWorldVersion()).forGetter(Schematic::getDataVersion),
SchematicMetadata.CODEC.optionalFieldOf("Metadata", SchematicMetadata.EMPTY).forGetter(Schematic::getMetadata),
Codec.SHORT.fieldOf("Width").forGetter(Schematic::getWidth),
Codec.SHORT.fieldOf("Height").forGetter(Schematic::getHeight),
Codec.SHORT.fieldOf("Length").forGetter(Schematic::getLength),
Vec3i.CODEC.fieldOf("Offset").forGetter(Schematic::getOffset),
Codec.INT.fieldOf("PaletteMax").forGetter(Schematic::getPaletteMax),
SchematicBlockPalette.CODEC.fieldOf("Palette").forGetter(Schematic::getBlockPalette),
Codec.BYTE_BUFFER.fieldOf("BlockData").forGetter(Schematic::getBlockData),
Codec.list(CompoundTag.CODEC).optionalFieldOf("BlockEntities", ImmutableList.of()).forGetter(Schematic::getBlockEntities),
Codec.list(CompoundTag.CODEC).optionalFieldOf("Entities", ImmutableList.of()).forGetter(Schematic::getEntities),
SchematicBiomePalette.CODEC.optionalFieldOf("BiomePalette", Collections.emptyMap()).forGetter(Schematic::getBiomePalette),
Codec.BYTE_BUFFER.optionalFieldOf("BiomeData", ByteBuffer.wrap(new byte[0])).forGetter(Schematic::getBlockData)
).apply(instance, Schematic::new));
private final int version;
private final int dataVersion;
@ -54,8 +58,11 @@ public class Schematic {
private final ByteBuffer blockData;
private List<CompoundTag> blockEntities;
private List<CompoundTag> entities;
private final BiMap<Biome, Integer> biomePalette;
private final ByteBuffer biomeData;
private RelativeBlockSample cachedBlockSample = null;
public Schematic(int version, int dataVersion, SchematicMetadata metadata, short width, short height, short length, Vec3i offset, int paletteMax, Map<BlockState, Integer> blockPalette, ByteBuffer blockData, List<CompoundTag> blockEntities, List<CompoundTag> entities) {
public Schematic(int version, int dataVersion, SchematicMetadata metadata, short width, short height, short length, Vec3i offset, int paletteMax, Map<BlockState, Integer> blockPalette, ByteBuffer blockData, List<CompoundTag> blockEntities, List<CompoundTag> entities, Map<Biome, Integer> biomePalette, ByteBuffer biomeData) {
this.version = version;
this.dataVersion = dataVersion;
this.metadata = metadata;
@ -68,6 +75,8 @@ public class Schematic {
this.blockData = blockData;
this.blockEntities = blockEntities;
this.entities = entities;
this.biomePalette = HashBiMap.create(biomePalette);
this.biomeData = biomeData;
}
public int getVersion() {
@ -114,6 +123,14 @@ public class Schematic {
return this.blockEntities;
}
public BiMap<Biome, Integer> getBiomePalette() {
return this.biomePalette;
}
public ByteBuffer getBiomeData() {
return this.biomeData;
}
public void setBlockEntities(List<CompoundTag> blockEntities) {
this.blockEntities = blockEntities.stream().map(SchematicPlacer::fixEntityId).collect(Collectors.toList());
}
@ -135,11 +152,10 @@ public class Schematic {
}
public static RelativeBlockSample getBlockSample(Schematic schem) {
return new RelativeBlockSample(schem);
}
public static RelativeBlockSample getBlockSample(Schematic schem, StructureWorldAccess world) {
return getBlockSample(schem).setWorld(world);
if (schem.cachedBlockSample == null) {
return (schem.cachedBlockSample = new RelativeBlockSample(schem));
}
return schem.cachedBlockSample;
}
public static Schematic fromTag(CompoundTag tag) {
@ -157,4 +173,12 @@ public class Schematic {
public static JsonObject toJson(Schematic schem) {
return (JsonObject) CODEC.encodeStart(JsonOps.INSTANCE, schem).getOrThrow(false, PRINT_TO_STDERR);
}
public static <T> Schematic fromDynamic(Dynamic<T> dynamic) {
return CODEC.parse(dynamic).getOrThrow(false, PRINT_TO_STDERR);
}
public static <T> T toDynamic(Schematic schem, DynamicOps<T> ops) {
return CODEC.encodeStart(ops, schem).getOrThrow(false, PRINT_TO_STDERR);
}
}

View file

@ -0,0 +1,11 @@
package org.dimdev.dimdoors.util.schematic.v2;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.UnboundedMapCodec;
import net.minecraft.util.registry.BuiltinRegistries;
import net.minecraft.world.biome.Biome;
public class SchematicBiomePalette {
public static final UnboundedMapCodec<Biome, Integer> CODEC = Codec.unboundedMap(BuiltinRegistries.BIOME, Codec.INT);
}

View file

@ -31,8 +31,8 @@ public final class SchematicPlacer {
LOGGER.warn("Schematic \"" + schematic.getMetadata().getName() + "\" depends on mod \"" + id + "\", which is missing!");
}
}
RelativeBlockSample blockSample = Schematic.getBlockSample(schematic, world);
blockSample.place(origin);
RelativeBlockSample blockSample = Schematic.getBlockSample(schematic);
blockSample.place(origin, world, false);
}
public static int[][][] getBlockData(Schematic schematic) {
@ -51,6 +51,19 @@ public final class SchematicPlacer {
return blockData;
}
public static int[][] getBiomeData(Schematic schematic) {
int width = schematic.getWidth();
int length = schematic.getLength();
byte[] biomeDataArray = schematic.getBiomeData().array();
int[][] biomeData = new int[width][length];
for (int x = 0; x < width; x++) {
for (int z = 0; z < length; z++) {
biomeData[x][z] = biomeDataArray[x + z * width];
}
}
return biomeData;
}
private static void placeEntities(int originX, int originY, int originZ, Schematic schematic, StructureWorldAccess world) {
List<CompoundTag> entityTags = schematic.getEntities();
for (CompoundTag tag : entityTags) {

View file

@ -0,0 +1,70 @@
package org.dimdev.dimdoors.util.schematic.v2;
import java.util.function.Predicate;
import org.jetbrains.annotations.Nullable;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.Entity;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
import net.minecraft.world.Heightmap;
import net.minecraft.world.ModifiableTestableWorld;
import net.minecraft.world.StructureWorldAccess;
public class WorldlyBlockSample implements BlockView, ModifiableTestableWorld {
private final RelativeBlockSample relativeBlockSample;
private final StructureWorldAccess world;
public WorldlyBlockSample(RelativeBlockSample relativeBlockSample, StructureWorldAccess world) {
this.relativeBlockSample = relativeBlockSample;
this.world = world;
}
public void place(BlockPos origin, boolean biomes) {
this.relativeBlockSample.place(origin, this.world, biomes);
}
@Nullable
@Override
public BlockEntity getBlockEntity(BlockPos pos) {
return this.relativeBlockSample.getBlockEntity(pos);
}
@Override
public BlockState getBlockState(BlockPos pos) {
return this.relativeBlockSample.getBlockState(pos);
}
@Override
public FluidState getFluidState(BlockPos pos) {
return this.relativeBlockSample.getFluidState(pos);
}
@Override
public boolean setBlockState(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) {
return this.relativeBlockSample.setBlockState(pos, state, flags, maxUpdateDepth);
}
@Override
public boolean removeBlock(BlockPos pos, boolean move) {
return this.relativeBlockSample.removeBlock(pos, move);
}
@Override
public boolean breakBlock(BlockPos pos, boolean drop, @Nullable Entity breakingEntity, int maxUpdateDepth) {
return this.relativeBlockSample.breakBlock(pos, drop, breakingEntity, maxUpdateDepth);
}
@Override
public boolean testBlockState(BlockPos pos, Predicate<BlockState> state) {
return state.test(this.getBlockState(pos));
}
@Override
public BlockPos getTopPosition(Heightmap.Type type, BlockPos pos) {
return this.world.getTopPosition(type, pos);
}
}