Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-09-06 08:02:50 +02:00
Merge master again
Dieser Commit ist enthalten in:
Commit
7ff537138a
@ -67,6 +67,14 @@ public class BukkitServerInterface implements MultiUserPlatform {
|
||||
return BukkitRegistries.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataVersion() {
|
||||
if (plugin.getBukkitImplAdapter() != null) {
|
||||
return plugin.getBukkitImplAdapter().getDataVersion();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidMobType(String type) {
|
||||
final EntityType entityType = EntityType.fromName(type);
|
||||
|
@ -40,6 +40,13 @@ import javax.annotation.Nullable;
|
||||
*/
|
||||
public interface BukkitImplAdapter {
|
||||
|
||||
/**
|
||||
* Get the Minecraft data version for the current world data.
|
||||
*
|
||||
* @return the data version
|
||||
*/
|
||||
int getDataVersion();
|
||||
|
||||
/**
|
||||
* Get the block at the given location.
|
||||
*
|
||||
|
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
@ -181,6 +181,18 @@ public class CompoundTagBuilder {
|
||||
return put(key, new StringTag(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given key from the compound tag. Does nothing if the key doesn't exist.
|
||||
*
|
||||
* @param key the key
|
||||
* @return this object
|
||||
*/
|
||||
public CompoundTagBuilder remove(String key) {
|
||||
checkNotNull(key);
|
||||
entries.remove(key);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put all the entries from the given map into this map.
|
||||
*
|
||||
|
@ -59,6 +59,7 @@ import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import org.enginehub.piston.annotation.Command;
|
||||
import org.enginehub.piston.annotation.CommandContainer;
|
||||
import org.enginehub.piston.annotation.param.Arg;
|
||||
import org.enginehub.piston.annotation.param.ArgFlag;
|
||||
import org.enginehub.piston.annotation.param.Switch;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
@ -145,8 +146,14 @@ public class BrushCommands {
|
||||
public void clipboardBrush(Player player, LocalSession session,
|
||||
@Switch(name = 'a', desc = "Don't paste air from the clipboard")
|
||||
boolean ignoreAir,
|
||||
@Switch(name = 'p', desc = "Paste using clipboard origin, instead of being centered at the target location")
|
||||
boolean usingOrigin) throws WorldEditException {
|
||||
@Switch(name = 'o', desc = "Paste using clipboard origin, instead of being centered at the target location")
|
||||
boolean usingOrigin,
|
||||
@Switch(name = 'e', desc = "Paste entities if available")
|
||||
boolean pasteEntities,
|
||||
@Switch(name = 'b', desc = "Paste biomes if available")
|
||||
boolean pasteBiomes,
|
||||
@ArgFlag(name = 'm', desc = "Skip blocks matching this mask", def = "")
|
||||
Mask sourceMask) throws WorldEditException {
|
||||
ClipboardHolder holder = session.getClipboard();
|
||||
Clipboard clipboard = holder.getClipboard();
|
||||
|
||||
@ -157,7 +164,7 @@ public class BrushCommands {
|
||||
worldEdit.checkMaxBrushRadius(size.getBlockZ() / 2D - 1);
|
||||
|
||||
BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
|
||||
tool.setBrush(new ClipboardBrush(holder, ignoreAir, usingOrigin), "worldedit.brush.clipboard");
|
||||
tool.setBrush(new ClipboardBrush(holder, ignoreAir, usingOrigin, pasteEntities, pasteBiomes, sourceMask), "worldedit.brush.clipboard");
|
||||
|
||||
player.print("Clipboard brush shape equipped.");
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
package com.sk89q.worldedit.command;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
@ -49,6 +50,8 @@ import org.enginehub.piston.annotation.param.Arg;
|
||||
import org.enginehub.piston.annotation.param.ArgFlag;
|
||||
import org.enginehub.piston.annotation.param.Switch;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT;
|
||||
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
|
||||
|
||||
@ -73,19 +76,24 @@ public class ClipboardCommands {
|
||||
@Selection Region region,
|
||||
@Switch(name = 'e', desc = "Also copy entities")
|
||||
boolean copyEntities,
|
||||
@Switch(name = 'b', desc = "Also copy biomes")
|
||||
boolean copyBiomes,
|
||||
@ArgFlag(name = 'm', desc = "Set the exclude mask, matching blocks become air", def = "")
|
||||
Mask mask) throws WorldEditException {
|
||||
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
|
||||
clipboard.setOrigin(session.getPlacementPosition(player));
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
|
||||
copy.setCopyingEntities(copyEntities);
|
||||
copy.setCopyingBiomes(copyBiomes);
|
||||
if (mask != null) {
|
||||
copy.setSourceMask(mask);
|
||||
}
|
||||
Operations.completeLegacy(copy);
|
||||
session.setClipboard(new ClipboardHolder(clipboard));
|
||||
|
||||
player.print(region.getArea() + " block(s) were copied.");
|
||||
List<String> messages = Lists.newArrayList();
|
||||
copy.addStatusMessages(messages);
|
||||
messages.forEach(player::print);
|
||||
}
|
||||
|
||||
@Command(
|
||||
@ -101,6 +109,8 @@ public class ClipboardCommands {
|
||||
Pattern leavePattern,
|
||||
@Switch(name = 'e', desc = "Also cut entities")
|
||||
boolean copyEntities,
|
||||
@Switch(name = 'b', desc = "Also copy biomes, source biomes are unaffected")
|
||||
boolean copyBiomes,
|
||||
@ArgFlag(name = 'm', desc = "Set the exclude mask, matching blocks become air", def = "")
|
||||
Mask mask) throws WorldEditException {
|
||||
|
||||
@ -110,13 +120,16 @@ public class ClipboardCommands {
|
||||
copy.setSourceFunction(new BlockReplace(editSession, leavePattern));
|
||||
copy.setCopyingEntities(copyEntities);
|
||||
copy.setRemovingEntities(true);
|
||||
copy.setCopyingBiomes(copyBiomes);
|
||||
if (mask != null) {
|
||||
copy.setSourceMask(mask);
|
||||
}
|
||||
Operations.completeLegacy(copy);
|
||||
session.setClipboard(new ClipboardHolder(clipboard));
|
||||
|
||||
player.print(region.getArea() + " block(s) were cut.");
|
||||
List<String> messages = Lists.newArrayList();
|
||||
copy.addStatusMessages(messages);
|
||||
messages.forEach(player::print);
|
||||
}
|
||||
|
||||
@Command(
|
||||
@ -131,7 +144,13 @@ public class ClipboardCommands {
|
||||
@Switch(name = 'o', desc = "Paste at the original position")
|
||||
boolean atOrigin,
|
||||
@Switch(name = 's', desc = "Select the region after pasting")
|
||||
boolean selectPasted) throws WorldEditException {
|
||||
boolean selectPasted,
|
||||
@Switch(name = 'e', desc = "Paste entities if available")
|
||||
boolean pasteEntities,
|
||||
@Switch(name = 'b', desc = "Paste biomes if available")
|
||||
boolean pasteBiomes,
|
||||
@ArgFlag(name = 'm', desc = "Skip blocks matching this mask", def = "")
|
||||
Mask sourceMask) throws WorldEditException {
|
||||
|
||||
ClipboardHolder holder = session.getClipboard();
|
||||
Clipboard clipboard = holder.getClipboard();
|
||||
@ -139,10 +158,13 @@ public class ClipboardCommands {
|
||||
|
||||
BlockVector3 to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(player);
|
||||
Operation operation = holder
|
||||
.createPaste(editSession)
|
||||
.to(to)
|
||||
.ignoreAirBlocks(ignoreAirBlocks)
|
||||
.build();
|
||||
.createPaste(editSession)
|
||||
.to(to)
|
||||
.ignoreAirBlocks(ignoreAirBlocks)
|
||||
.copyBiomes(pasteBiomes)
|
||||
.copyEntities(pasteEntities)
|
||||
.maskSource(sourceMask)
|
||||
.build();
|
||||
Operations.completeLegacy(operation);
|
||||
|
||||
if (selectPasted) {
|
||||
@ -156,6 +178,9 @@ public class ClipboardCommands {
|
||||
}
|
||||
|
||||
player.print("The clipboard has been pasted at " + to);
|
||||
List<String> messages = Lists.newArrayList();
|
||||
operation.addStatusMessages(messages);
|
||||
messages.forEach(player::print);
|
||||
}
|
||||
|
||||
@Command(
|
||||
|
@ -115,6 +115,9 @@ class FlattenedClipboardTransform {
|
||||
BlockTransformExtent extent = new BlockTransformExtent(original, transform);
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(extent, original.getRegion(), original.getOrigin(), target, original.getOrigin());
|
||||
copy.setTransform(transform);
|
||||
if (original.hasBiomes()) {
|
||||
copy.setCopyingBiomes(true);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ package com.sk89q.worldedit.command.tool.brush;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
@ -31,14 +32,30 @@ import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
|
||||
public class ClipboardBrush implements Brush {
|
||||
|
||||
private ClipboardHolder holder;
|
||||
private boolean ignoreAirBlocks;
|
||||
private boolean usingOrigin;
|
||||
private final ClipboardHolder holder;
|
||||
private final boolean ignoreAirBlocks;
|
||||
private final boolean usingOrigin;
|
||||
private final boolean pasteEntities;
|
||||
private final boolean pasteBiomes;
|
||||
private final Mask sourceMask;
|
||||
|
||||
public ClipboardBrush(ClipboardHolder holder, boolean ignoreAirBlocks, boolean usingOrigin) {
|
||||
this.holder = holder;
|
||||
this.ignoreAirBlocks = ignoreAirBlocks;
|
||||
this.usingOrigin = usingOrigin;
|
||||
this.pasteBiomes = false;
|
||||
this.pasteEntities = false;
|
||||
this.sourceMask = null;
|
||||
}
|
||||
|
||||
public ClipboardBrush(ClipboardHolder holder, boolean ignoreAirBlocks, boolean usingOrigin, boolean pasteEntities,
|
||||
boolean pasteBiomes, Mask sourceMask) {
|
||||
this.holder = holder;
|
||||
this.ignoreAirBlocks = ignoreAirBlocks;
|
||||
this.usingOrigin = usingOrigin;
|
||||
this.pasteEntities = pasteEntities;
|
||||
this.pasteBiomes = pasteBiomes;
|
||||
this.sourceMask = sourceMask;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -51,6 +68,9 @@ public class ClipboardBrush implements Brush {
|
||||
.createPaste(editSession)
|
||||
.to(usingOrigin ? position : position.subtract(centerOffset))
|
||||
.ignoreAirBlocks(ignoreAirBlocks)
|
||||
.copyEntities(pasteEntities)
|
||||
.copyBiomes(pasteBiomes)
|
||||
.maskSource(sourceMask)
|
||||
.build();
|
||||
|
||||
Operations.completeLegacy(operation);
|
||||
|
@ -46,6 +46,13 @@ public interface Platform {
|
||||
*/
|
||||
Registries getRegistries();
|
||||
|
||||
/**
|
||||
* Gets the Minecraft data version being used by the platform.
|
||||
*
|
||||
* @return the data version
|
||||
*/
|
||||
int getDataVersion();
|
||||
|
||||
/**
|
||||
* Checks if a mob type is valid.
|
||||
*
|
||||
|
@ -161,12 +161,20 @@ public class BlockArrayClipboard implements Clipboard {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBiomes() {
|
||||
return biomes != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiome(BlockVector2 position) {
|
||||
if (biomes != null
|
||||
&& position.containedWithin(getMinimumPoint().toBlockVector2(), getMaximumPoint().toBlockVector2())) {
|
||||
BlockVector2 v = position.subtract(region.getMinimumPoint().toBlockVector2());
|
||||
return biomes[v.getBlockX()][v.getBlockZ()];
|
||||
BiomeType biomeType = biomes[v.getBlockX()][v.getBlockZ()];
|
||||
if (biomeType != null) {
|
||||
return biomeType;
|
||||
}
|
||||
}
|
||||
|
||||
return BiomeTypes.OCEAN;
|
||||
|
@ -20,6 +20,7 @@
|
||||
package com.sk89q.worldedit.extent.clipboard;
|
||||
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
@ -58,4 +59,15 @@ public interface Clipboard extends Extent {
|
||||
*/
|
||||
void setOrigin(BlockVector3 origin);
|
||||
|
||||
/**
|
||||
* Returns true if the clipboard has biome data. This can be checked since {@link Extent#getBiome(BlockVector2)}
|
||||
* strongly suggests returning {@link com.sk89q.worldedit.world.biome.BiomeTypes.OCEAN} instead of {@code null}
|
||||
* if biomes aren't present. However, it might not be desired to set areas to ocean if the clipboard is defaulting
|
||||
* to ocean, instead of having biomes explicitly set.
|
||||
*
|
||||
* @return true if the clipboard has biome data set
|
||||
*/
|
||||
default boolean hasBiomes() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
package com.sk89q.worldedit.extent.clipboard.io;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.sk89q.jnbt.ByteArrayTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
@ -32,8 +33,13 @@ import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.EntityNBTCompatibilityHandler;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.FlowerPotCompatibilityHandler;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NBTCompatibilityHandler;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NoteBlockCompatibilityHandler;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.Pre13HangingCompatibilityHandler;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.SignCompatibilityHandler;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.SkullBlockCompatibilityHandler;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
@ -47,10 +53,11 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -59,12 +66,18 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
*/
|
||||
public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
|
||||
private static final List<NBTCompatibilityHandler> COMPATIBILITY_HANDLERS = new ArrayList<>();
|
||||
|
||||
static {
|
||||
COMPATIBILITY_HANDLERS.add(new SignCompatibilityHandler());
|
||||
// TODO Add a handler for skulls, flower pots, note blocks, etc.
|
||||
}
|
||||
private static final ImmutableList<NBTCompatibilityHandler> COMPATIBILITY_HANDLERS
|
||||
= ImmutableList.of(
|
||||
new SignCompatibilityHandler(),
|
||||
new FlowerPotCompatibilityHandler(),
|
||||
new NoteBlockCompatibilityHandler(),
|
||||
new SkullBlockCompatibilityHandler()
|
||||
// TODO - item tags for inventories...? DFUs :>
|
||||
);
|
||||
private static final ImmutableList<EntityNBTCompatibilityHandler> ENTITY_COMPATIBILITY_HANDLERS
|
||||
= ImmutableList.of(
|
||||
new Pre13HangingCompatibilityHandler()
|
||||
);
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MCEditSchematicReader.class);
|
||||
private final NBTInputStream inputStream;
|
||||
@ -162,65 +175,55 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
// Need to pull out tile entities
|
||||
List<Tag> tileEntities = requireTag(schematic, "TileEntities", ListTag.class).getValue();
|
||||
Map<BlockVector3, Map<String, Tag>> tileEntitiesMap = new HashMap<>();
|
||||
Map<BlockVector3, BlockState> blockOverrides = new HashMap<>();
|
||||
|
||||
for (Tag tag : tileEntities) {
|
||||
if (!(tag instanceof CompoundTag)) continue;
|
||||
CompoundTag t = (CompoundTag) tag;
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int z = 0;
|
||||
int x = t.getInt("x");
|
||||
int y = t.getInt("y");
|
||||
int z = t.getInt("z");
|
||||
String id = t.getString("id");
|
||||
|
||||
Map<String, Tag> values = new HashMap<>();
|
||||
|
||||
for (Map.Entry<String, Tag> entry : t.getValue().entrySet()) {
|
||||
switch (entry.getKey()) {
|
||||
case "x":
|
||||
if (entry.getValue() instanceof IntTag) {
|
||||
x = ((IntTag) entry.getValue()).getValue();
|
||||
}
|
||||
break;
|
||||
case "y":
|
||||
if (entry.getValue() instanceof IntTag) {
|
||||
y = ((IntTag) entry.getValue()).getValue();
|
||||
}
|
||||
break;
|
||||
case "z":
|
||||
if (entry.getValue() instanceof IntTag) {
|
||||
z = ((IntTag) entry.getValue()).getValue();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
values.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
Map<String, Tag> values = new HashMap<>(t.getValue());
|
||||
values.put("id", new StringTag(convertBlockEntityId(id)));
|
||||
|
||||
int index = y * width * length + z * width + x;
|
||||
BlockState block = LegacyMapper.getInstance().getBlockFromLegacy(blocks[index], blockData[index]);
|
||||
if (block != null) {
|
||||
BlockState newBlock = block;
|
||||
if (newBlock != null) {
|
||||
for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) {
|
||||
if (handler.isAffectedBlock(block)) {
|
||||
handler.updateNBT(block, values);
|
||||
if (handler.isAffectedBlock(newBlock)) {
|
||||
newBlock = handler.updateNBT(block, values);
|
||||
if (newBlock == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BlockVector3 vec = BlockVector3.at(x, y, z);
|
||||
tileEntitiesMap.put(vec, values);
|
||||
if (newBlock != block) {
|
||||
blockOverrides.put(vec, newBlock);
|
||||
}
|
||||
}
|
||||
|
||||
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
|
||||
clipboard.setOrigin(origin);
|
||||
|
||||
// Don't log a torrent of errors
|
||||
int failedBlockSets = 0;
|
||||
|
||||
Set<Integer> unknownBlocks = new HashSet<>();
|
||||
for (int x = 0; x < width; ++x) {
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int z = 0; z < length; ++z) {
|
||||
int index = y * width * length + z * width + x;
|
||||
BlockVector3 pt = BlockVector3.at(x, y, z);
|
||||
BlockState state = LegacyMapper.getInstance().getBlockFromLegacy(blocks[index], blockData[index]);
|
||||
boolean useOverride = blockOverrides.containsKey(pt);
|
||||
BlockState state = useOverride
|
||||
? blockOverrides.get(pt)
|
||||
: LegacyMapper.getInstance().getBlockFromLegacy(blocks[index], blockData[index]);
|
||||
|
||||
try {
|
||||
if (state != null) {
|
||||
@ -229,21 +232,16 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
} else {
|
||||
clipboard.setBlock(region.getMinimumPoint().add(pt), state);
|
||||
}
|
||||
} else {
|
||||
log.warn("Unknown block when pasting schematic: " + blocks[index] + ":" + blockData[index] + ". Please report this issue.");
|
||||
} else if (!useOverride) {
|
||||
short block = blocks[index];
|
||||
byte data = blockData[index];
|
||||
int combined = block << 8 | data;
|
||||
if (unknownBlocks.add(combined)) {
|
||||
log.warn("Unknown block when pasting schematic: "
|
||||
+ block + ":" + data + ". Please report this issue.");
|
||||
}
|
||||
}
|
||||
} catch (WorldEditException e) {
|
||||
switch (failedBlockSets) {
|
||||
case 0:
|
||||
log.warn("Failed to set block on a Clipboard", e);
|
||||
break;
|
||||
case 1:
|
||||
log.warn("Failed to set block on a Clipboard (again) -- no more messages will be logged", e);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
failedBlockSets++;
|
||||
} catch (WorldEditException ignored) { // BlockArrayClipboard won't throw this
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -253,8 +251,9 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
// Entities
|
||||
// ====================================================================
|
||||
|
||||
List<Tag> entityTags = getTag(schematic, "Entities", ListTag.class).getValue();
|
||||
if (entityTags != null) {
|
||||
ListTag entityList = getTag(schematic, "Entities", ListTag.class);
|
||||
if (entityList != null) {
|
||||
List<Tag> entityTags = entityList.getValue();
|
||||
for (Tag tag : entityTags) {
|
||||
if (tag instanceof CompoundTag) {
|
||||
CompoundTag compound = (CompoundTag) tag;
|
||||
@ -264,6 +263,11 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
if (!id.isEmpty()) {
|
||||
EntityType entityType = EntityTypes.get(id.toLowerCase());
|
||||
if (entityType != null) {
|
||||
for (EntityNBTCompatibilityHandler compatibilityHandler : ENTITY_COMPATIBILITY_HANDLERS) {
|
||||
if (compatibilityHandler.isAffectedEntity(entityType, compound)) {
|
||||
compound = compatibilityHandler.updateNBT(entityType, compound);
|
||||
}
|
||||
}
|
||||
BaseEntity state = new BaseEntity(entityType, compound);
|
||||
clipboard.createEntity(location, state);
|
||||
} else {
|
||||
@ -279,32 +283,66 @@ public class MCEditSchematicReader extends NBTSchematicReader {
|
||||
|
||||
private String convertEntityId(String id) {
|
||||
switch(id) {
|
||||
case "xp_orb":
|
||||
return "experience_orb";
|
||||
case "xp_bottle":
|
||||
return "experience_bottle";
|
||||
case "eye_of_ender_signal":
|
||||
return "eye_of_ender";
|
||||
case "ender_crystal":
|
||||
return "end_crystal";
|
||||
case "fireworks_rocket":
|
||||
return "firework_rocket";
|
||||
case "commandblock_minecart":
|
||||
return "command_block_minecart";
|
||||
case "snowman":
|
||||
return "snow_golem";
|
||||
case "villager_golem":
|
||||
return "iron_golem";
|
||||
case "evocation_fangs":
|
||||
return "evoker_fangs";
|
||||
case "evocation_illager":
|
||||
return "evoker";
|
||||
case "vindication_illager":
|
||||
return "vindicator";
|
||||
case "illusion_illager":
|
||||
return "illusioner";
|
||||
case "AreaEffectCloud": return "area_effect_cloud";
|
||||
case "ArmorStand": return "armor_stand";
|
||||
case "CaveSpider": return "cave_spider";
|
||||
case "MinecartChest": return "chest_minecart";
|
||||
case "MinecartCommandBlock": return "commandblock_minecart";
|
||||
case "DragonFireball": return "dragon_fireball";
|
||||
case "ThrownEgg": return "egg";
|
||||
case "EnderCrystal": return "ender_crystal";
|
||||
case "EnderDragon": return "ender_dragon";
|
||||
case "ThrownEnderpearl": return "ender_pearl";
|
||||
case "EyeOfEnderSignal": return "eye_of_ender_signal";
|
||||
case "FallingSand": return "falling_block";
|
||||
case "FireworksRocketEntity": return "fireworks_rocket";
|
||||
case "MinecartFurnace": return "furnace_minecart";
|
||||
case "MinecartHopper": return "hopper_minecart";
|
||||
case "EntityHorse": return "horse";
|
||||
case "ItemFrame": return "item_frame";
|
||||
case "LeashKnot": return "leash_knot";
|
||||
case "LightningBolt": return "lightning_bolt";
|
||||
case "LavaSlime": return "magma_cube";
|
||||
case "MinecartRideable": return "minecart";
|
||||
case "MushroomCow": return "mooshroom";
|
||||
case "Ozelot": return "ocelot";
|
||||
case "PolarBear": return "polar_bear";
|
||||
case "ThrownPotion": return "potion";
|
||||
case "ShulkerBullet": return "shulker_bullet";
|
||||
case "SmallFireball": return "small_fireball";
|
||||
case "MinecartSpawner": return "spawner_minecart";
|
||||
case "SpectralArrow": return "spectral_arrow";
|
||||
case "PrimedTnt": return "tnt";
|
||||
case "MinecartTNT": return "tnt_minecart";
|
||||
case "VillagerGolem": return "villager_golem";
|
||||
case "WitherBoss": return "wither";
|
||||
case "WitherSkull": return "wither_skull";
|
||||
case "ThrownExpBottle": return "xp_bottle";
|
||||
case "XPOrb": return "xp_orb";
|
||||
case "PigZombie": return "zombie_pigman";
|
||||
default: return id;
|
||||
}
|
||||
}
|
||||
|
||||
private String convertBlockEntityId(String id) {
|
||||
switch(id) {
|
||||
case "Cauldron": return "brewing_stand";
|
||||
case "Control": return "command_block";
|
||||
case "DLDetector": return "daylight_detector";
|
||||
case "Trap": return "dispenser";
|
||||
case "EnchantTable": return "enchanting_table";
|
||||
case "EndGateway": return "end_gateway";
|
||||
case "AirPortal": return "end_portal";
|
||||
case "EnderChest": return "ender_chest";
|
||||
case "FlowerPot": return "flower_pot";
|
||||
case "RecordPlayer": return "jukebox";
|
||||
case "MobSpawner": return "mob_spawner";
|
||||
case "Music":
|
||||
case "noteblock":
|
||||
return "note_block";
|
||||
case "Structure": return "structure_block";
|
||||
default: return id;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -28,18 +28,28 @@ import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NamedTag;
|
||||
import com.sk89q.jnbt.ShortTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NBTCompatibilityHandler;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.entity.EntityTypes;
|
||||
import com.sk89q.worldedit.world.storage.NBTConversions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -48,6 +58,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
@ -89,6 +100,15 @@ public class SpongeSchematicReader extends NBTSchematicReader {
|
||||
int version = requireTag(schematic, "Version", IntTag.class).getValue();
|
||||
if (version == 1) {
|
||||
return readVersion1(schematicTag);
|
||||
} else if (version == 2) {
|
||||
int dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue();
|
||||
if (dataVersion > WorldEdit.getInstance().getPlatformManager()
|
||||
.queryCapability(Capability.WORLD_EDITING).getDataVersion()) {
|
||||
// maybe should just warn? simple schematics may be compatible still.
|
||||
throw new IOException("Schematic was made in a newer Minecraft version. Data may be incompatible.");
|
||||
}
|
||||
BlockArrayClipboard clip = readVersion1(schematicTag);
|
||||
return readVersion2(clip, schematicTag);
|
||||
}
|
||||
throw new IOException("This schematic version is currently not supported");
|
||||
}
|
||||
@ -126,7 +146,7 @@ public class SpongeSchematicReader extends NBTSchematicReader {
|
||||
int paletteMax = requireTag(schematic, "PaletteMax", IntTag.class).getValue();
|
||||
Map<String, Tag> paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue();
|
||||
if (paletteObject.size() != paletteMax) {
|
||||
throw new IOException("Differing given palette size to actual size");
|
||||
throw new IOException("Block palette size does not match expected size.");
|
||||
}
|
||||
|
||||
Map<Integer, BlockState> palette = new HashMap<>();
|
||||
@ -142,7 +162,8 @@ public class SpongeSchematicReader extends NBTSchematicReader {
|
||||
try {
|
||||
state = WorldEdit.getInstance().getBlockFactory().parseFromInput(palettePart, parserContext).toImmutableState();
|
||||
} catch (InputParseException e) {
|
||||
throw new IOException("Invalid BlockState in schematic: " + palettePart + ". Are you missing a mod or using a schematic made in a newer version of Minecraft?");
|
||||
throw new IOException("Invalid BlockState in palette: " + palettePart +
|
||||
". Are you missing a mod or using a schematic made in a newer version of Minecraft?");
|
||||
}
|
||||
palette.put(id, state);
|
||||
}
|
||||
@ -168,8 +189,8 @@ public class SpongeSchematicReader extends NBTSchematicReader {
|
||||
|
||||
int index = 0;
|
||||
int i = 0;
|
||||
int value = 0;
|
||||
int varintLength = 0;
|
||||
int value;
|
||||
int varintLength;
|
||||
while (i < blocks.length) {
|
||||
value = 0;
|
||||
varintLength = 0;
|
||||
@ -185,7 +206,7 @@ public class SpongeSchematicReader extends NBTSchematicReader {
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// index = (y * length + z) * width + x
|
||||
// index = (y * length * width) + (z * width) + x
|
||||
int y = index / (width * length);
|
||||
int z = (index % (width * length)) / width;
|
||||
int x = (index % (width * length)) % width;
|
||||
@ -219,6 +240,99 @@ public class SpongeSchematicReader extends NBTSchematicReader {
|
||||
return clipboard;
|
||||
}
|
||||
|
||||
private Clipboard readVersion2(BlockArrayClipboard version1, CompoundTag schematicTag) throws IOException {
|
||||
Map<String, Tag> schematic = schematicTag.getValue();
|
||||
if (schematic.containsKey("BiomeData")) {
|
||||
readBiomes(version1, schematic);
|
||||
}
|
||||
if (schematic.containsKey("Entities")) {
|
||||
readEntities(version1, schematic);
|
||||
}
|
||||
return version1;
|
||||
}
|
||||
|
||||
private void readBiomes(BlockArrayClipboard clipboard, Map<String, Tag> schematic) throws IOException {
|
||||
ByteArrayTag dataTag = requireTag(schematic, "BiomeData", ByteArrayTag.class);
|
||||
IntTag maxTag = requireTag(schematic, "BiomePaletteMax", IntTag.class);
|
||||
CompoundTag paletteTag = requireTag(schematic, "BiomePalette", CompoundTag.class);
|
||||
|
||||
Map<Integer, BiomeType> palette = new HashMap<>();
|
||||
if (maxTag.getValue() != paletteTag.getValue().size()) {
|
||||
throw new IOException("Biome palette size does not match expected size.");
|
||||
}
|
||||
Map<String, Tag> paletteEntries = paletteTag.getValue();
|
||||
|
||||
for (Entry<String, Tag> palettePart : paletteEntries.entrySet()) {
|
||||
BiomeType biome = BiomeTypes.get(palettePart.getKey());
|
||||
if (biome == null) {
|
||||
log.warn("Unknown biome type :" + palettePart.getKey() +
|
||||
" in palette. Are you missing a mod or using a schematic made in a newer version of Minecraft?");
|
||||
}
|
||||
Tag idTag = palettePart.getValue();
|
||||
if (!(idTag instanceof IntTag)) {
|
||||
throw new IOException("Biome mapped to non-Int tag.");
|
||||
}
|
||||
palette.put(((IntTag) idTag).getValue(), biome);
|
||||
}
|
||||
|
||||
int width = clipboard.getDimensions().getX();
|
||||
|
||||
byte[] biomes = dataTag.getValue();
|
||||
int biomeIndex = 0;
|
||||
int biomeJ = 0;
|
||||
int bVal;
|
||||
int varIntLength;
|
||||
BlockVector2 min = clipboard.getMinimumPoint().toBlockVector2();
|
||||
while (biomeJ < biomes.length) {
|
||||
bVal = 0;
|
||||
varIntLength = 0;
|
||||
|
||||
while (true) {
|
||||
bVal |= (biomes[biomeJ] & 127) << (varIntLength++ * 7);
|
||||
if (varIntLength > 5) {
|
||||
throw new RuntimeException("VarInt too big (probably corrupted data)");
|
||||
}
|
||||
if (((biomes[biomeJ] & 128) != 128)) {
|
||||
biomeJ++;
|
||||
break;
|
||||
}
|
||||
biomeJ++;
|
||||
}
|
||||
int z = biomeIndex / width;
|
||||
int x = biomeIndex % width;
|
||||
BiomeType type = palette.get(bVal);
|
||||
clipboard.setBiome(min.add(x, z), type);
|
||||
biomeIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
private void readEntities(BlockArrayClipboard clipboard, Map<String, Tag> schematic) throws IOException {
|
||||
List<Tag> entList = requireTag(schematic, "Entities", ListTag.class).getValue();
|
||||
if (entList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (Tag et : entList) {
|
||||
if (!(et instanceof CompoundTag)) {
|
||||
continue;
|
||||
}
|
||||
CompoundTag entityTag = (CompoundTag) et;
|
||||
Map<String, Tag> tags = entityTag.getValue();
|
||||
String id = requireTag(tags, "Id", StringTag.class).getValue();
|
||||
|
||||
EntityType entityType = EntityTypes.get(id);
|
||||
if (entityType != null) {
|
||||
Location location = NBTConversions.toLocation(clipboard,
|
||||
requireTag(tags, "Pos", ListTag.class),
|
||||
requireTag(tags, "Rotation", ListTag.class));
|
||||
BaseEntity state = new BaseEntity(entityType,
|
||||
entityTag.createBuilder().putString("id", id).remove("Id").build());
|
||||
clipboard.createEntity(location, state);
|
||||
} else {
|
||||
log.warn("Unknown entity when pasting schematic: " + id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
inputStream.close();
|
||||
|
@ -21,8 +21,12 @@ package com.sk89q.worldedit.extent.clipboard.io;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.sk89q.jnbt.ByteArrayTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.DoubleTag;
|
||||
import com.sk89q.jnbt.FloatTag;
|
||||
import com.sk89q.jnbt.IntArrayTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
@ -30,9 +34,16 @@ import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.jnbt.ShortTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@ -41,12 +52,15 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Writes schematic files using the Sponge schematic format.
|
||||
*/
|
||||
public class SpongeSchematicWriter implements ClipboardWriter {
|
||||
|
||||
private static final int CURRENT_VERSION = 2;
|
||||
|
||||
private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE;
|
||||
private final NBTOutputStream outputStream;
|
||||
|
||||
@ -63,17 +77,17 @@ public class SpongeSchematicWriter implements ClipboardWriter {
|
||||
@Override
|
||||
public void write(Clipboard clipboard) throws IOException {
|
||||
// For now always write the latest version. Maybe provide support for earlier if more appear.
|
||||
outputStream.writeNamedTag("Schematic", new CompoundTag(write1(clipboard)));
|
||||
outputStream.writeNamedTag("Schematic", new CompoundTag(write2(clipboard)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a version 1 schematic file.
|
||||
* Writes a version 2 schematic file.
|
||||
*
|
||||
* @param clipboard The clipboard
|
||||
* @return The schematic map
|
||||
* @throws IOException If an error occurs
|
||||
*/
|
||||
private Map<String, Tag> write1(Clipboard clipboard) throws IOException {
|
||||
private Map<String, Tag> write2(Clipboard clipboard) throws IOException {
|
||||
Region region = clipboard.getRegion();
|
||||
BlockVector3 origin = clipboard.getOrigin();
|
||||
BlockVector3 min = region.getMinimumPoint();
|
||||
@ -93,7 +107,9 @@ public class SpongeSchematicWriter implements ClipboardWriter {
|
||||
}
|
||||
|
||||
Map<String, Tag> schematic = new HashMap<>();
|
||||
schematic.put("Version", new IntTag(1));
|
||||
schematic.put("Version", new IntTag(CURRENT_VERSION));
|
||||
schematic.put("DataVersion", new IntTag(
|
||||
WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion()));
|
||||
|
||||
Map<String, Tag> metadata = new HashMap<>();
|
||||
metadata.put("WEOffsetX", new IntTag(offset.getBlockX()));
|
||||
@ -129,10 +145,7 @@ public class SpongeSchematicWriter implements ClipboardWriter {
|
||||
BlockVector3 point = BlockVector3.at(x0, y0, z0);
|
||||
BaseBlock block = clipboard.getFullBlock(point);
|
||||
if (block.getNbtData() != null) {
|
||||
Map<String, Tag> values = new HashMap<>();
|
||||
for (Map.Entry<String, Tag> entry : block.getNbtData().getValue().entrySet()) {
|
||||
values.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
Map<String, Tag> values = new HashMap<>(block.getNbtData().getValue());
|
||||
|
||||
values.remove("id"); // Remove 'id' if it exists. We want 'Id'
|
||||
|
||||
@ -179,9 +192,101 @@ public class SpongeSchematicWriter implements ClipboardWriter {
|
||||
schematic.put("BlockData", new ByteArrayTag(buffer.toByteArray()));
|
||||
schematic.put("TileEntities", new ListTag(CompoundTag.class, tileEntities));
|
||||
|
||||
// version 2 stuff
|
||||
if (clipboard.hasBiomes()) {
|
||||
writeBiomes(clipboard, schematic);
|
||||
}
|
||||
|
||||
if (!clipboard.getEntities().isEmpty()) {
|
||||
writeEntities(clipboard, schematic);
|
||||
}
|
||||
|
||||
return schematic;
|
||||
}
|
||||
|
||||
private void writeBiomes(Clipboard clipboard, Map<String, Tag> schematic) {
|
||||
BlockVector3 min = clipboard.getMinimumPoint();
|
||||
int width = clipboard.getRegion().getWidth();
|
||||
int length = clipboard.getRegion().getLength();
|
||||
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * length);
|
||||
|
||||
int paletteMax = 0;
|
||||
Map<String, Integer> palette = new HashMap<>();
|
||||
|
||||
for (int z = 0; z < length; z++) {
|
||||
int z0 = min.getBlockZ() + z;
|
||||
for (int x = 0; x < width; x++) {
|
||||
int x0 = min.getBlockX() + x;
|
||||
BlockVector2 pt = BlockVector2.at(x0, z0);
|
||||
BiomeType biome = clipboard.getBiome(pt);
|
||||
|
||||
String biomeKey = biome.getId();
|
||||
int biomeId;
|
||||
if (palette.containsKey(biomeKey)) {
|
||||
biomeId = palette.get(biomeKey);
|
||||
} else {
|
||||
biomeId = paletteMax;
|
||||
palette.put(biomeKey, biomeId);
|
||||
paletteMax++;
|
||||
}
|
||||
|
||||
while ((biomeId & -128) != 0) {
|
||||
buffer.write(biomeId & 127 | 128);
|
||||
biomeId >>>= 7;
|
||||
}
|
||||
buffer.write(biomeId);
|
||||
}
|
||||
}
|
||||
|
||||
schematic.put("BiomePaletteMax", new IntTag(paletteMax));
|
||||
|
||||
Map<String, Tag> paletteTag = new HashMap<>();
|
||||
palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value)));
|
||||
|
||||
schematic.put("BiomePalette", new CompoundTag(paletteTag));
|
||||
schematic.put("BiomeData", new ByteArrayTag(buffer.toByteArray()));
|
||||
}
|
||||
|
||||
private void writeEntities(Clipboard clipboard, Map<String, Tag> schematic) {
|
||||
List<CompoundTag> entities = clipboard.getEntities().stream().map(e -> {
|
||||
BaseEntity state = e.getState();
|
||||
if (state == null) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Tag> values = Maps.newHashMap();
|
||||
CompoundTag rawData = state.getNbtData();
|
||||
if (rawData != null) {
|
||||
values.putAll(rawData.getValue());
|
||||
}
|
||||
values.remove("id");
|
||||
values.put("Id", new StringTag(state.getType().getId()));
|
||||
values.put("Pos", writeVector(e.getLocation().toVector()));
|
||||
values.put("Rotation", writeRotation(e.getLocation()));
|
||||
|
||||
return new CompoundTag(values);
|
||||
}).filter(e -> e != null).collect(Collectors.toList());
|
||||
if (entities.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
schematic.put("Entities", new ListTag(CompoundTag.class, entities));
|
||||
}
|
||||
|
||||
private Tag writeVector(Vector3 vector) {
|
||||
List<DoubleTag> list = new ArrayList<DoubleTag>();
|
||||
list.add(new DoubleTag(vector.getX()));
|
||||
list.add(new DoubleTag(vector.getY()));
|
||||
list.add(new DoubleTag(vector.getZ()));
|
||||
return new ListTag(DoubleTag.class, list);
|
||||
}
|
||||
|
||||
private Tag writeRotation(Location location) {
|
||||
List<FloatTag> list = new ArrayList<FloatTag>();
|
||||
list.add(new FloatTag(location.getYaw()));
|
||||
list.add(new FloatTag(location.getPitch()));
|
||||
return new ListTag(FloatTag.class, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
outputStream.close();
|
||||
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.extent.clipboard.io.legacycompat;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface EntityNBTCompatibilityHandler {
|
||||
boolean isAffectedEntity(EntityType type, CompoundTag entityTag);
|
||||
CompoundTag updateNBT(EntityType type, CompoundTag entityTag);
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.extent.clipboard.io.legacycompat;
|
||||
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.registry.LegacyMapper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler {
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> boolean isAffectedBlock(B block) {
|
||||
return block.getBlockType() == BlockTypes.FLOWER_POT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values) {
|
||||
Tag item = values.get("Item");
|
||||
if (item instanceof StringTag) {
|
||||
String id = ((StringTag) item).getValue();
|
||||
int data = 0;
|
||||
Tag dataTag = values.get("Data");
|
||||
if (dataTag instanceof IntTag) {
|
||||
data = ((IntTag) dataTag).getValue();
|
||||
}
|
||||
BlockState newState = convertLegacyBlockType(id, data);
|
||||
if (newState != null) {
|
||||
return (B) newState; // generics pls :\
|
||||
}
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
private BlockState convertLegacyBlockType(String id, int data) {
|
||||
int newId = 0;
|
||||
switch (id) {
|
||||
case "minecraft:red_flower":
|
||||
newId = 38; // now poppy
|
||||
break;
|
||||
case "minecraft:yellow_flower":
|
||||
newId = 37; // now dandelion
|
||||
break;
|
||||
case "minecraft:sapling":
|
||||
newId = 6; // oak_sapling
|
||||
break;
|
||||
case "minecraft:deadbush":
|
||||
case "minecraft:tallgrass":
|
||||
newId = 31; // dead_bush with fern and grass (not 32!)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
String plantedName = null;
|
||||
if (newId == 0) {
|
||||
plantedName = id.substring(10);
|
||||
} else {
|
||||
BlockState plantedWithData = LegacyMapper.getInstance().getBlockFromLegacy(newId, data);
|
||||
if (plantedWithData != null) {
|
||||
plantedName = plantedWithData.getBlockType().getId().substring(10); // remove "minecraft:"
|
||||
}
|
||||
}
|
||||
if (plantedName != null) {
|
||||
BlockType potAndPlanted = BlockTypes.get("minecraft:potted_" + plantedName);
|
||||
if (potAndPlanted != null) {
|
||||
return potAndPlanted.getDefaultState();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -26,5 +26,5 @@ import java.util.Map;
|
||||
|
||||
public interface NBTCompatibilityHandler {
|
||||
<B extends BlockStateHolder<B>> boolean isAffectedBlock(B block);
|
||||
<B extends BlockStateHolder<B>> void updateNBT(B block, Map<String, Tag> values);
|
||||
<B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values);
|
||||
}
|
||||
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.extent.clipboard.io.legacycompat;
|
||||
|
||||
import com.sk89q.jnbt.ByteTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.registry.state.IntegerProperty;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler {
|
||||
private static final IntegerProperty NoteProperty;
|
||||
|
||||
static {
|
||||
IntegerProperty temp;
|
||||
try {
|
||||
temp = (IntegerProperty) (Property<?>) BlockTypes.NOTE_BLOCK.getProperty("note");
|
||||
} catch (NullPointerException | IllegalArgumentException | ClassCastException e) {
|
||||
temp = null;
|
||||
}
|
||||
NoteProperty = temp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> boolean isAffectedBlock(B block) {
|
||||
return NoteProperty != null && block.getBlockType() == BlockTypes.NOTE_BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values) {
|
||||
// note that instrument was not stored (in state or nbt) previously.
|
||||
// it will be updated to the block below when it gets set into the world for the first time
|
||||
Tag noteTag = values.get("note");
|
||||
if (noteTag instanceof ByteTag) {
|
||||
Byte note = ((ByteTag) noteTag).getValue();
|
||||
if (note != null) {
|
||||
return block.with(NoteProperty, (int) note);
|
||||
}
|
||||
}
|
||||
return block;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.extent.clipboard.io.legacycompat;
|
||||
|
||||
import com.sk89q.jnbt.ByteTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.CompoundTagBuilder;
|
||||
import com.sk89q.worldedit.internal.helper.MCDirections;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
|
||||
public class Pre13HangingCompatibilityHandler implements EntityNBTCompatibilityHandler {
|
||||
|
||||
@Override
|
||||
public boolean isAffectedEntity(EntityType type, CompoundTag tag) {
|
||||
if (!type.getId().startsWith("minecraft:")) {
|
||||
return false;
|
||||
}
|
||||
boolean hasLegacyDirection = tag.containsKey("Dir") || tag.containsKey("Direction");
|
||||
boolean hasFacing = tag.containsKey("Facing");
|
||||
return hasLegacyDirection || hasFacing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag updateNBT(EntityType type, CompoundTag tag) {
|
||||
boolean hasLegacyDir = tag.containsKey("Dir");
|
||||
boolean hasLegacyDirection = tag.containsKey("Direction");
|
||||
boolean hasPre113Facing = tag.containsKey("Facing");
|
||||
Direction newDirection;
|
||||
if (hasLegacyDir) {
|
||||
newDirection = MCDirections.fromPre13Hanging(MCDirections.fromLegacyHanging((byte) tag.asInt("Dir")));
|
||||
} else if (hasLegacyDirection) {
|
||||
newDirection = MCDirections.fromPre13Hanging(tag.asInt("Direction"));
|
||||
} else if (hasPre113Facing) {
|
||||
newDirection = MCDirections.fromPre13Hanging(tag.asInt("Facing"));
|
||||
} else {
|
||||
return tag;
|
||||
}
|
||||
byte hangingByte = (byte) MCDirections.toHanging(newDirection);
|
||||
CompoundTagBuilder builder = tag.createBuilder();
|
||||
builder.putByte("Facing", hangingByte);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
@ -39,7 +39,7 @@ public class SignCompatibilityHandler implements NBTCompatibilityHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> void updateNBT(B block, Map<String, Tag> values) {
|
||||
public <B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
String key = "Text" + (i + 1);
|
||||
Tag value = values.get(key);
|
||||
@ -69,5 +69,6 @@ public class SignCompatibilityHandler implements NBTCompatibilityHandler {
|
||||
values.put("Text" + (i + 1), new StringTag(jsonTextObject.toString()));
|
||||
}
|
||||
}
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.extent.clipboard.io.legacycompat;
|
||||
|
||||
import com.sk89q.jnbt.ByteTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.registry.state.DirectionalProperty;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class SkullBlockCompatibilityHandler implements NBTCompatibilityHandler {
|
||||
|
||||
private static final DirectionalProperty FacingProperty;
|
||||
|
||||
static {
|
||||
DirectionalProperty tempFacing;
|
||||
try {
|
||||
tempFacing = (DirectionalProperty) (Property<?>) BlockTypes.SKELETON_WALL_SKULL.getProperty("facing");
|
||||
} catch (NullPointerException | IllegalArgumentException | ClassCastException e) {
|
||||
tempFacing = null;
|
||||
}
|
||||
FacingProperty = tempFacing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> boolean isAffectedBlock(B block) {
|
||||
return block.getBlockType() == BlockTypes.SKELETON_SKULL
|
||||
|| block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values) {
|
||||
boolean isWall = block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL;
|
||||
Tag typeTag = values.get("SkullType");
|
||||
if (typeTag instanceof ByteTag) {
|
||||
String skullType = convertSkullType(((ByteTag) typeTag).getValue(), isWall);
|
||||
if (skullType != null) {
|
||||
BlockType type = BlockTypes.get("minecraft:" + skullType);
|
||||
if (type != null) {
|
||||
BlockState state = type.getDefaultState();
|
||||
if (isWall) {
|
||||
Property newProp = type.getProperty("facing");
|
||||
state = state.with(newProp, block.getState(FacingProperty));
|
||||
} else {
|
||||
Tag rotTag = values.get("Rot");
|
||||
if (rotTag instanceof ByteTag) {
|
||||
Property newProp = type.getProperty("rotation");
|
||||
state = state.with(newProp, (int) ((ByteTag) rotTag).getValue());
|
||||
}
|
||||
}
|
||||
values.remove("SkullType");
|
||||
values.remove("Rot");
|
||||
return (B) state;
|
||||
}
|
||||
}
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
private String convertSkullType(Byte oldType, boolean isWall) {
|
||||
switch (oldType) {
|
||||
case 0:
|
||||
return isWall ? "skeleton_wall_skull" : "skeleton_skull";
|
||||
case 1:
|
||||
return isWall ? "wither_skeleton_wall_skull" : "wither_skeleton_skull";
|
||||
case 2:
|
||||
return isWall ? "zombie_wall_head" : "zombie_head";
|
||||
case 3:
|
||||
return isWall ? "player_wall_head" : "player_head";
|
||||
case 4:
|
||||
return isWall ? "creeper_wall_head" : "creeper_head";
|
||||
case 5:
|
||||
return isWall ? "dragon_wall_head" : "dragon_head";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.function.biome;
|
||||
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.FlatRegionFunction;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Copies the biome from one extent to another.
|
||||
*/
|
||||
public class ExtentBiomeCopy implements FlatRegionFunction {
|
||||
|
||||
private final Extent source;
|
||||
private final Extent destination;
|
||||
private final BlockVector2 from;
|
||||
private final BlockVector2 to;
|
||||
private final Transform transform;
|
||||
|
||||
/**
|
||||
* Make a new biome copy.
|
||||
*
|
||||
* @param source the source extent
|
||||
* @param from the source offset
|
||||
* @param destination the destination extent
|
||||
* @param to the destination offset
|
||||
* @param transform a transform to apply to positions (after source offset, before destination offset)
|
||||
*/
|
||||
public ExtentBiomeCopy(Extent source, BlockVector2 from, Extent destination, BlockVector2 to, Transform transform) {
|
||||
checkNotNull(source);
|
||||
checkNotNull(from);
|
||||
checkNotNull(destination);
|
||||
checkNotNull(to);
|
||||
checkNotNull(transform);
|
||||
this.source = source;
|
||||
this.from = from;
|
||||
this.destination = destination;
|
||||
this.to = to;
|
||||
this.transform = transform;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(BlockVector2 position) throws WorldEditException {
|
||||
BiomeType biome = source.getBiome(position);
|
||||
BlockVector2 orig = position.subtract(from);
|
||||
BlockVector2 transformed = transform.apply(orig.toVector3(0)).toVector2().toBlockPoint();
|
||||
|
||||
return destination.setBiome(transformed.add(to), biome);
|
||||
}
|
||||
}
|
@ -130,8 +130,6 @@ public class ExtentEntityCopy implements EntityFunction {
|
||||
if (tag != null) {
|
||||
// Handle hanging entities (paintings, item frames, etc.)
|
||||
boolean hasTilePosition = tag.containsKey("TileX") && tag.containsKey("TileY") && tag.containsKey("TileZ");
|
||||
boolean hasDirection = tag.containsKey("Direction");
|
||||
boolean hasLegacyDirection = tag.containsKey("Dir");
|
||||
boolean hasFacing = tag.containsKey("Facing");
|
||||
|
||||
if (hasTilePosition) {
|
||||
@ -143,27 +141,15 @@ public class ExtentEntityCopy implements EntityFunction {
|
||||
.putInt("TileY", newTilePosition.getBlockY())
|
||||
.putInt("TileZ", newTilePosition.getBlockZ());
|
||||
|
||||
if (hasDirection || hasLegacyDirection || hasFacing) {
|
||||
int d;
|
||||
if (hasDirection) {
|
||||
d = tag.asInt("Direction");
|
||||
} else if (hasLegacyDirection) {
|
||||
d = MCDirections.fromLegacyHanging((byte) tag.asInt("Dir"));
|
||||
} else {
|
||||
d = tag.asInt("Facing");
|
||||
}
|
||||
|
||||
Direction direction = MCDirections.fromHanging(d);
|
||||
if (hasFacing) {
|
||||
Direction direction = MCDirections.fromHanging(tag.asInt("Facing"));
|
||||
|
||||
if (direction != null) {
|
||||
Vector3 vector = transform.apply(direction.toVector()).subtract(transform.apply(Vector3.ZERO)).normalize();
|
||||
Direction newDirection = Direction.findClosest(vector, Flag.CARDINAL);
|
||||
|
||||
if (newDirection != null) {
|
||||
byte hangingByte = (byte) MCDirections.toHanging(newDirection);
|
||||
builder.putByte("Direction", hangingByte);
|
||||
builder.putByte("Facing", hangingByte);
|
||||
builder.putByte("Dir", MCDirections.toLegacyHanging(MCDirections.toHanging(newDirection)));
|
||||
builder.putByte("Facing", (byte) MCDirections.toHanging(newDirection));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,17 +28,23 @@ import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.entity.metadata.EntityProperties;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.CombinedRegionFunction;
|
||||
import com.sk89q.worldedit.function.FlatRegionFunction;
|
||||
import com.sk89q.worldedit.function.FlatRegionMaskingFilter;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.RegionMaskingFilter;
|
||||
import com.sk89q.worldedit.function.biome.ExtentBiomeCopy;
|
||||
import com.sk89q.worldedit.function.block.ExtentBlockCopy;
|
||||
import com.sk89q.worldedit.function.entity.ExtentEntityCopy;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.Mask2D;
|
||||
import com.sk89q.worldedit.function.mask.Masks;
|
||||
import com.sk89q.worldedit.function.visitor.EntityVisitor;
|
||||
import com.sk89q.worldedit.function.visitor.FlatRegionVisitor;
|
||||
import com.sk89q.worldedit.function.visitor.RegionVisitor;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.transform.Identity;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.regions.FlatRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
import java.util.List;
|
||||
@ -61,11 +67,18 @@ public class ForwardExtentCopy implements Operation {
|
||||
private Mask sourceMask = Masks.alwaysTrue();
|
||||
private boolean removingEntities;
|
||||
private boolean copyingEntities = true; // default to true for backwards compatibility, sort of
|
||||
private boolean copyingBiomes;
|
||||
private RegionFunction sourceFunction = null;
|
||||
private Transform transform = new Identity();
|
||||
private Transform currentTransform = null;
|
||||
|
||||
private RegionVisitor lastVisitor;
|
||||
private int affected;
|
||||
private FlatRegionVisitor lastBiomeVisitor;
|
||||
private EntityVisitor lastEntityVisitor;
|
||||
|
||||
private int affectedBlocks;
|
||||
private int affectedBiomeCols;
|
||||
private int affectedEntities;
|
||||
|
||||
/**
|
||||
* Create a new copy using the region's lowest minimum point as the
|
||||
@ -222,21 +235,50 @@ public class ForwardExtentCopy implements Operation {
|
||||
this.removingEntities = removingEntities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether biomes should be copied along with blocks.
|
||||
*
|
||||
* @return true if copying biomes
|
||||
*/
|
||||
public boolean isCopyingBiomes() {
|
||||
return copyingBiomes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether biomes should be copies along with blocks.
|
||||
*
|
||||
* @param copyingBiomes true if copying
|
||||
*/
|
||||
public void setCopyingBiomes(boolean copyingBiomes) {
|
||||
if (copyingBiomes && !(region instanceof FlatRegion)) {
|
||||
throw new UnsupportedOperationException("Can't copy biomes from region that doesn't implement FlatRegion");
|
||||
}
|
||||
this.copyingBiomes = copyingBiomes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of affected objects.
|
||||
*
|
||||
* @return the number of affected
|
||||
*/
|
||||
public int getAffected() {
|
||||
return affected;
|
||||
return affectedBlocks + affectedBiomeCols + affectedEntities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation resume(RunContext run) throws WorldEditException {
|
||||
if (lastVisitor != null) {
|
||||
affected += lastVisitor.getAffected();
|
||||
affectedBlocks += lastVisitor.getAffected();
|
||||
lastVisitor = null;
|
||||
}
|
||||
if (lastBiomeVisitor != null) {
|
||||
affectedBiomeCols += lastBiomeVisitor.getAffected();
|
||||
lastBiomeVisitor = null;
|
||||
}
|
||||
if (lastEntityVisitor != null) {
|
||||
affectedEntities += lastEntityVisitor.getAffected();
|
||||
lastEntityVisitor = null;
|
||||
}
|
||||
|
||||
if (repetitions > 0) {
|
||||
repetitions--;
|
||||
@ -254,6 +296,23 @@ public class ForwardExtentCopy implements Operation {
|
||||
|
||||
lastVisitor = blockVisitor;
|
||||
|
||||
if (!copyingBiomes && !copyingEntities) {
|
||||
return new DelegateOperation(this, blockVisitor);
|
||||
}
|
||||
|
||||
List<Operation> ops = Lists.newArrayList(blockVisitor);
|
||||
|
||||
if (copyingBiomes && region instanceof FlatRegion) { // double-check here even though we checked before
|
||||
ExtentBiomeCopy biomeCopy = new ExtentBiomeCopy(source, from.toBlockVector2(),
|
||||
destination, to.toBlockVector2(), currentTransform);
|
||||
Mask2D biomeMask = sourceMask.toMask2D();
|
||||
FlatRegionFunction biomeFunction = biomeMask == null ? biomeCopy
|
||||
: new FlatRegionMaskingFilter(biomeMask, biomeCopy);
|
||||
FlatRegionVisitor biomeVisitor = new FlatRegionVisitor(((FlatRegion) region), biomeFunction);
|
||||
ops.add(biomeVisitor);
|
||||
lastBiomeVisitor = biomeVisitor;
|
||||
}
|
||||
|
||||
if (copyingEntities) {
|
||||
ExtentEntityCopy entityCopy = new ExtentEntityCopy(from.toVector3(), destination, to.toVector3(), currentTransform);
|
||||
entityCopy.setRemoving(removingEntities);
|
||||
@ -263,10 +322,11 @@ public class ForwardExtentCopy implements Operation {
|
||||
return properties != null && !properties.isPasteable();
|
||||
});
|
||||
EntityVisitor entityVisitor = new EntityVisitor(entities.iterator(), entityCopy);
|
||||
return new DelegateOperation(this, new OperationQueue(blockVisitor, entityVisitor));
|
||||
} else {
|
||||
return new DelegateOperation(this, blockVisitor);
|
||||
ops.add(entityVisitor);
|
||||
lastEntityVisitor = entityVisitor;
|
||||
}
|
||||
|
||||
return new DelegateOperation(this, new OperationQueue(ops));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@ -278,6 +338,24 @@ public class ForwardExtentCopy implements Operation {
|
||||
|
||||
@Override
|
||||
public void addStatusMessages(List<String> messages) {
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append(affectedBlocks).append(" block(s)");
|
||||
if (affectedBiomeCols > 0) {
|
||||
if (affectedEntities > 0) {
|
||||
msg.append(", ");
|
||||
} else {
|
||||
msg.append(" and ");
|
||||
}
|
||||
msg.append(affectedBiomeCols).append(" biome(s)");
|
||||
}
|
||||
if (affectedEntities > 0) {
|
||||
if (affectedBiomeCols > 0) {
|
||||
msg.append(",");
|
||||
}
|
||||
msg.append(" and ").append(affectedEntities).append(" entities(s)");
|
||||
}
|
||||
msg.append(" affected.");
|
||||
messages.add(msg.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,6 +30,44 @@ public final class MCDirections {
|
||||
}
|
||||
|
||||
public static Direction fromHanging(int i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return Direction.DOWN;
|
||||
case 1:
|
||||
return Direction.UP;
|
||||
case 2:
|
||||
return Direction.NORTH;
|
||||
case 3:
|
||||
return Direction.SOUTH;
|
||||
case 4:
|
||||
return Direction.WEST;
|
||||
case 5:
|
||||
return Direction.EAST;
|
||||
default:
|
||||
return Direction.DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
public static int toHanging(Direction direction) {
|
||||
switch (direction) {
|
||||
case DOWN:
|
||||
return 0;
|
||||
case UP:
|
||||
return 1;
|
||||
case NORTH:
|
||||
return 2;
|
||||
case SOUTH:
|
||||
return 3;
|
||||
case WEST:
|
||||
return 4;
|
||||
case EAST:
|
||||
return 5;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static Direction fromPre13Hanging(int i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return Direction.SOUTH;
|
||||
@ -44,21 +82,6 @@ public final class MCDirections {
|
||||
}
|
||||
}
|
||||
|
||||
public static int toHanging(Direction direction) {
|
||||
switch (direction) {
|
||||
case SOUTH:
|
||||
return 0;
|
||||
case WEST:
|
||||
return 1;
|
||||
case NORTH:
|
||||
return 2;
|
||||
case EAST:
|
||||
return 3;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static int fromLegacyHanging(byte i) {
|
||||
switch (i) {
|
||||
case 0: return 2;
|
||||
@ -68,15 +91,6 @@ public final class MCDirections {
|
||||
}
|
||||
}
|
||||
|
||||
public static byte toLegacyHanging(int i) {
|
||||
switch (i) {
|
||||
case 0: return (byte) 2;
|
||||
case 1: return (byte) 1;
|
||||
case 2: return (byte) 0;
|
||||
default: return (byte) 3;
|
||||
}
|
||||
}
|
||||
|
||||
public static Direction fromRotation(int i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
|
@ -25,6 +25,9 @@ import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
|
||||
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.MaskIntersection;
|
||||
import com.sk89q.worldedit.function.mask.Masks;
|
||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
@ -39,8 +42,12 @@ public class PasteBuilder {
|
||||
private final Transform transform;
|
||||
private final Extent targetExtent;
|
||||
|
||||
private Mask sourceMask = Masks.alwaysTrue();
|
||||
|
||||
private BlockVector3 to = BlockVector3.ZERO;
|
||||
private boolean ignoreAirBlocks;
|
||||
private boolean copyEntities = true; // default because it used to be this way
|
||||
private boolean copyBiomes;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
@ -67,6 +74,23 @@ public class PasteBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a custom mask of blocks to ignore from the source.
|
||||
* This provides a more flexible alternative to {@link #ignoreAirBlocks(boolean)}, for example
|
||||
* one might want to ignore structure void if copying a Minecraft Structure, etc.
|
||||
*
|
||||
* @param sourceMask
|
||||
* @return this builder instance
|
||||
*/
|
||||
public PasteBuilder maskSource(Mask sourceMask) {
|
||||
if (sourceMask == null) {
|
||||
this.sourceMask = Masks.alwaysTrue();
|
||||
return this;
|
||||
}
|
||||
this.sourceMask = sourceMask;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether air blocks in the source are skipped over when pasting.
|
||||
*
|
||||
@ -77,6 +101,29 @@ public class PasteBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the copy should include source entities.
|
||||
* Note that this is true by default for legacy reasons.
|
||||
*
|
||||
* @param copyEntities
|
||||
* @return this builder instance
|
||||
*/
|
||||
public PasteBuilder copyEntities(boolean copyEntities) {
|
||||
this.copyEntities = copyEntities;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the copy should include source biomes (if available).
|
||||
*
|
||||
* @param copyBiomes
|
||||
* @return this builder instance
|
||||
*/
|
||||
public PasteBuilder copyBiomes(boolean copyBiomes) {
|
||||
this.copyBiomes = copyBiomes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the operation.
|
||||
*
|
||||
@ -87,8 +134,13 @@ public class PasteBuilder {
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(extent, clipboard.getRegion(), clipboard.getOrigin(), targetExtent, to);
|
||||
copy.setTransform(transform);
|
||||
if (ignoreAirBlocks) {
|
||||
copy.setSourceMask(new ExistingBlockMask(clipboard));
|
||||
copy.setSourceMask(sourceMask == Masks.alwaysTrue() ? new ExistingBlockMask(clipboard)
|
||||
: new MaskIntersection(sourceMask, new ExistingBlockMask(clipboard)));
|
||||
} else {
|
||||
copy.setSourceMask(sourceMask);
|
||||
}
|
||||
copy.setCopyingEntities(copyEntities);
|
||||
copy.setCopyingBiomes(copyBiomes && clipboard.hasBiomes());
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ public final class NBTConversions {
|
||||
return new Location(
|
||||
extent,
|
||||
positionTag.asDouble(0), positionTag.asDouble(1), positionTag.asDouble(2),
|
||||
(float) directionTag.asDouble(0), (float) directionTag.asDouble(1));
|
||||
directionTag.getFloat(0), directionTag.getFloat(1));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -69,6 +69,12 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform {
|
||||
return ForgeRegistries.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataVersion() {
|
||||
// TODO switch to SharedConstants in 1.14
|
||||
return 1631;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidMobType(String type) {
|
||||
return net.minecraftforge.registries.ForgeRegistries.ENTITIES.containsKey(new ResourceLocation(type));
|
||||
|
@ -73,6 +73,12 @@ class SpongePlatform extends AbstractPlatform implements MultiUserPlatform {
|
||||
return SpongeRegistries.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataVersion() {
|
||||
// TODO add to adapter - org.spongepowered.common.data.util.DataUtil#MINECRAFT_DATA_VERSION
|
||||
return 1631;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidMobType(String type) {
|
||||
return Sponge.getRegistry().getType(EntityType.class, type).isPresent();
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren