Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-07 20:10:06 +01:00
Fix //snapshot in 1.18 and re-implement biome/entity restoration (#1620)
* Re-add "//snap" and "//snapshot" * Place code in correct method * Use CompoundBinaryTags in AnvilChunk18 and implement biome/entity restoration * Address comments * Fix biome reading * Fix retrieval of entities from zipped snapshot world Co-authored-by: Alex <mc.cache@web.de>
Dieser Commit ist enthalten in:
Ursprung
49d5183685
Commit
fc2662e51e
@ -8,6 +8,7 @@ import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
|||||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||||
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
@ -367,8 +368,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
|
|||||||
readEntityIntoTag(mcEntity, minecraftTag);
|
readEntityIntoTag(mcEntity, minecraftTag);
|
||||||
//add Id for AbstractChangeSet to work
|
//add Id for AbstractChangeSet to work
|
||||||
final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag);
|
final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag);
|
||||||
final Map<String, BinaryTag> tags = new HashMap<>();
|
final Map<String, BinaryTag> tags = NbtUtils.getCompoundBinaryTagValues(tag);
|
||||||
tag.keySet().forEach(key -> tags.put(key, tag.get(key)));
|
|
||||||
tags.put("Id", StringBinaryTag.of(id));
|
tags.put("Id", StringBinaryTag.of(id));
|
||||||
return CompoundBinaryTag.from(tags);
|
return CompoundBinaryTag.from(tags);
|
||||||
};
|
};
|
||||||
|
@ -8,6 +8,7 @@ import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
|||||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||||
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
@ -359,8 +360,7 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
|
|||||||
readEntityIntoTag(mcEntity, minecraftTag);
|
readEntityIntoTag(mcEntity, minecraftTag);
|
||||||
//add Id for AbstractChangeSet to work
|
//add Id for AbstractChangeSet to work
|
||||||
final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag);
|
final CompoundBinaryTag tag = (CompoundBinaryTag) toNativeBinary(minecraftTag);
|
||||||
final Map<String, BinaryTag> tags = new HashMap<>();
|
final Map<String, BinaryTag> tags = NbtUtils.getCompoundBinaryTagValues(tag);
|
||||||
tag.keySet().forEach(key -> tags.put(key, tag.get(key)));
|
|
||||||
tags.put("Id", StringBinaryTag.of(id));
|
tags.put("Id", StringBinaryTag.of(id));
|
||||||
return CompoundBinaryTag.from(tags);
|
return CompoundBinaryTag.from(tags);
|
||||||
};
|
};
|
||||||
|
@ -2,9 +2,16 @@ package com.fastasyncworldedit.core.util;
|
|||||||
|
|
||||||
import com.sk89q.worldedit.util.nbt.BinaryTag;
|
import com.sk89q.worldedit.util.nbt.BinaryTag;
|
||||||
import com.sk89q.worldedit.util.nbt.BinaryTagType;
|
import com.sk89q.worldedit.util.nbt.BinaryTagType;
|
||||||
|
import com.sk89q.worldedit.util.nbt.BinaryTagTypes;
|
||||||
|
import com.sk89q.worldedit.util.nbt.ByteBinaryTag;
|
||||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||||
|
import com.sk89q.worldedit.util.nbt.IntBinaryTag;
|
||||||
|
import com.sk89q.worldedit.util.nbt.ShortBinaryTag;
|
||||||
import com.sk89q.worldedit.world.storage.InvalidFormatException;
|
import com.sk89q.worldedit.world.storage.InvalidFormatException;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class NbtUtils {
|
public class NbtUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,4 +39,45 @@ public class NbtUtils {
|
|||||||
return childTagCast;
|
return childTagCast;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an integer from a tag.
|
||||||
|
*
|
||||||
|
* @param tag the tag to read from
|
||||||
|
* @param key the key to look for
|
||||||
|
* @return child tag
|
||||||
|
* @throws InvalidFormatException if the format of the items is invalid
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
public static int getInt(CompoundBinaryTag tag, String key) throws InvalidFormatException {
|
||||||
|
BinaryTag childTag = tag.get(key);
|
||||||
|
if (childTag == null) {
|
||||||
|
throw new InvalidFormatException("Missing a \"" + key + "\" tag");
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryTagType<?> type = childTag.type();
|
||||||
|
if (type == BinaryTagTypes.INT) {
|
||||||
|
return ((IntBinaryTag) childTag).intValue();
|
||||||
|
}
|
||||||
|
if (type == BinaryTagTypes.BYTE) {
|
||||||
|
return ((ByteBinaryTag) childTag).intValue();
|
||||||
|
}
|
||||||
|
if (type == BinaryTagTypes.SHORT) {
|
||||||
|
return ((ShortBinaryTag) childTag).intValue();
|
||||||
|
}
|
||||||
|
throw new InvalidFormatException(key + " tag is not of int, short or byte tag type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a mutable map of the values stored inside a {@link CompoundBinaryTag}
|
||||||
|
*
|
||||||
|
* @param tag {@link CompoundBinaryTag} to get values for
|
||||||
|
* @return Mutable map of values
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
public static Map<String, BinaryTag> getCompoundBinaryTagValues(CompoundBinaryTag tag) {
|
||||||
|
Map<String, BinaryTag> value = new HashMap<>();
|
||||||
|
tag.forEach((e) -> value.put(e.getKey(), e.getValue()));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
package com.sk89q.worldedit.extension.factory.parser;
|
package com.sk89q.worldedit.extension.factory.parser;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.configuration.Caption;
|
import com.fastasyncworldedit.core.configuration.Caption;
|
||||||
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
import com.sk89q.worldedit.blocks.BaseItem;
|
import com.sk89q.worldedit.blocks.BaseItem;
|
||||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||||
@ -132,9 +133,7 @@ public class DefaultItemParser extends InputParser<BaseItem> {
|
|||||||
if (itemNbtData == null) {
|
if (itemNbtData == null) {
|
||||||
itemNbtData = otherTag;
|
itemNbtData = otherTag;
|
||||||
} else {
|
} else {
|
||||||
for (String key : otherTag.keySet()) {
|
itemNbtData.put(NbtUtils.getCompoundBinaryTagValues(otherTag));
|
||||||
itemNbtData.put(key, otherTag.get(key));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new NoMatchException(TranslatableComponent.of(
|
throw new NoMatchException(TranslatableComponent.of(
|
||||||
|
@ -467,7 +467,9 @@ public final class PlatformCommandManager {
|
|||||||
);
|
);
|
||||||
registerSubCommands(
|
registerSubCommands(
|
||||||
"snapshot",
|
"snapshot",
|
||||||
ImmutableList.of("snap"),
|
//FAWE start - add "/" aliases as well
|
||||||
|
ImmutableList.of("snap", "/snapshot", "/snap"),
|
||||||
|
//FAWE end
|
||||||
"Snapshot commands for restoring backups",
|
"Snapshot commands for restoring backups",
|
||||||
SnapshotCommandsRegistration.builder(),
|
SnapshotCommandsRegistration.builder(),
|
||||||
new SnapshotCommands(worldEdit)
|
new SnapshotCommands(worldEdit)
|
||||||
|
@ -31,9 +31,7 @@ import com.sk89q.worldedit.world.biome.BiomeTypes;
|
|||||||
/**
|
/**
|
||||||
* The chunk format for Minecraft 1.15 and newer
|
* The chunk format for Minecraft 1.15 and newer
|
||||||
*/
|
*/
|
||||||
//FAWE start - biome and entity restore
|
|
||||||
public class AnvilChunk15 extends AnvilChunk13 {
|
public class AnvilChunk15 extends AnvilChunk13 {
|
||||||
//FAWE end
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct the chunk with a compound tag.
|
* Construct the chunk with a compound tag.
|
||||||
|
@ -95,7 +95,7 @@ public class AnvilChunk17 implements Chunk {
|
|||||||
|
|
||||||
blocks = new BlockState[16][]; // initialise with default length
|
blocks = new BlockState[16][]; // initialise with default length
|
||||||
|
|
||||||
ListBinaryTag sections = NbtUtils.getChildTag(rootTag, "Sections", BinaryTagTypes.LIST);
|
ListBinaryTag sections = rootTag.getList("Sections");
|
||||||
|
|
||||||
for (BinaryTag rawSectionTag : sections) {
|
for (BinaryTag rawSectionTag : sections) {
|
||||||
if (!(rawSectionTag instanceof CompoundBinaryTag)) {
|
if (!(rawSectionTag instanceof CompoundBinaryTag)) {
|
||||||
@ -107,7 +107,7 @@ public class AnvilChunk17 implements Chunk {
|
|||||||
continue; // Empty section.
|
continue; // Empty section.
|
||||||
}
|
}
|
||||||
|
|
||||||
int y = NbtUtils.getChildTag(sectionTag, "Y", BinaryTagTypes.BYTE).value();
|
int y = NbtUtils.getInt(tag, "Y");
|
||||||
updateSectionIndexRange(y);
|
updateSectionIndexRange(y);
|
||||||
|
|
||||||
// parse palette
|
// parse palette
|
||||||
@ -143,7 +143,7 @@ public class AnvilChunk17 implements Chunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse block states
|
// parse block states
|
||||||
long[] blockStatesSerialized = NbtUtils.getChildTag(sectionTag, "BlockStates", BinaryTagTypes.LONG_ARRAY).value();
|
long[] blockStatesSerialized = sectionTag.getLongArray("BlockStates");
|
||||||
|
|
||||||
BlockState[] chunkSectionBlocks = new BlockState[4096];
|
BlockState[] chunkSectionBlocks = new BlockState[4096];
|
||||||
blocks[y - minSectionPosition] = chunkSectionBlocks;
|
blocks[y - minSectionPosition] = chunkSectionBlocks;
|
||||||
@ -197,7 +197,7 @@ public class AnvilChunk17 implements Chunk {
|
|||||||
if (rootTag.get("TileEntities") == null) {
|
if (rootTag.get("TileEntities") == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ListBinaryTag tags = NbtUtils.getChildTag(rootTag, "TileEntities", BinaryTagTypes.LIST);
|
ListBinaryTag tags = rootTag.getList("TileEntities");
|
||||||
|
|
||||||
for (BinaryTag tag : tags) {
|
for (BinaryTag tag : tags) {
|
||||||
if (!(tag instanceof CompoundBinaryTag)) {
|
if (!(tag instanceof CompoundBinaryTag)) {
|
||||||
@ -274,7 +274,7 @@ public class AnvilChunk17 implements Chunk {
|
|||||||
if (rootTag.get("Biomes") == null) {
|
if (rootTag.get("Biomes") == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int[] stored = NbtUtils.getChildTag(rootTag, "Biomes", BinaryTagTypes.INT_ARRAY).value();
|
int[] stored = rootTag.getIntArray("Biomes");
|
||||||
for (int i = 0; i < 1024; i++) {
|
for (int i = 0; i < 1024; i++) {
|
||||||
biomes[i] = BiomeTypes.getLegacy(stored[i]);
|
biomes[i] = BiomeTypes.getLegacy(stored[i]);
|
||||||
}
|
}
|
||||||
@ -297,7 +297,7 @@ public class AnvilChunk17 implements Chunk {
|
|||||||
if (entityTagSupplier == null || (entityTag = entityTagSupplier.get()) == null) {
|
if (entityTagSupplier == null || (entityTag = entityTagSupplier.get()) == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ListBinaryTag tags = NbtUtils.getChildTag(entityTag, "Entities", BinaryTagTypes.LIST);
|
ListBinaryTag tags = entityTag.getList("Entities");
|
||||||
|
|
||||||
for (BinaryTag tag : tags) {
|
for (BinaryTag tag : tags) {
|
||||||
if (!(tag instanceof CompoundBinaryTag)) {
|
if (!(tag instanceof CompoundBinaryTag)) {
|
||||||
|
@ -19,91 +19,134 @@
|
|||||||
|
|
||||||
package com.sk89q.worldedit.world.chunk;
|
package com.sk89q.worldedit.world.chunk;
|
||||||
|
|
||||||
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.jnbt.IntTag;
|
import com.sk89q.worldedit.entity.BaseEntity;
|
||||||
import com.sk89q.jnbt.ListTag;
|
|
||||||
import com.sk89q.jnbt.LongArrayTag;
|
|
||||||
import com.sk89q.jnbt.NBTUtils;
|
|
||||||
import com.sk89q.jnbt.Tag;
|
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.registry.state.Property;
|
import com.sk89q.worldedit.registry.state.Property;
|
||||||
|
import com.sk89q.worldedit.util.concurrency.LazyReference;
|
||||||
|
import com.sk89q.worldedit.util.nbt.BinaryTag;
|
||||||
|
import com.sk89q.worldedit.util.nbt.BinaryTagTypes;
|
||||||
|
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||||
|
import com.sk89q.worldedit.util.nbt.ListBinaryTag;
|
||||||
import com.sk89q.worldedit.world.DataException;
|
import com.sk89q.worldedit.world.DataException;
|
||||||
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
import com.sk89q.worldedit.world.block.BlockType;
|
import com.sk89q.worldedit.world.block.BlockType;
|
||||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||||
|
import com.sk89q.worldedit.world.entity.EntityTypes;
|
||||||
import com.sk89q.worldedit.world.storage.InvalidFormatException;
|
import com.sk89q.worldedit.world.storage.InvalidFormatException;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The chunk format for Minecraft 1.18 and newer
|
* The chunk format for Minecraft 1.18 and newer
|
||||||
*/
|
*/
|
||||||
public class AnvilChunk18 implements Chunk {
|
public class AnvilChunk18 implements Chunk {
|
||||||
|
|
||||||
private final CompoundTag rootTag;
|
//FAWE start - CBT
|
||||||
|
private final CompoundBinaryTag rootTag;
|
||||||
|
//FAWE end
|
||||||
private final Int2ObjectOpenHashMap<BlockState[]> blocks;
|
private final Int2ObjectOpenHashMap<BlockState[]> blocks;
|
||||||
private final int rootX;
|
//FAWE start - entity and biome restore
|
||||||
private final int rootZ;
|
private final int sectionCount;
|
||||||
|
private final Supplier<CompoundBinaryTag> entityTagSupplier;
|
||||||
|
private Int2ObjectOpenHashMap<BiomeType[]> biomes = null;
|
||||||
|
private List<BaseEntity> entities;
|
||||||
|
private Map<BlockVector3, CompoundBinaryTag> tileEntities;
|
||||||
|
//FAWE end
|
||||||
|
|
||||||
private Map<BlockVector3, Map<String, Tag>> tileEntities;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct the chunk with a compound tag.
|
* Construct the chunk with a compound tag.
|
||||||
*
|
*
|
||||||
* @param tag the tag to read
|
* @param tag the tag to read
|
||||||
* @throws DataException on a data error
|
* @throws DataException on a data error
|
||||||
|
* @deprecated Use {@link AnvilChunk18#AnvilChunk18(CompoundBinaryTag, Supplier)}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public AnvilChunk18(CompoundTag tag) throws DataException {
|
public AnvilChunk18(CompoundTag tag) throws DataException {
|
||||||
|
//FAWE start - CBT
|
||||||
|
this(tag.asBinaryTag(), () -> null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct the chunk with a compound tag.
|
||||||
|
*
|
||||||
|
* @param tag the tag to read
|
||||||
|
* @throws DataException on a data error
|
||||||
|
* @deprecated Use {@link AnvilChunk18#AnvilChunk18(CompoundBinaryTag, Supplier)}
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public AnvilChunk18(CompoundTag tag, Supplier<CompoundTag> entitiesTag) throws DataException {
|
||||||
|
//FAWE start - CBT
|
||||||
|
this(tag.asBinaryTag(), () -> {
|
||||||
|
CompoundTag compoundTag = entitiesTag.get();
|
||||||
|
return compoundTag == null ? null : compoundTag.asBinaryTag();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct the chunk with a compound tag.
|
||||||
|
*
|
||||||
|
* @param tag the tag to read
|
||||||
|
* @throws DataException on a data error
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
public AnvilChunk18(CompoundBinaryTag tag, Supplier<CompoundBinaryTag> entityTag) throws DataException {
|
||||||
|
//FAWE end
|
||||||
rootTag = tag;
|
rootTag = tag;
|
||||||
|
entityTagSupplier = entityTag;
|
||||||
|
|
||||||
rootX = NBTUtils.getChildTag(rootTag.getValue(), "xPos", IntTag.class).getValue();
|
//FAWE start - CBT
|
||||||
rootZ = NBTUtils.getChildTag(rootTag.getValue(), "zPos", IntTag.class).getValue();
|
ListBinaryTag sections = rootTag.getList("sections");
|
||||||
|
this.sectionCount = sections.size();
|
||||||
|
|
||||||
List<Tag> sections = NBTUtils.getChildTag(rootTag.getValue(), "sections", ListTag.class).getValue();
|
|
||||||
blocks = new Int2ObjectOpenHashMap<>(sections.size());
|
blocks = new Int2ObjectOpenHashMap<>(sections.size());
|
||||||
|
|
||||||
for (Tag rawSectionTag : sections) {
|
for (BinaryTag rawSectionTag : sections) {
|
||||||
if (!(rawSectionTag instanceof CompoundTag sectionTag)) {
|
if (!(rawSectionTag instanceof CompoundBinaryTag sectionTag)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object yValue = sectionTag.getValue().get("Y").getValue(); // sometimes a byte, sometimes an int
|
int y = NbtUtils.getInt(sectionTag, "Y"); // sometimes a byte, sometimes an int
|
||||||
if (!(yValue instanceof Number)) {
|
|
||||||
throw new InvalidFormatException("Y is not numeric: " + yValue);
|
|
||||||
}
|
|
||||||
int y = ((Number) yValue).intValue();
|
|
||||||
|
|
||||||
Tag rawBlockStatesTag = sectionTag.getValue().get("block_states"); // null for sections outside of the world limits
|
BinaryTag rawBlockStatesTag = sectionTag.get("block_states"); // null for sections outside of the world limits
|
||||||
if (rawBlockStatesTag instanceof CompoundTag blockStatesTag) {
|
if (rawBlockStatesTag instanceof CompoundBinaryTag blockStatesTag) {
|
||||||
|
|
||||||
// parse palette
|
// parse palette
|
||||||
List<CompoundTag> paletteEntries = blockStatesTag.getList("palette", CompoundTag.class);
|
ListBinaryTag paletteEntries = blockStatesTag.getList("palette");
|
||||||
int paletteSize = paletteEntries.size();
|
int paletteSize = paletteEntries.size();
|
||||||
if (paletteSize == 0) {
|
if (paletteSize == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BlockState[] palette = new BlockState[paletteSize];
|
BlockState[] palette = new BlockState[paletteSize];
|
||||||
for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) {
|
for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) {
|
||||||
CompoundTag paletteEntry = paletteEntries.get(paletteEntryId);
|
CompoundBinaryTag paletteEntry = (CompoundBinaryTag) paletteEntries.get(paletteEntryId);
|
||||||
BlockType type = BlockTypes.get(paletteEntry.getString("Name"));
|
BlockType type = BlockTypes.get(paletteEntry.getString("Name"));
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
throw new InvalidFormatException("Invalid block type: " + paletteEntry.getString("Name"));
|
throw new InvalidFormatException("Invalid block type: " + paletteEntry.getString("Name"));
|
||||||
}
|
}
|
||||||
BlockState blockState = type.getDefaultState();
|
BlockState blockState = type.getDefaultState();
|
||||||
if (paletteEntry.containsKey("Properties")) {
|
BinaryTag propertiesTag = paletteEntry.get("Properties");
|
||||||
CompoundTag properties = NBTUtils.getChildTag(paletteEntry.getValue(), "Properties", CompoundTag.class);
|
if (propertiesTag instanceof CompoundBinaryTag properties) {
|
||||||
for (Property<?> property : blockState.getStates().keySet()) {
|
for (Property<?> property : blockState.getStates().keySet()) {
|
||||||
if (properties.containsKey(property.getName())) {
|
String value;
|
||||||
String value = properties.getString(property.getName());
|
if (!(value = properties.getString(property.getName())).isEmpty()) {
|
||||||
try {
|
try {
|
||||||
blockState = getBlockStateWith(blockState, property, value);
|
blockState = getBlockStateWith(blockState, property, value);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new InvalidFormatException("Invalid block state for " + blockState.getBlockType().getId() + ", " + property.getName() + ": " + value);
|
throw new InvalidFormatException("Invalid block state for " + blockState
|
||||||
|
.getBlockType()
|
||||||
|
.getId() + ", " + property.getName() + ": " + value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,7 +160,7 @@ public class AnvilChunk18 implements Chunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse block states
|
// parse block states
|
||||||
long[] blockStatesSerialized = NBTUtils.getChildTag(blockStatesTag.getValue(), "data", LongArrayTag.class).getValue();
|
long[] blockStatesSerialized = blockStatesTag.getLongArray("data");
|
||||||
|
|
||||||
BlockState[] chunkSectionBlocks = new BlockState[16 * 16 * 16];
|
BlockState[] chunkSectionBlocks = new BlockState[16 * 16 * 16];
|
||||||
blocks.put(y, chunkSectionBlocks);
|
blocks.put(y, chunkSectionBlocks);
|
||||||
@ -125,6 +168,7 @@ public class AnvilChunk18 implements Chunk {
|
|||||||
readBlockStates(palette, blockStatesSerialized, chunkSectionBlocks);
|
readBlockStates(palette, blockStatesSerialized, chunkSectionBlocks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//FAWE end
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialized, BlockState[] chunkSectionBlocks) throws InvalidFormatException {
|
protected void readBlockStates(BlockState[] palette, long[] blockStatesSerialized, BlockState[] chunkSectionBlocks) throws InvalidFormatException {
|
||||||
@ -146,26 +190,24 @@ public class AnvilChunk18 implements Chunk {
|
|||||||
* Used to load the tile entities.
|
* Used to load the tile entities.
|
||||||
*/
|
*/
|
||||||
private void populateTileEntities() throws DataException {
|
private void populateTileEntities() throws DataException {
|
||||||
|
//FAWE start - CBT
|
||||||
tileEntities = new HashMap<>();
|
tileEntities = new HashMap<>();
|
||||||
if (!rootTag.getValue().containsKey("block_entities")) {
|
if (!(rootTag.get("block_entities") instanceof ListBinaryTag tags)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<Tag> tags = NBTUtils.getChildTag(rootTag.getValue(),
|
for (BinaryTag tag : tags) {
|
||||||
"block_entities", ListTag.class).getValue();
|
if (!(tag instanceof CompoundBinaryTag t)) {
|
||||||
|
|
||||||
for (Tag tag : tags) {
|
|
||||||
if (!(tag instanceof CompoundTag t)) {
|
|
||||||
throw new InvalidFormatException("CompoundTag expected in block_entities");
|
throw new InvalidFormatException("CompoundTag expected in block_entities");
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Tag> values = new HashMap<>(t.getValue());
|
int x = t.getInt("x");
|
||||||
int x = ((IntTag) values.get("x")).getValue();
|
int y = t.getInt("y");
|
||||||
int y = ((IntTag) values.get("y")).getValue();
|
int z = t.getInt("z");
|
||||||
int z = ((IntTag) values.get("z")).getValue();
|
|
||||||
|
|
||||||
BlockVector3 vec = BlockVector3.at(x, y, z);
|
BlockVector3 vec = BlockVector3.at(x, y, z);
|
||||||
tileEntities.put(vec, values);
|
tileEntities.put(vec, t);
|
||||||
}
|
}
|
||||||
|
//FAWE end
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,24 +220,21 @@ public class AnvilChunk18 implements Chunk {
|
|||||||
* @throws DataException thrown if there is a data error
|
* @throws DataException thrown if there is a data error
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private CompoundTag getBlockTileEntity(BlockVector3 position) throws DataException {
|
private CompoundBinaryTag getBlockTileEntity(BlockVector3 position) throws DataException {
|
||||||
|
//FAWE start - CBT
|
||||||
if (tileEntities == null) {
|
if (tileEntities == null) {
|
||||||
populateTileEntities();
|
populateTileEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Tag> values = tileEntities.get(position);
|
return tileEntities.get(position);
|
||||||
if (values == null) {
|
//FAWE end
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CompoundTag(values);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseBlock getBlock(BlockVector3 position) throws DataException {
|
public BaseBlock getBlock(BlockVector3 position) throws DataException {
|
||||||
int x = position.getX() - rootX * 16;
|
int x = position.getX() & 15;
|
||||||
int y = position.getY();
|
int y = position.getY();
|
||||||
int z = position.getZ() - rootZ * 16;
|
int z = position.getZ() & 15;
|
||||||
|
|
||||||
int section = y >> 4;
|
int section = y >> 4;
|
||||||
int yIndex = y & 0x0F;
|
int yIndex = y & 0x0F;
|
||||||
@ -206,7 +245,7 @@ public class AnvilChunk18 implements Chunk {
|
|||||||
}
|
}
|
||||||
BlockState state = sectionBlocks[sectionBlocks.length == 1 ? 0 : ((yIndex << 8) | (z << 4) | x)];
|
BlockState state = sectionBlocks[sectionBlocks.length == 1 ? 0 : ((yIndex << 8) | (z << 4) | x)];
|
||||||
|
|
||||||
CompoundTag tileEntity = getBlockTileEntity(position);
|
CompoundBinaryTag tileEntity = getBlockTileEntity(position);
|
||||||
|
|
||||||
if (tileEntity != null) {
|
if (tileEntity != null) {
|
||||||
return state.toBaseBlock(tileEntity);
|
return state.toBaseBlock(tileEntity);
|
||||||
@ -215,4 +254,110 @@ public class AnvilChunk18 implements Chunk {
|
|||||||
return state.toBaseBlock();
|
return state.toBaseBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BiomeType getBiome(final BlockVector3 position) throws DataException {
|
||||||
|
if (biomes == null) {
|
||||||
|
populateBiomes();
|
||||||
|
}
|
||||||
|
int x = (position.getX() & 15) >> 2;
|
||||||
|
int y = (position.getY() & 15) >> 2;
|
||||||
|
int z = (position.getZ() & 15) >> 2;
|
||||||
|
int section = position.getY() >> 4;
|
||||||
|
BiomeType[] sectionBiomes = biomes.get(section);
|
||||||
|
if (sectionBiomes.length == 1) {
|
||||||
|
return sectionBiomes[0];
|
||||||
|
}
|
||||||
|
return biomes.get(section)[y << 4 | z << 2 | x];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateBiomes() throws DataException {
|
||||||
|
biomes = new Int2ObjectOpenHashMap<>(sectionCount);
|
||||||
|
ListBinaryTag sections = rootTag.getList("sections");
|
||||||
|
for (BinaryTag rawSectionTag : sections) {
|
||||||
|
if (!(rawSectionTag instanceof CompoundBinaryTag sectionTag)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int y = NbtUtils.getInt(sectionTag, "Y"); // sometimes a byte, sometimes an int
|
||||||
|
|
||||||
|
BinaryTag rawBlockStatesTag = sectionTag.get("biomes"); // null for sections outside of the world limits
|
||||||
|
if (rawBlockStatesTag instanceof CompoundBinaryTag biomeTypesTag) {
|
||||||
|
|
||||||
|
// parse palette
|
||||||
|
ListBinaryTag paletteEntries = biomeTypesTag.getList("palette");
|
||||||
|
int paletteSize = paletteEntries.size();
|
||||||
|
if (paletteSize == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BiomeType[] palette = new BiomeType[paletteSize];
|
||||||
|
for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) {
|
||||||
|
String paletteEntry = paletteEntries.getString(paletteEntryId);
|
||||||
|
BiomeType type = BiomeType.REGISTRY.get(paletteEntry);
|
||||||
|
if (type == null) {
|
||||||
|
throw new InvalidFormatException("Invalid biome type: " + paletteEntry);
|
||||||
|
}
|
||||||
|
palette[paletteEntryId] = type;
|
||||||
|
}
|
||||||
|
if (paletteSize == 1) {
|
||||||
|
// the same block everywhere
|
||||||
|
biomes.put(y, palette);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse block states
|
||||||
|
long[] biomesSerialized = biomeTypesTag.getLongArray("data");
|
||||||
|
if (biomesSerialized.length == 0) {
|
||||||
|
throw new InvalidFormatException("Biome data not present.");
|
||||||
|
}
|
||||||
|
|
||||||
|
BiomeType[] chunkSectionBiomes = new BiomeType[64];
|
||||||
|
biomes.put(y, chunkSectionBiomes);
|
||||||
|
|
||||||
|
readBiomes(palette, biomesSerialized, chunkSectionBiomes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void readBiomes(BiomeType[] palette, long[] biomesSerialized, BiomeType[] chunkSectionBiomes) throws
|
||||||
|
InvalidFormatException {
|
||||||
|
PackedIntArrayReader reader = new PackedIntArrayReader(biomesSerialized, 64);
|
||||||
|
for (int biomePos = 0; biomePos < chunkSectionBiomes.length; biomePos++) {
|
||||||
|
int index = reader.get(biomePos);
|
||||||
|
if (index >= palette.length) {
|
||||||
|
throw new InvalidFormatException("Invalid biome table entry: " + index);
|
||||||
|
}
|
||||||
|
chunkSectionBiomes[biomePos] = palette[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BaseEntity> getEntities() throws DataException {
|
||||||
|
if (entities == null) {
|
||||||
|
populateEntities();
|
||||||
|
}
|
||||||
|
return entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to load the biomes.
|
||||||
|
*/
|
||||||
|
private void populateEntities() throws DataException {
|
||||||
|
entities = new ArrayList<>();
|
||||||
|
CompoundBinaryTag entityTag;
|
||||||
|
if (entityTagSupplier == null || (entityTag = entityTagSupplier.get()) == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ListBinaryTag tags = NbtUtils.getChildTag(entityTag, "Entities", BinaryTagTypes.LIST);
|
||||||
|
|
||||||
|
for (BinaryTag tag : tags) {
|
||||||
|
if (!(tag instanceof CompoundBinaryTag t)) {
|
||||||
|
throw new InvalidFormatException("CompoundTag expected in Entities");
|
||||||
|
}
|
||||||
|
|
||||||
|
entities.add(new BaseEntity(EntityTypes.get(t.getString("id")), LazyReference.computed(t)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -32,28 +32,56 @@ public class PackedIntArrayReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int SIZE = 4096;
|
|
||||||
|
|
||||||
private final long[] data;
|
private final long[] data;
|
||||||
private final int elementBits;
|
private final int elementBits;
|
||||||
private final long maxValue;
|
private final long maxValue;
|
||||||
private final int elementsPerLong;
|
private final int elementsPerLong;
|
||||||
private final int factor;
|
private final int factor;
|
||||||
|
//FAWE start - allow other sizes of data to be parsed
|
||||||
|
private final int storedSize;
|
||||||
|
//FAWE end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new PackedIntArrayReader instance based on an array of longs containing 4096 integers.
|
||||||
|
*
|
||||||
|
* @param data long array containing data
|
||||||
|
*/
|
||||||
public PackedIntArrayReader(long[] data) {
|
public PackedIntArrayReader(long[] data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
|
this.storedSize = 4096;
|
||||||
this.elementBits = data.length * 64 / 4096;
|
this.elementBits = data.length * 64 / 4096;
|
||||||
this.maxValue = (1L << elementBits) - 1L;
|
this.maxValue = (1L << elementBits) - 1L;
|
||||||
this.elementsPerLong = 64 / elementBits;
|
this.elementsPerLong = 64 / elementBits;
|
||||||
this.factor = FACTORS[elementsPerLong - 1];
|
this.factor = FACTORS[elementsPerLong - 1];
|
||||||
int j = (SIZE + this.elementsPerLong - 1) / this.elementsPerLong;
|
int j = (storedSize + this.elementsPerLong - 1) / this.elementsPerLong;
|
||||||
if (j != data.length) {
|
if (j != data.length) {
|
||||||
throw new IllegalStateException("Invalid packed-int array provided, should be of length " + j);
|
throw new IllegalStateException("Invalid packed-int array provided, should be of length " + j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//FAWE start - allow other sizes of data to be parsed
|
||||||
|
/**
|
||||||
|
* Create a new PackedIntArrayReader instance based on an array of longs containing a certain number of integers.
|
||||||
|
*
|
||||||
|
* @param data long array containing data
|
||||||
|
* @param storedSize the amount of integers stored in the long array
|
||||||
|
*/
|
||||||
|
public PackedIntArrayReader(long[] data, int storedSize) {
|
||||||
|
this.data = data;
|
||||||
|
this.storedSize = storedSize;
|
||||||
|
this.elementBits = data.length * 64 / storedSize;
|
||||||
|
this.maxValue = (1L << elementBits) - 1L;
|
||||||
|
this.elementsPerLong = 64 / elementBits;
|
||||||
|
this.factor = FACTORS[elementsPerLong - 1];
|
||||||
|
int j = (storedSize + this.elementsPerLong - 1) / this.elementsPerLong;
|
||||||
|
if (j != data.length) {
|
||||||
|
throw new IllegalStateException("Invalid packed-int array provided, should be of length " + j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//FAWE end
|
||||||
|
|
||||||
public int get(int index) {
|
public int get(int index) {
|
||||||
checkElementIndex(index, SIZE);
|
checkElementIndex(index, storedSize);
|
||||||
int i = this.adjustIndex(index);
|
int i = this.adjustIndex(index);
|
||||||
long l = this.data[i];
|
long l = this.data[i];
|
||||||
int j = (index - i * this.elementsPerLong) * this.elementBits;
|
int j = (index - i * this.elementsPerLong) * this.elementBits;
|
||||||
|
@ -73,28 +73,8 @@ public class ChunkStoreHelper {
|
|||||||
* @throws DataException if the rootTag is not valid chunk data
|
* @throws DataException if the rootTag is not valid chunk data
|
||||||
*/
|
*/
|
||||||
public static Chunk getChunk(CompoundTag rootTag) throws DataException {
|
public static Chunk getChunk(CompoundTag rootTag) throws DataException {
|
||||||
int dataVersion = rootTag.getInt("DataVersion");
|
|
||||||
if (dataVersion == 0) {
|
|
||||||
dataVersion = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING);
|
|
||||||
final int currentDataVersion = platform.getDataVersion();
|
|
||||||
if ((dataVersion > 0 || hasLevelSections(rootTag)) && dataVersion < currentDataVersion) { // only fix up MCA format, DFU doesn't support MCR chunks
|
|
||||||
final DataFixer dataFixer = platform.getDataFixer();
|
|
||||||
if (dataFixer != null) {
|
|
||||||
rootTag = (CompoundTag) AdventureNBTConverter.fromAdventure(dataFixer.fixUp(DataFixer.FixTypes.CHUNK,
|
|
||||||
rootTag.asBinaryTag(), dataVersion));
|
|
||||||
dataVersion = currentDataVersion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dataVersion >= Constants.DATA_VERSION_MC_1_18) {
|
|
||||||
return new AnvilChunk18(rootTag);
|
|
||||||
}
|
|
||||||
//FAWE start - biome and entity restore
|
//FAWE start - biome and entity restore
|
||||||
return getChunk(rootTag, () -> null);
|
return getChunk(rootTag, () -> null);
|
||||||
//FAWE end
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -105,9 +85,32 @@ public class ChunkStoreHelper {
|
|||||||
* location
|
* location
|
||||||
* @return a Chunk implementation
|
* @return a Chunk implementation
|
||||||
* @throws DataException if the rootTag is not valid chunk data
|
* @throws DataException if the rootTag is not valid chunk data
|
||||||
|
* @since TODO
|
||||||
*/
|
*/
|
||||||
public static Chunk getChunk(CompoundTag rootTag, Supplier<CompoundTag> entitiesTag) throws DataException {
|
public static Chunk getChunk(CompoundTag rootTag, Supplier<CompoundTag> entitiesTag) throws DataException {
|
||||||
//FAWE end
|
//FAWE end
|
||||||
|
int dataVersion = rootTag.getInt("DataVersion");
|
||||||
|
if (dataVersion == 0) {
|
||||||
|
dataVersion = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING);
|
||||||
|
final int currentDataVersion = platform.getDataVersion();
|
||||||
|
if ((dataVersion > 0 || hasLevelSections(rootTag)) && dataVersion < currentDataVersion) { // only fix up MCA format, DFU doesn't support MCR chunks
|
||||||
|
final DataFixer dataFixer = platform.getDataFixer();
|
||||||
|
if (dataFixer != null) {
|
||||||
|
//FAWE start - CBT
|
||||||
|
rootTag = (CompoundTag) AdventureNBTConverter.fromAdventure(dataFixer.fixUp(DataFixer.FixTypes.CHUNK,
|
||||||
|
rootTag.asBinaryTag(), dataVersion));
|
||||||
|
//FAWE end
|
||||||
|
dataVersion = currentDataVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataVersion >= Constants.DATA_VERSION_MC_1_18) {
|
||||||
|
return new AnvilChunk18(rootTag, entitiesTag);
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, Tag> children = rootTag.getValue();
|
Map<String, Tag> children = rootTag.getValue();
|
||||||
CompoundTag tag = null;
|
CompoundTag tag = null;
|
||||||
|
|
||||||
@ -130,10 +133,6 @@ public class ChunkStoreHelper {
|
|||||||
throw new ChunkStoreException("Missing root 'Level' tag");
|
throw new ChunkStoreException("Missing root 'Level' tag");
|
||||||
}
|
}
|
||||||
|
|
||||||
int dataVersion = rootTag.getInt("DataVersion");
|
|
||||||
if (dataVersion == 0) {
|
|
||||||
dataVersion = -1;
|
|
||||||
}
|
|
||||||
//FAWE start - biome and entity restore
|
//FAWE start - biome and entity restore
|
||||||
if (dataVersion >= Constants.DATA_VERSION_MC_1_17) {
|
if (dataVersion >= Constants.DATA_VERSION_MC_1_17) {
|
||||||
return new AnvilChunk17(tag, entitiesTag);
|
return new AnvilChunk17(tag, entitiesTag);
|
||||||
|
@ -80,14 +80,13 @@ public class TrueZipMcRegionChunkStore extends McRegionChunkStore {
|
|||||||
protected InputStream getInputStream(String name, String worldName, @Nullable String folderOverride) throws IOException,
|
protected InputStream getInputStream(String name, String worldName, @Nullable String folderOverride) throws IOException,
|
||||||
DataException {
|
DataException {
|
||||||
// Detect subfolder for the world's files
|
// Detect subfolder for the world's files
|
||||||
if (folderOverride != null) {
|
if (folder != null) {
|
||||||
if (!folderOverride.isEmpty()) {
|
|
||||||
name = folderOverride + "/" + name;
|
|
||||||
}
|
|
||||||
} else if (folder != null) {
|
|
||||||
//FAWE end
|
|
||||||
if (!folder.isEmpty()) {
|
if (!folder.isEmpty()) {
|
||||||
|
//FAWE end
|
||||||
name = folder + "/" + name;
|
name = folder + "/" + name;
|
||||||
|
if (folderOverride != null) {
|
||||||
|
name = name.replace("region", folderOverride);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Pattern pattern = Pattern.compile(".*\\.mc[ra]$");
|
Pattern pattern = Pattern.compile(".*\\.mc[ra]$");
|
||||||
@ -105,6 +104,12 @@ public class TrueZipMcRegionChunkStore extends McRegionChunkStore {
|
|||||||
endIndex = entryName.lastIndexOf('\\');
|
endIndex = entryName.lastIndexOf('\\');
|
||||||
}
|
}
|
||||||
folder = entryName.substring(0, endIndex);
|
folder = entryName.substring(0, endIndex);
|
||||||
|
//FAWE start - biome and entity restore
|
||||||
|
if (folderOverride != null && folder.endsWith(folderOverride)) {
|
||||||
|
name = folder + "/" + name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//FAWE end
|
||||||
if (folder.endsWith("poi") || folder.endsWith("entities")) {
|
if (folder.endsWith("poi") || folder.endsWith("entities")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -78,14 +78,13 @@ public class ZippedMcRegionChunkStore extends McRegionChunkStore {
|
|||||||
protected InputStream getInputStream(String name, String worldName, @Nullable String folderOverride) throws IOException,
|
protected InputStream getInputStream(String name, String worldName, @Nullable String folderOverride) throws IOException,
|
||||||
DataException {
|
DataException {
|
||||||
// Detect subfolder for the world's files
|
// Detect subfolder for the world's files
|
||||||
if (folderOverride != null) {
|
if (folder != null) {
|
||||||
if (!folderOverride.isEmpty()) {
|
|
||||||
name = folderOverride + "/" + name;
|
|
||||||
}
|
|
||||||
} else if (folder != null) {
|
|
||||||
if (!folder.isEmpty()) {
|
if (!folder.isEmpty()) {
|
||||||
//FAWE end
|
//FAWE end
|
||||||
name = folder + "/" + name;
|
name = folder + "/" + name;
|
||||||
|
if (folderOverride != null) {
|
||||||
|
name = name.replace("region", folderOverride);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Pattern pattern = Pattern.compile(".*\\.mc[ra]$");
|
Pattern pattern = Pattern.compile(".*\\.mc[ra]$");
|
||||||
@ -101,6 +100,12 @@ public class ZippedMcRegionChunkStore extends McRegionChunkStore {
|
|||||||
endIndex = entryName.lastIndexOf('\\');
|
endIndex = entryName.lastIndexOf('\\');
|
||||||
}
|
}
|
||||||
folder = entryName.substring(0, endIndex);
|
folder = entryName.substring(0, endIndex);
|
||||||
|
//FAWE start - biome and entity restore
|
||||||
|
if (folderOverride != null && folder.endsWith(folderOverride)) {
|
||||||
|
name = folder + "/" + name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//FAWE end
|
||||||
if (folder.endsWith("poi") || folder.endsWith("entities")) {
|
if (folder.endsWith("poi") || folder.endsWith("entities")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren