Feature/propagate diff and object cleanup (#1190)

* Feature/main/propagate diff annotations (#1187)

* 25% done

* More work

* More work

* 50%

* More work

* 75%

* 100% & cleanup

* Update adapters

* Squish squash, applesauce

commit 275ba9bd84
Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Date:   Sat Jul 17 01:10:20 2021 +0200

    Update dependency com.comphenix.protocol:ProtocolLib to v4.7.0 (#1173)

    Co-authored-by: Renovate Bot <bot@renovateapp.com>

commit 9fd8984804
Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Date:   Sat Jul 17 01:09:29 2021 +0200

    Update dependency org.checkerframework:checker-qual to v3.16.0 (#1184)

    Co-authored-by: Renovate Bot <bot@renovateapp.com>

commit 861fb45e5c
Author: dordsor21 <dordsor21@gmail.com>
Date:   Fri Jul 16 19:07:02 2021 +0100

    Fix #1075

commit 420c45a29a
Author: dordsor21 <dordsor21@gmail.com>
Date:   Fri Jul 16 18:48:21 2021 +0100

    Entity removal should be on the main thread as we're just passing through rather than doing chunk operations
     - Fixes #1164
     - Not working: butcher/remove history

commit 4d4db7dcd0
Author: SirYwell <hannesgreule@outlook.de>
Date:   Fri Jul 16 17:52:44 2021 +0200

    Make sure leaves category is loaded for heightmaps (fixes #1176)

commit c98f6e4f37
Author: dordsor21 <dordsor21@gmail.com>
Date:   Fri Jul 16 10:44:52 2021 +0100

    Do not allow generation commands to generate outside selection

commit 2485f5eccc
Author: dordsor21 <dordsor21@gmail.com>
Date:   Fri Jul 16 10:43:15 2021 +0100

    EditSession needs to override some Extent methods to ensure block changes are correctly set through the various extents
    Fixes #1152

commit d9418ec8ae
Author: dordsor21 <dordsor21@gmail.com>
Date:   Fri Jul 16 09:52:44 2021 +0100

    Undo part of 41073bb1a0
    Fixes #1178

* Update Upstream

fb1fb84 Fixed typo and grammar

* We don't support custom heights yet

* Casing inconsistency

* Address a few comments

* Address comments

* Don't refactor to AP classpath

* Document annotation style

* Refactoring & shade cleanup

* Address a few comments

* More work

* Resolve comments not being resolved yet

* Feature/main/propagate diff annotations (#1187) (#1194)

* Remove beta package, fix history packages, move classes out of object package

* Resolve comments not being resolved yet

* Remove beta package, fix history packages, move classes out of object package

Co-authored-by: NotMyFault <mc.cache@web.de>

* brushes should be under brush

* More refactoring
 - Filters/processors should be in the same place and are related to extents
 - Transforms are in `extent.transform` in upstream

* Move history classes under history

* Update adapters

Co-authored-by: dordsor21 <dordsor21@gmail.com>
This commit is contained in:
NotMyFault
2021-07-23 17:48:51 +02:00
committed by GitHub
parent ad102ab7a9
commit 50ab8ad5c7
799 changed files with 4916 additions and 10589 deletions

View File

@ -19,11 +19,11 @@
package com.sk89q.worldedit.extent;
import com.fastasyncworldedit.core.beta.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.object.HistoryExtent;
import com.fastasyncworldedit.core.object.changeset.AbstractChangeSet;
import com.fastasyncworldedit.core.object.exception.FaweException;
import com.fastasyncworldedit.core.extent.HistoryExtent;
import com.fastasyncworldedit.core.history.changeset.AbstractChangeSet;
import com.fastasyncworldedit.core.internal.exception.FaweException;
import com.fastasyncworldedit.core.util.ExtentTraverser;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEditException;
@ -53,12 +53,15 @@ import static org.apache.logging.log4j.LogManager.getLogger;
/**
* A base class for {@link Extent}s that merely passes extents onto another.
*/
//FAWE start - made none abstract
public class AbstractDelegateExtent implements Extent {
//FAWE end
private static final Logger LOGGER = LogManagerCompat.getLogger();
//Not safe for public usage
//FAWE start - made public: Not safe for public usage
public Extent extent;
//FAWE end
/**
* Create a new instance.
@ -81,7 +84,9 @@ public class AbstractDelegateExtent implements Extent {
@Override
public BlockState getBlock(BlockVector3 position) {
//FAWE start - return coordinates
return extent.getBlock(position.getX(), position.getY(), position.getZ());
//FAWE end
}
@Override
@ -91,107 +96,23 @@ public class AbstractDelegateExtent implements Extent {
@Override
public BaseBlock getFullBlock(BlockVector3 position) {
//FAWE start - return coordinates
return extent.getFullBlock(position.getX(), position.getY(), position.getZ());
//FAWE end
}
//FAWE start
/*
Queue based methods
TODO NOT IMPLEMENTED: IQueueExtent and such need to implement these
*/
*/
//FAWE end
@Override
public BaseBlock getFullBlock(int x, int y, int z) {
//FAWE start - return coordinates
return extent.getFullBlock(x, y, z);
}
@Override
public BiomeType getBiomeType(int x, int y, int z) {
return extent.getBiomeType(x, y, z);
}
@Override
public BiomeType getBiome(BlockVector3 position) {
return extent.getBiome(position);
}
/*
History
*/
@Override
public int getEmmittedLight(int x, int y, int z) {
return extent.getEmmittedLight(x, y, z);
}
@Override
public int getSkyLight(int x, int y, int z) {
return extent.getSkyLight(x, y, z);
}
@Override
public int getBrightness(int x, int y, int z) {
return extent.getBrightness(x, y, z);
}
public void setChangeSet(AbstractChangeSet changeSet) {
if (extent instanceof HistoryExtent) {
HistoryExtent history = ((HistoryExtent) extent);
if (changeSet == null) {
new ExtentTraverser(this).setNext(history.getExtent());
} else {
history.setChangeSet(changeSet);
}
} else if (extent instanceof AbstractDelegateExtent) {
((AbstractDelegateExtent) extent).setChangeSet(changeSet);
} else if (changeSet != null) {
new ExtentTraverser<>(this).setNext(new HistoryExtent(extent, changeSet));
}
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block)
throws WorldEditException {
return extent.setBlock(position.getX(), position.getY(), position.getZ(), block);
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(int x, @Range(from = 0, to = 255) int y,
int z, T block) throws WorldEditException {
return extent.setBlock(x, y, z, block);
}
@Override
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
return setBlock(x, y, z, getBlock(x, y, z).toBaseBlock(tile));
}
@Override
public boolean fullySupports3DBiomes() {
return extent.fullySupports3DBiomes();
}
@Override
public boolean setBiome(int x, int y, int z, BiomeType biome) {
return extent.setBiome(x, y, z, biome);
}
@Override
public boolean setBiome(BlockVector3 position, BiomeType biome) {
return extent.setBiome(position.getX(), position.getY(), position.getZ(), biome);
}
@Override
public void setBlockLight(int x, int y, int z, int value) {
extent.setSkyLight(x, y, z, value);
}
@Override
public void setSkyLight(int x, int y, int z, int value) {
extent.setSkyLight(x, y, z, value);
}
@Override
public String toString() {
return super.toString() + ":" + (extent == this ? "" : extent.toString());
//FAWE end
}
@Override
@ -220,6 +141,28 @@ public class AbstractDelegateExtent implements Extent {
return extent.createEntity(location, entity);
}
@Override
@Nullable
public Operation commit() {
Operation ours = commitBefore();
Operation other = null;
//FAWE start - implement extent
if (extent != this) {
other = extent.commit();
}
//FAWE end
if (ours != null && other != null) {
return new OperationQueue(ours, other);
} else if (ours != null) {
return ours;
} else if (other != null) {
return other;
} else {
return null;
}
}
//FAWE start
@Override
public void removeEntity(int x, int y, int z, UUID uuid) {
extent.removeEntity(x, y, z, uuid);
@ -256,25 +199,6 @@ public class AbstractDelegateExtent implements Extent {
}
}
@Override
@Nullable
public Operation commit() {
Operation ours = commitBefore();
Operation other = null;
if (extent != this) {
other = extent.commit();
}
if (ours != null && other != null) {
return new OperationQueue(ours, other);
} else if (ours != null) {
return ours;
} else if (other != null) {
return other;
} else {
return null;
}
}
@Override
public int getMaxY() {
return extent.getMaxY();
@ -343,4 +267,95 @@ public class AbstractDelegateExtent implements Extent {
protected Operation commitBefore() {
return null;
}
@Override
public BiomeType getBiomeType(int x, int y, int z) {
return extent.getBiomeType(x, y, z);
}
@Override
public BiomeType getBiome(BlockVector3 position) {
return extent.getBiome(position);
}
/*
History
*/
@Override
public int getEmittedLight(int x, int y, int z) {
return extent.getEmittedLight(x, y, z);
}
@Override
public int getSkyLight(int x, int y, int z) {
return extent.getSkyLight(x, y, z);
}
@Override
public int getBrightness(int x, int y, int z) {
return extent.getBrightness(x, y, z);
}
public void setChangeSet(AbstractChangeSet changeSet) {
if (extent instanceof HistoryExtent) {
HistoryExtent history = ((HistoryExtent) extent);
if (changeSet == null) {
new ExtentTraverser(this).setNext(history.getExtent());
} else {
history.setChangeSet(changeSet);
}
} else if (extent instanceof AbstractDelegateExtent) {
((AbstractDelegateExtent) extent).setChangeSet(changeSet);
} else if (changeSet != null) {
new ExtentTraverser<>(this).setNext(new HistoryExtent(extent, changeSet));
}
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block)
throws WorldEditException {
return extent.setBlock(position.getX(), position.getY(), position.getZ(), block);
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(int x, @Range(from = 0, to = 255) int y,
int z, T block) throws WorldEditException {
return extent.setBlock(x, y, z, block);
}
@Override
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
return setBlock(x, y, z, getBlock(x, y, z).toBaseBlock(tile));
}
@Override
public boolean fullySupports3DBiomes() {
return extent.fullySupports3DBiomes();
}
@Override
public boolean setBiome(int x, int y, int z, BiomeType biome) {
return extent.setBiome(x, y, z, biome);
}
@Override
public boolean setBiome(BlockVector3 position, BiomeType biome) {
return extent.setBiome(position.getX(), position.getY(), position.getZ(), biome);
}
@Override
public void setBlockLight(int x, int y, int z, int value) {
extent.setSkyLight(x, y, z, value);
}
@Override
public void setSkyLight(int x, int y, int z, int value) {
extent.setSkyLight(x, y, z, value);
}
@Override
public String toString() {
return super.toString() + ":" + (extent == this ? "" : extent.toString());
}
//FAWE end
}

View File

@ -20,15 +20,15 @@
package com.sk89q.worldedit.extent;
import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.beta.Filter;
import com.fastasyncworldedit.core.beta.IBatchProcessor;
import com.fastasyncworldedit.core.beta.implementation.filter.block.ExtentFilterBlock;
import com.fastasyncworldedit.core.beta.implementation.processors.ProcessorScope;
import com.fastasyncworldedit.core.queue.Filter;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.extent.filter.block.ExtentFilterBlock;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.object.changeset.AbstractChangeSet;
import com.fastasyncworldedit.core.object.clipboard.WorldCopyClipboard;
import com.fastasyncworldedit.core.object.exception.FaweException;
import com.fastasyncworldedit.core.object.extent.NullExtent;
import com.fastasyncworldedit.core.history.changeset.AbstractChangeSet;
import com.fastasyncworldedit.core.extent.clipboard.WorldCopyClipboard;
import com.fastasyncworldedit.core.internal.exception.FaweException;
import com.fastasyncworldedit.core.extent.NullExtent;
import com.fastasyncworldedit.core.util.ExtentTraverser;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException;
@ -37,11 +37,11 @@ import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.RegionMaskingFilter;
import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.function.generator.CavesGen;
import com.sk89q.worldedit.function.generator.GenBase;
import com.sk89q.worldedit.function.generator.OreGen;
import com.sk89q.worldedit.function.generator.Resource;
import com.sk89q.worldedit.function.generator.SchemGen;
import com.fastasyncworldedit.core.function.generator.CavesGen;
import com.fastasyncworldedit.core.function.generator.GenBase;
import com.fastasyncworldedit.core.function.generator.OreGen;
import com.fastasyncworldedit.core.function.generator.Resource;
import com.fastasyncworldedit.core.function.generator.SchemGen;
import com.sk89q.worldedit.function.mask.BlockMask;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
@ -53,11 +53,11 @@ import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.MathUtils;
import com.sk89q.worldedit.math.MutableBlockVector3;
import com.fastasyncworldedit.core.math.MutableBlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.registry.state.PropertyGroup;
import com.fastasyncworldedit.core.registry.state.PropertyGroup;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.Location;
@ -147,6 +147,7 @@ public interface Extent extends InputExtent, OutputExtent {
return null;
}
//FAWE start
/**
* Create an entity at the given location.
*
@ -741,4 +742,5 @@ public interface Extent extends InputExtent, OutputExtent {
}
return filter;
}
//FAWE end
}

View File

@ -19,13 +19,13 @@
package com.sk89q.worldedit.extent;
import com.fastasyncworldedit.core.beta.implementation.lighting.HeightMapType;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.util.DeprecationUtil;
import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.MutableBlockVector3;
import com.fastasyncworldedit.core.math.MutableBlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
@ -53,6 +53,7 @@ public interface InputExtent {
return getBlock(position.getX(), position.getY(), position.getZ());
}
//FAWE start
default BlockState getBlock(int x, int y, int z) {
return getBlock(MutableBlockVector3.get(x, y, z));
}
@ -70,6 +71,7 @@ public interface InputExtent {
default BaseBlock getFullBlock(int x, int y, int z) {
return getFullBlock(MutableBlockVector3.get(x, y, z));
}
//FAWE end
/**
* Get the biome at the given location.
@ -114,17 +116,18 @@ public interface InputExtent {
return getBiome(position.toBlockVector2());
}
//FAWE start
/**
* Get the light level at the given location.
*
* @param position location
* @return the light level at the location
*/
default int getEmmittedLight(BlockVector3 position) {
return getEmmittedLight(position.getX(), position.getY(), position.getZ());
default int getEmittedLight(BlockVector3 position) {
return getEmittedLight(position.getX(), position.getY(), position.getZ());
}
default int getEmmittedLight(int x, int y, int z) {
default int getEmittedLight(int x, int y, int z) {
return 0;
}
@ -161,4 +164,5 @@ public interface InputExtent {
default int[] getHeightMap(HeightMapType type) {
return new int[256];
}
//FAWE end
}

View File

@ -20,15 +20,15 @@
package com.sk89q.worldedit.extent;
import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.beta.Filter;
import com.fastasyncworldedit.core.beta.IBatchProcessor;
import com.fastasyncworldedit.core.beta.IChunk;
import com.fastasyncworldedit.core.beta.IChunkGet;
import com.fastasyncworldedit.core.beta.IChunkSet;
import com.fastasyncworldedit.core.beta.implementation.filter.block.CharFilterBlock;
import com.fastasyncworldedit.core.beta.implementation.filter.block.ChunkFilterBlock;
import com.fastasyncworldedit.core.beta.implementation.filter.block.FilterBlock;
import com.fastasyncworldedit.core.beta.implementation.processors.ProcessorScope;
import com.fastasyncworldedit.core.queue.Filter;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunk;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.extent.filter.block.CharFilterBlock;
import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
import com.google.common.cache.LoadingCache;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.function.mask.Mask;
@ -47,7 +47,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class MaskingExtent extends AbstractDelegateExtent implements IBatchProcessor, Filter {
private Mask mask;
//FAWE start
private final LoadingCache<Long, ChunkFilterBlock> threadIdToFilter;
//FAWE end
/**
* Create a new instance.
@ -59,15 +61,19 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
super(extent);
checkNotNull(mask);
this.mask = mask;
//FAWE start
this.threadIdToFilter = FaweCache.IMP.createCache(() -> new CharFilterBlock(getExtent()));
//FAWE end
}
//FAWE start
private MaskingExtent(Extent extent, Mask mask, LoadingCache<Long, ChunkFilterBlock> threadIdToFilter) {
super(extent);
checkNotNull(mask);
this.mask = mask;
this.threadIdToFilter = threadIdToFilter;
}
//FAWE end
/**
* Get the mask.
@ -88,6 +94,7 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
this.mask = mask;
}
//FAWE start
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
return this.mask.test(location) && super.setBlock(location, block);
@ -134,4 +141,5 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
public ProcessorScope getScope() {
return ProcessorScope.REMOVING_BLOCKS;
}
//FAWE end
}

View File

@ -91,12 +91,6 @@ public class NullExtent implements Extent {
return false;
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T block)
throws WorldEditException {
return false;
}
@Override
public boolean fullySupports3DBiomes() {
return false;
@ -112,11 +106,19 @@ public class NullExtent implements Extent {
return false;
}
//FAWE start
@Override
public boolean setBiome(int x, int y, int z, BiomeType biome) {
return false;
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T block)
throws WorldEditException {
return false;
}
//FAWE end
@Nullable
@Override
public Operation commit() {

View File

@ -19,7 +19,7 @@
package com.sk89q.worldedit.extent;
import com.fastasyncworldedit.core.beta.implementation.lighting.HeightMapType;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.function.operation.Operation;
@ -27,7 +27,7 @@ import com.sk89q.worldedit.internal.util.DeprecationUtil;
import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.MutableBlockVector3;
import com.fastasyncworldedit.core.math.MutableBlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockStateHolder;
@ -112,6 +112,7 @@ public interface OutputExtent {
return setBiome(MutableBlockVector3.get(x, y, z), biome);
}
//FAWE start
/**
* Set the biome.
*
@ -159,6 +160,7 @@ public interface OutputExtent {
default void setSkyLight(BlockVector3 position, int value) {
setSkyLight(position.getX(), position.getY(), position.getZ(), value);
}
//FAWE end
default void setSkyLight(int x, int y, int z, int value) {
}

View File

@ -1,244 +0,0 @@
package com.sk89q.worldedit.extent;
import com.fastasyncworldedit.core.beta.Filter;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.generator.GenBase;
import com.sk89q.worldedit.function.generator.Resource;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
public class PassthroughExtent extends AbstractDelegateExtent {
/**
* Create a new instance.
*
* @param extent the extent
*/
public PassthroughExtent(Extent extent) {
super(extent);
}
@Override
public boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullable Long seed) {
return getExtent().regenerateChunk(x, z, type, seed);
}
@Override
public int getHighestTerrainBlock(int x, int z, int minY, int maxY) {
return getExtent().getHighestTerrainBlock(x, z, minY, maxY);
}
@Override
public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) {
return getExtent().getHighestTerrainBlock(x, z, minY, maxY, filter);
}
@Override
public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
return getExtent().getNearestSurfaceLayer(x, z, y, minY, maxY);
}
@Override
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) {
return getExtent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir);
}
@Override
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
return getExtent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY);
}
@Override
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) {
return getExtent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax);
}
@Override
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) {
return getExtent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask);
}
@Override
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, boolean ignoreAir) {
return getExtent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir);
}
@Override
public void addCaves(Region region) throws WorldEditException {
getExtent().addCaves(region);
}
@Override
public void generate(Region region, GenBase gen) throws WorldEditException {
getExtent().generate(region, gen);
}
@Override
public void addSchems(Region region, Mask mask, List<ClipboardHolder> clipboards, int rarity, boolean rotate) throws WorldEditException {
getExtent().addSchems(region, mask, clipboards, rarity, rotate);
}
@Override
public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException {
getExtent().spawnResource(region, gen, rarity, frequency);
}
@Override
public boolean contains(BlockVector3 pt) {
return getExtent().contains(pt);
}
@Override
public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException {
getExtent().addOre(region, mask, material, size, frequency, rarity, minY, maxY);
}
@Override
public void addOres(Region region, Mask mask) throws WorldEditException {
getExtent().addOres(region, mask);
}
@Override
public List<Countable<BlockType>> getBlockDistribution(Region region) {
return getExtent().getBlockDistribution(region);
}
@Override
public List<Countable<BlockState>> getBlockDistributionWithData(Region region) {
return getExtent().getBlockDistributionWithData(region);
}
@Override
public Clipboard lazyCopy(Region region) {
return getExtent().lazyCopy(region);
}
@Override
public int countBlocks(Region region, Set<BaseBlock> searchBlocks) {
return getExtent().countBlocks(region, searchBlocks);
}
@Override
public int countBlocks(Region region, Mask searchMask) {
return getExtent().countBlocks(region, searchMask);
}
@Override
public <B extends BlockStateHolder<B>> int setBlocks(Region region, B block) throws MaxChangedBlocksException {
return getExtent().setBlocks(region, block);
}
@Override
public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException {
return getExtent().setBlocks(region, pattern);
}
@Override
public <B extends BlockStateHolder<B>> int replaceBlocks(Region region, Set<BaseBlock> filter, B replacement) throws MaxChangedBlocksException {
return getExtent().replaceBlocks(region, filter, replacement);
}
@Override
public int replaceBlocks(Region region, Set<BaseBlock> filter, Pattern pattern) throws MaxChangedBlocksException {
return getExtent().replaceBlocks(region, filter, pattern);
}
@Override
public int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException {
return getExtent().replaceBlocks(region, mask, pattern);
}
@Override
public int center(Region region, Pattern pattern) throws MaxChangedBlocksException {
return getExtent().center(region, pattern);
}
@Override
public int setBlocks(Set<BlockVector3> vset, Pattern pattern) {
return getExtent().setBlocks(vset, pattern);
}
@Override
public BlockState getBlock(BlockVector3 position) {
return getExtent().getBlock(position);
}
@Override
public BaseBlock getFullBlock(BlockVector3 position) {
return getExtent().getFullBlock(position);
}
@Override
@Deprecated
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block) throws WorldEditException {
return getExtent().setBlock(position, block);
}
@Override
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
return getExtent().setTile(x, y, z, tile);
}
@Override
public boolean setBiome(BlockVector3 position, BiomeType biome) {
return getExtent().setBiome(position, biome);
}
@Override
@Nullable
public Operation commit() {
return getExtent().commit();
}
@Override
public boolean cancel() {
return getExtent().cancel();
}
@Override
public boolean isQueueEnabled() {
return getExtent().isQueueEnabled();
}
@Override
public void enableQueue() {
getExtent().enableQueue();
}
@Override
public void disableQueue() {
getExtent().disableQueue();
}
@Override
public boolean isWorld() {
return getExtent().isWorld();
}
@Override
public <T extends Filter> T apply(Region region, T filter, boolean full) {
return getExtent().apply(region, filter, full);
}
@Override
public <T extends Filter> T apply(Iterable<BlockVector3> positions, T filter) {
return getExtent().apply(positions, filter);
}
}

View File

@ -68,10 +68,12 @@ public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pat
this(delegate, Masks.alwaysTrue());
}
//FAWE start
@Override
public boolean isQueueEnabled() {
return true;
}
//FAWE end
/**
* Create a new extent buffer that will buffer changes that meet the criteria
@ -102,16 +104,19 @@ public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pat
max = max.getMaximum(location);
}
//FAWE start
if (mask.test(location)) {
buffer.put(location, block.toBaseBlock());
return true;
} else {
return getExtent().setBlock(location, block);
}
//FAWE end
}
@Override
public boolean setBiome(BlockVector3 position, BiomeType biome) {
//FAWE start
// Update minimum
if (min == null) {
min = position;
@ -132,10 +137,12 @@ public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pat
} else {
return getExtent().setBiome(position, biome);
}
//FAWE end
}
@Override
public boolean setBiome(int x, int y, int z, BiomeType biome) {
//FAWE start
// Update minimum
if (min == null) {
min = BlockVector3.at(x, y, z);
@ -156,6 +163,7 @@ public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pat
} else {
return getExtent().setBiome(x, y, z, biome);
}
//FAWE end
}

View File

@ -25,11 +25,11 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.visitor.Order;
import com.fastasyncworldedit.core.function.visitor.Order;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.MutableBlockVector2;
import com.sk89q.worldedit.math.OffsetBlockVector3;
import com.fastasyncworldedit.core.math.MutableBlockVector2;
import com.fastasyncworldedit.core.math.OffsetBlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BiomeType;
@ -53,6 +53,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public class BlockArrayClipboard implements Clipboard {
//FAWE start
private final Region region;
private final BlockVector3 origin;
private final Clipboard parent;
@ -87,6 +88,7 @@ public class BlockArrayClipboard implements Clipboard {
this.region = region.clone();
this.origin = region.getMinimumPoint();
}
//FAWE end
@Override
public Region getRegion() {
@ -139,14 +141,17 @@ public class BlockArrayClipboard implements Clipboard {
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block) throws WorldEditException {
if (region.contains(position)) {
//FAWE - get points
final int x = position.getBlockX();
final int y = position.getBlockY();
final int z = position.getBlockZ();
return setBlock(x, y, z, block);
//FAWE end
}
return false;
}
//FAWE start
@Override
public boolean setTile(int x, int y, int z, CompoundTag tag) {
x -= origin.getX();
@ -155,6 +160,7 @@ public class BlockArrayClipboard implements Clipboard {
return getParent().setTile(x, y, z, tag);
}
public boolean setTile(BlockVector3 position, CompoundTag tag) {
return setTile(position.getX(), position.getY(), position.getZ(), tag);
}
@ -293,6 +299,7 @@ public class BlockArrayClipboard implements Clipboard {
OffsetBlockVector3 mutable = new OffsetBlockVector3(origin);
return Iterators.transform(getParent().iterator(order), mutable::init);
}
//FAWE end
@Override
public BlockVector3 getDimensions() {
@ -313,6 +320,7 @@ public class BlockArrayClipboard implements Clipboard {
this.parent.close();
}
//FAWE start
/**
* Stores entity data.
*/
@ -384,4 +392,5 @@ public class BlockArrayClipboard implements Clipboard {
return result != null;
}
}
//FAWE end
}

View File

@ -19,12 +19,12 @@
package com.sk89q.worldedit.extent.clipboard;
import com.fastasyncworldedit.core.beta.Filter;
import com.fastasyncworldedit.core.queue.Filter;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.object.clipboard.CPUOptimizedClipboard;
import com.fastasyncworldedit.core.object.clipboard.DiskOptimizedClipboard;
import com.fastasyncworldedit.core.object.clipboard.MemoryOptimizedClipboard;
import com.fastasyncworldedit.core.object.clipboard.ReadOnlyClipboard;
import com.fastasyncworldedit.core.extent.clipboard.CPUOptimizedClipboard;
import com.fastasyncworldedit.core.extent.clipboard.DiskOptimizedClipboard;
import com.fastasyncworldedit.core.extent.clipboard.MemoryOptimizedClipboard;
import com.fastasyncworldedit.core.extent.clipboard.ReadOnlyClipboard;
import com.fastasyncworldedit.core.util.EditSessionBuilder;
import com.fastasyncworldedit.core.util.MaskTraverser;
import com.sk89q.worldedit.EditSession;
@ -38,7 +38,7 @@ import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.visitor.Order;
import com.fastasyncworldedit.core.function.visitor.Order;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.transform.Transform;
@ -66,6 +66,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public interface Clipboard extends Extent, Iterable<BlockVector3>, Closeable {
//FAWE start
static Clipboard create(Region region) {
checkNotNull(region);
checkNotNull(region.getWorld(),
@ -84,6 +85,7 @@ public interface Clipboard extends Extent, Iterable<BlockVector3>, Closeable {
return new MemoryOptimizedClipboard(region);
}
}
//FAWE end
/**
* Get the bounding region of this extent.
@ -127,6 +129,7 @@ public interface Clipboard extends Extent, Iterable<BlockVector3>, Closeable {
return false;
}
//FAWE start
/**
* Remove entity from clipboard.
*/
@ -358,4 +361,5 @@ public interface Clipboard extends Extent, Iterable<BlockVector3>, Closeable {
}
}
}
//FAWE end
}

View File

@ -19,16 +19,18 @@
package com.sk89q.worldedit.extent.clipboard.io;
import com.fastasyncworldedit.core.object.io.PGZIPOutputStream;
import com.fastasyncworldedit.core.object.io.ResettableFileInputStream;
import com.fastasyncworldedit.core.object.schematic.MinecraftStructure;
import com.fastasyncworldedit.core.object.schematic.PNGWriter;
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReader;
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriter;
import com.fastasyncworldedit.core.internal.io.ResettableFileInputStream;
import com.fastasyncworldedit.core.extent.clipboard.io.schematic.MinecraftStructure;
import com.fastasyncworldedit.core.extent.clipboard.io.schematic.PNGWriter;
import com.google.common.collect.ImmutableSet;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.Tag;
import org.anarres.parallelgzip.ParallelGZIPOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@ -48,6 +50,7 @@ import java.util.zip.GZIPOutputStream;
*/
public enum BuiltInClipboardFormat implements ClipboardFormat {
//FAWE start - register fast clipboard io
FAST("fast", "fawe") {
@Override
@ -68,11 +71,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
@Override
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
OutputStream gzip;
if (outputStream instanceof PGZIPOutputStream || outputStream instanceof GZIPOutputStream) {
if (outputStream instanceof ParallelGZIPOutputStream || outputStream instanceof GZIPOutputStream) {
gzip = outputStream;
} else {
outputStream = new BufferedOutputStream(outputStream);
gzip = new PGZIPOutputStream(outputStream);
gzip = new ParallelGZIPOutputStream(outputStream);
}
NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip));
return new FastSchematicWriter(nbtStream);
@ -85,6 +88,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
}
},
//FAWE end
/**
* The Schematic format used by MCEdit.
@ -104,7 +108,10 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
@Override
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
throw new IOException("The formats `.schematic`, `.mcedit` and `.mce` are discontinued on versions newer than 1.12 and superseded by the sponge schematic implementation known for `.schem` files.");
//FAWE start - be a more helpful exception
throw new IOException("The formats `.schematic`, `.mcedit` and `.mce` are discontinued on versions newer than" +
"1.12 and superseded by the sponge schematic implementation known for `.schem` files.");
//FAWE end
}
@Override
@ -154,6 +161,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
}
},
//FAWE start - recover schematics with bad entity data & register other clipboard formats
BROKENENTITY("brokenentity", "legacyentity", "le", "be", "brokenentities", "legacyentities") {
@Override
@ -176,11 +184,11 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
@Override
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
OutputStream gzip;
if (outputStream instanceof PGZIPOutputStream || outputStream instanceof GZIPOutputStream) {
if (outputStream instanceof ParallelGZIPOutputStream || outputStream instanceof GZIPOutputStream) {
gzip = outputStream;
} else {
outputStream = new BufferedOutputStream(outputStream);
gzip = new PGZIPOutputStream(outputStream);
gzip = new ParallelGZIPOutputStream(outputStream);
}
NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip));
FastSchematicWriter writer = new FastSchematicWriter(nbtStream);
@ -215,7 +223,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
@Override
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
outputStream = new BufferedOutputStream(outputStream);
OutputStream gzip = new PGZIPOutputStream(outputStream);
OutputStream gzip = new ParallelGZIPOutputStream(outputStream);
NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip));
return new MinecraftStructure(nbtStream);
}
@ -252,6 +260,7 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
return "png";
}
};
//FAWE end
private final ImmutableSet<String> aliases;

View File

@ -19,14 +19,14 @@
package com.sk89q.worldedit.extent.clipboard.io;
import com.fastasyncworldedit.core.object.RunnableVal;
import com.fastasyncworldedit.core.object.clipboard.URIClipboardHolder;
import com.fastasyncworldedit.core.object.io.PGZIPOutputStream;
import com.fastasyncworldedit.core.util.task.RunnableVal;
import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder;
import com.fastasyncworldedit.core.util.MainUtil;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import org.anarres.parallelgzip.ParallelGZIPOutputStream;
import java.io.File;
import java.io.FileInputStream;
@ -99,6 +99,7 @@ public interface ClipboardFormat {
*/
Set<String> getFileExtensions();
//FAWE start
/**
* Sets the actor's clipboard.
* @param actor the actor
@ -131,9 +132,8 @@ public interface ClipboardFormat {
return getReader(stream).read();
}
default URL upload(final Clipboard clipboard) {
return MainUtil.upload(null, null, getPrimaryFileExtension(), new RunnableVal<OutputStream>() {
return MainUtil.upload(null, null, getPrimaryFileExtension(), new RunnableVal<>() {
@Override
public void run(OutputStream value) {
write(value, clipboard);
@ -143,7 +143,7 @@ public interface ClipboardFormat {
default void write(OutputStream value, Clipboard clipboard) {
try {
try (PGZIPOutputStream gzip = new PGZIPOutputStream(value)) {
try (ParallelGZIPOutputStream gzip = new ParallelGZIPOutputStream(value)) {
try (ClipboardWriter writer = getWriter(gzip)) {
writer.write(clipboard);
}
@ -152,4 +152,5 @@ public interface ClipboardFormat {
throw new RuntimeException(e);
}
}
//FAWE end
}

View File

@ -21,10 +21,10 @@ package com.sk89q.worldedit.extent.clipboard.io;
import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.object.clipboard.LazyClipboardHolder;
import com.fastasyncworldedit.core.object.clipboard.MultiClipboardHolder;
import com.fastasyncworldedit.core.object.clipboard.URIClipboardHolder;
import com.fastasyncworldedit.core.object.io.FastByteArrayOutputStream;
import com.fastasyncworldedit.core.extent.clipboard.LazyClipboardHolder;
import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder;
import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder;
import com.fastasyncworldedit.core.internal.io.FastByteArrayOutputStream;
import com.fastasyncworldedit.core.util.MainUtil;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
@ -126,26 +126,6 @@ public class ClipboardFormats {
return null;
}
/**
* Detect the format using the given extension.
*
* @param extension the extension
* @return the format, otherwise null if one cannot be detected
*/
@Nullable
public static ClipboardFormat findByExtension(String extension) {
checkNotNull(extension);
Collection<Entry<String, ClipboardFormat>> entries = getFileExtensionMap().entries();
for (Map.Entry<String, ClipboardFormat> entry : entries) {
if (entry.getKey().equalsIgnoreCase(extension)) {
return entry.getValue();
}
}
return null;
}
/**
* A mapping from extensions to formats.
*
@ -170,6 +150,27 @@ public class ClipboardFormats {
private ClipboardFormats() {
}
//FAWE start
/**
* Detect the format using the given extension.
*
* @param extension the extension
* @return the format, otherwise null if one cannot be detected
*/
@Nullable
public static ClipboardFormat findByExtension(String extension) {
checkNotNull(extension);
Collection<Entry<String, ClipboardFormat>> entries = getFileExtensionMap().entries();
for (Map.Entry<String, ClipboardFormat> entry : entries) {
if (entry.getKey().equalsIgnoreCase(extension)) {
return entry.getValue();
}
}
return null;
}
public static MultiClipboardHolder loadAllFromInput(Actor player, String input, ClipboardFormat format, boolean message) throws IOException {
checkNotNull(player);
checkNotNull(input);
@ -325,4 +326,5 @@ public class ClipboardFormats {
throw new RuntimeException(e);
}
}
//FAWE end
}

View File

@ -19,7 +19,7 @@
package com.sk89q.worldedit.extent.clipboard.io;
import com.fastasyncworldedit.core.object.clipboard.DiskOptimizedClipboard;
import com.fastasyncworldedit.core.extent.clipboard.DiskOptimizedClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.math.BlockVector3;
@ -43,7 +43,9 @@ public interface ClipboardReader extends Closeable {
* @throws IOException thrown on I/O error
*/
default Clipboard read() throws IOException {
//FAWE start
return read(UUID.randomUUID());
//FAWe end
}
/**
@ -55,6 +57,7 @@ public interface ClipboardReader extends Closeable {
return OptionalInt.empty();
}
//FAWE start
default Clipboard read(UUID uuid) throws IOException {
return read(uuid, DiskOptimizedClipboard::new);
}
@ -62,4 +65,5 @@ public interface ClipboardReader extends Closeable {
default Clipboard read(UUID uuid, Function<BlockVector3, Clipboard> createOutput) throws IOException {
return read();
}
//FAWE end
}

View File

@ -47,6 +47,7 @@ public interface ClipboardWriter extends Closeable {
*/
void write(Clipboard clipboard) throws IOException;
//FAWE start
default Tag writeVector(Vector3 vector) {
List<DoubleTag> list = new ArrayList<>();
list.add(new DoubleTag(vector.getX()));
@ -61,4 +62,5 @@ public interface ClipboardWriter extends Closeable {
list.add(new FloatTag(location.getPitch()));
return new ListTag(FloatTag.class, list);
}
//FAWE end
}

View File

@ -1,424 +0,0 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extent.clipboard.io;
import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.jnbt.streamer.StreamDelegate;
import com.fastasyncworldedit.core.jnbt.streamer.ValueReader;
import com.fastasyncworldedit.core.object.FaweInputStream;
import com.fastasyncworldedit.core.object.FaweOutputStream;
import com.fastasyncworldedit.core.object.clipboard.LinearClipboard;
import com.fastasyncworldedit.core.object.io.FastByteArrayOutputStream;
import com.fastasyncworldedit.core.object.io.FastByteArraysInputStream;
import com.sk89q.jnbt.AdventureNBTConverter;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.NBTInputStream;
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.entity.Entity;
import com.sk89q.worldedit.extension.input.InputParseException;
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.internal.Constants;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.DataFixer;
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.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.entity.EntityTypes;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.function.Function;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Reads schematic files using the Sponge Schematic Specification.
*/
public class FastSchematicReader extends NBTSchematicReader {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private final NBTInputStream inputStream;
private DataFixer fixer;
private int dataVersion = -1;
private int version = -1;
private int faweWritten = -1;
private FastByteArrayOutputStream blocksOut;
private FaweOutputStream blocks;
private FastByteArrayOutputStream biomesOut;
private FaweOutputStream biomes;
private List<Map<String, Object>> tiles;
private List<Map<String, Object>> entities;
private int width;
private int height;
private int length;
private int offsetX;
private int offsetY;
private int offsetZ;
private char[] palette;
private char[] biomePalette;
private BlockVector3 min = BlockVector3.ZERO;
private boolean brokenEntities = false;
private boolean isWorldEdit = false;
/**
* Create a new instance.
*
* @param inputStream the input stream to read from
*/
public FastSchematicReader(NBTInputStream inputStream) {
checkNotNull(inputStream);
this.inputStream = inputStream;
this.fixer = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataFixer();
}
public void setBrokenEntities(boolean brokenEntities) {
this.brokenEntities = brokenEntities;
}
private String fix(String palettePart) {
if (fixer == null || dataVersion == -1) {
return palettePart;
}
return fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, palettePart, dataVersion);
}
private CompoundBinaryTag fixBlockEntity(CompoundTag tag) {
if (fixer == null || dataVersion == -1) {
return tag.asBinaryTag();
}
return fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, tag.asBinaryTag(), dataVersion);
}
private CompoundBinaryTag fixEntity(CompoundTag tag) {
if (fixer == null || dataVersion == -1) {
return tag.asBinaryTag();
}
return fixer.fixUp(DataFixer.FixTypes.ENTITY, tag.asBinaryTag(), dataVersion);
}
private String fixBiome(String biomePalettePart) {
if (fixer == null || dataVersion == -1) {
return biomePalettePart;
}
return fixer.fixUp(DataFixer.FixTypes.BIOME, biomePalettePart, dataVersion);
}
public StreamDelegate createVersionDelegate() {
StreamDelegate root = new StreamDelegate();
StreamDelegate schematic = root.add("Schematic");
schematic.add("DataVersion").withInt((i, v) -> dataVersion = v);
schematic.add("Version").withInt((i, v) -> {
version = v;
if (v == 1 && dataVersion == -1) { // DataVersion might not be present, assume 1.13.2
dataVersion = Constants.DATA_VERSION_MC_1_13_2;
}
});
return root;
}
public StreamDelegate createDelegate() {
StreamDelegate root = new StreamDelegate();
StreamDelegate schematic = root.add("Schematic");
schematic.add("Width").withInt((i, v) -> width = v);
schematic.add("Height").withInt((i, v) -> height = v);
schematic.add("Length").withInt((i, v) -> length = v);
schematic.add("Offset").withValue((ValueReader<int[]>) (index, v) -> min = BlockVector3.at(v[0], v[1], v[2]));
StreamDelegate metadata = schematic.add("Metadata");
metadata.add("WEOffsetX").withInt((i, v) -> offsetX = v);
metadata.add("WEOffsetY").withInt((i, v) -> offsetY = v);
metadata.add("WEOffsetZ").withInt((i, v) -> offsetZ = v);
metadata.add("FAWEVersion").withInt((i, v) -> faweWritten = v);
StreamDelegate worldEditSection = metadata.add("WorldEdit");
worldEditSection.withValue((ValueReader<String>) (index, v) -> isWorldEdit = true);
StreamDelegate paletteDelegate = schematic.add("Palette");
paletteDelegate.withValue((ValueReader<Map<String, Object>>) (ignore, v) -> {
palette = new char[v.size()];
for (Entry<String, Object> entry : v.entrySet()) {
BlockState state;
String palettePart = fix(entry.getKey());
try {
state = BlockState.get(palettePart);
} catch (InputParseException ignored) {
LOGGER.warn("Invalid BlockState in palette: " + palettePart + ". Block will be replaced with air.");
state = BlockTypes.AIR.getDefaultState();
}
int index = (int) entry.getValue();
palette[index] = (char) state.getOrdinal();
}
});
StreamDelegate blockData = schematic.add("BlockData");
blockData.withInfo((length, type) -> {
blocksOut = new FastByteArrayOutputStream();
blocks = new FaweOutputStream(new LZ4BlockOutputStream(blocksOut));
});
blockData.withInt((index, value) -> blocks.write(value));
StreamDelegate tilesDelegate = schematic.add("BlockEntities");
tilesDelegate.withInfo((length, type) -> tiles = new ArrayList<>(length));
tilesDelegate.withElem((ValueReader<Map<String, Object>>) (index, tile) -> tiles.add(tile));
// Keep this here so schematics created with FAWE before TileEntities was fixed to BlockEntities still work
StreamDelegate compatTilesDelegate = schematic.add("TileEntities");
compatTilesDelegate.withInfo((length, type) -> tiles = new ArrayList<>(length));
compatTilesDelegate.withElem((ValueReader<Map<String, Object>>) (index, tile) -> tiles.add(tile));
StreamDelegate entitiesDelegate = schematic.add("Entities");
entitiesDelegate.withInfo((length, type) -> entities = new ArrayList<>(length));
entitiesDelegate.withElem((ValueReader<Map<String, Object>>) (index, entity) -> entities.add(entity));
StreamDelegate biomePaletteDelegate = schematic.add("BiomePalette");
biomePaletteDelegate.withValue((ValueReader<Map<String, Object>>) (ignore, v) -> {
biomePalette = new char[v.size()];
for (Entry<String, Object> entry : v.entrySet()) {
BiomeType biome = null;
try {
String biomePalettePart = fixBiome(entry.getKey());
biome = BiomeTypes.get(biomePalettePart);
} catch (InputParseException e) {
e.printStackTrace();
}
int index = (int) entry.getValue();
biomePalette[index] = (char) biome.getInternalId();
}
});
StreamDelegate biomeData = schematic.add("BiomeData");
biomeData.withInfo((length, type) -> {
biomesOut = new FastByteArrayOutputStream();
biomes = new FaweOutputStream(new LZ4BlockOutputStream(biomesOut));
});
biomeData.withInt((index, value) -> biomes.write(value));
return root;
}
private BlockState getBlockState(int id) {
return BlockTypesCache.states[palette[id]];
}
private BiomeType getBiomeType(FaweInputStream fis) throws IOException {
char biomeId = biomePalette[fis.readVarInt()];
return BiomeTypes.get(biomeId);
}
@Override
public Clipboard read(UUID uuid, Function<BlockVector3, Clipboard> createOutput) throws IOException {
StreamDelegate root = createDelegate();
StreamDelegate versions = createVersionDelegate();
inputStream.mark(Integer.MAX_VALUE);
inputStream.readNamedTagLazy(versions);
inputStream.reset();
inputStream.readNamedTagLazy(root);
if (version != 1 && version != 2) {
throw new IOException("This schematic version is not supported; Version: " + version + ", DataVersion: " + dataVersion + ". It's very likely your schematic has an invalid file extension, if the schematic has been created on a version lower than 1.13.2, the extension MUST be `.schematic`, elsewise the schematic can't be read properly.");
}
if (blocks != null) {
blocks.close();
}
if (biomes != null) {
biomes.close();
}
blocks = null;
biomes = null;
BlockVector3 dimensions = BlockVector3.at(width, height, length);
BlockVector3 origin;
if (offsetX != Integer.MIN_VALUE && offsetY != Integer.MIN_VALUE && offsetZ != Integer.MIN_VALUE) {
origin = BlockVector3.at(-offsetX, -offsetY, -offsetZ);
} else {
origin = BlockVector3.ZERO;
}
Clipboard clipboard = createOutput.apply(dimensions);
if (blocksOut != null && blocksOut.getSize() != 0) {
try (FaweInputStream fis = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(blocksOut.toByteArrays())))) {
if (clipboard instanceof LinearClipboard) {
LinearClipboard linear = (LinearClipboard) clipboard;
int volume = width * height * length;
if (palette.length < 128) {
for (int index = 0; index < volume; index++) {
int ordinal = fis.read();
linear.setBlock(index, getBlockState(ordinal));
}
} else {
for (int index = 0; index < volume; index++) {
int ordinal = fis.readVarInt();
linear.setBlock(index, getBlockState(ordinal));
}
}
} else {
if (palette.length < 128) {
for (int y = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
int ordinal = fis.read();
clipboard.setBlock(x, y, z, getBlockState(ordinal));
}
}
}
} else {
for (int y = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
int ordinal = fis.readVarInt();
clipboard.setBlock(x, y, z, getBlockState(ordinal));
}
}
}
}
}
}
}
if (biomesOut != null && biomesOut.getSize() != 0) {
try (FaweInputStream fis = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(biomesOut.toByteArrays())))) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
BiomeType biome = getBiomeType(fis);
for (int y = 0; y < height; y ++) {
clipboard.setBiome(x, y, z, biome);
}
}
}
}
}
// tiles
if (tiles != null && !tiles.isEmpty()) {
for (Map<String, Object> tileRaw : tiles) {
CompoundTag tile = FaweCache.IMP.asTag(tileRaw);
int[] pos = tile.getIntArray("Pos");
int x;
int y;
int z;
if (pos.length != 3) {
if (!tile.containsKey("x") || !tile.containsKey("y") || !tile.containsKey("z")) {
return null;
}
x = tile.getInt("x");
y = tile.getInt("y");
z = tile.getInt("z");
} else {
x = pos[0];
y = pos[1];
z = pos[2];
}
Map<String, Tag> values = new HashMap<>(tile.getValue());
Tag id = values.get("Id");
if (id != null) {
values.put("x", new IntTag(x));
values.put("y", new IntTag(y));
values.put("z", new IntTag(z));
values.put("id", id);
}
values.remove("Id");
values.remove("Pos");
clipboard.setTile(x, y, z, (CompoundTag) AdventureNBTConverter.fromAdventure(fixBlockEntity(new CompoundTag(values))));
}
}
// entities
if (entities != null && !entities.isEmpty()) {
for (Map<String, Object> entRaw : entities) {
Map<String, Tag> value = new HashMap<>(FaweCache.IMP.asTag(entRaw).getValue());
StringTag id = (StringTag) value.get("Id");
if (id == null) {
id = (StringTag) value.get("id");
if (id == null) {
continue;
}
}
value.put("id", id);
value.remove("Id");
EntityType type = EntityTypes.parse(id.getValue());
if (type != null) {
final CompoundTag ent = (CompoundTag) AdventureNBTConverter.fromAdventure(fixEntity(new CompoundTag(value)));
BaseEntity state = new BaseEntity(type, ent);
Location loc = ent.getEntityLocation(clipboard);
if (brokenEntities) {
clipboard.createEntity(loc, state);
continue;
}
if (!isWorldEdit && faweWritten == -1) {
int locX = loc.getBlockX();
int locY = loc.getBlockY();
int locZ = loc.getBlockZ();
BlockVector3 max = min.add(dimensions).subtract(BlockVector3.ONE);
if (locX < min.getX() || locY < min.getY() || locZ < min.getZ()
|| locX > max.getX() || locY > max.getY() || locZ > max.getZ()) {
for (Entity e : clipboard.getEntities()) {
clipboard.removeEntity(e);
}
LOGGER.error("Detected schematic entity outside clipboard region. FAWE will not load entities. "
+ "Please try loading the schematic with the format \"legacyentity\"");
break;
}
}
clipboard.createEntity(loc.setPosition(loc.subtract(min.toVector3())), state);
} else {
LOGGER.debug("Invalid entity: " + id);
}
}
}
clipboard.setOrigin(origin);
if (!min.equals(BlockVector3.ZERO)) {
clipboard = new BlockArrayClipboard(clipboard, min);
}
return clipboard;
}
@Override
public void close() throws IOException {
inputStream.close();
}
}

View File

@ -1,328 +0,0 @@
/*
* 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extent.clipboard.io;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.jnbt.streamer.IntValueReader;
import com.fastasyncworldedit.core.object.FaweOutputStream;
import com.fastasyncworldedit.core.util.IOUtil;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntArrayTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.NBTConstants;
import com.sk89q.jnbt.NBTOutputStream;
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.entity.Entity;
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.function.visitor.Order;
import com.sk89q.worldedit.math.BlockVector3;
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.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Writes schematic files using the Sponge schematic format.
*/
public class FastSchematicWriter 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;
private boolean brokenEntities = false;
/**
* Create a new schematic writer.
*
* @param outputStream the output stream to write to
*/
public FastSchematicWriter(NBTOutputStream outputStream) {
checkNotNull(outputStream);
this.outputStream = outputStream;
}
public void setBrokenEntities(boolean brokenEntities) {
this.brokenEntities = brokenEntities;
}
@Override
public void write(Clipboard clipboard) throws IOException {
// For now always write the latest version. Maybe provide support for earlier if more appear.
write2(clipboard);
}
/**
* Writes a version 2 schematic file.
*
* @param clipboard The clipboard
*/
private void write2(Clipboard clipboard) throws IOException {
Region region = clipboard.getRegion();
BlockVector3 origin = clipboard.getOrigin();
BlockVector3 min = region.getMinimumPoint();
BlockVector3 offset = min.subtract(origin);
int width = region.getWidth();
int height = region.getHeight();
int length = region.getLength();
if (width > MAX_SIZE) {
throw new IllegalArgumentException("Width of region too large for a .schematic");
}
if (height > MAX_SIZE) {
throw new IllegalArgumentException("Height of region too large for a .schematic");
}
if (length > MAX_SIZE) {
throw new IllegalArgumentException("Length of region too large for a .schematic");
}
final DataOutput rawStream = outputStream.getOutputStream();
outputStream.writeLazyCompoundTag("Schematic", out -> {
out.writeNamedTag("DataVersion", WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion());
out.writeNamedTag("Version", CURRENT_VERSION);
out.writeNamedTag("Width", (short) width);
out.writeNamedTag("Height", (short) height);
out.writeNamedTag("Length", (short) length);
// The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin'
out.writeNamedTag("Offset", new int[]{
min.getBlockX(),
min.getBlockY(),
min.getBlockZ(),
});
out.writeLazyCompoundTag("Metadata", out1 -> {
out1.writeNamedTag("WEOffsetX", offset.getBlockX());
out1.writeNamedTag("WEOffsetY", offset.getBlockY());
out1.writeNamedTag("WEOffsetZ", offset.getBlockZ());
out1.writeNamedTag("FAWEVersion", Fawe.get().getVersion().build);
});
ByteArrayOutputStream blocksCompressed = new ByteArrayOutputStream();
FaweOutputStream blocksOut = new FaweOutputStream(new DataOutputStream(new LZ4BlockOutputStream(blocksCompressed)));
ByteArrayOutputStream tilesCompressed = new ByteArrayOutputStream();
NBTOutputStream tilesOut = new NBTOutputStream(new LZ4BlockOutputStream(tilesCompressed));
List<Integer> paletteList = new ArrayList<>();
char[] palette = new char[BlockTypesCache.states.length];
Arrays.fill(palette, Character.MAX_VALUE);
int paletteMax = 0;
int numTiles = 0;
Clipboard finalClipboard;
if (clipboard instanceof BlockArrayClipboard) {
finalClipboard = ((BlockArrayClipboard) clipboard).getParent();
} else {
finalClipboard = clipboard;
}
Iterator<BlockVector3> iterator = finalClipboard.iterator(Order.YZX);
while (iterator.hasNext()) {
BlockVector3 pos = iterator.next();
BaseBlock block = pos.getFullBlock(finalClipboard);
CompoundTag nbt = block.getNbtData();
if (nbt != null) {
Map<String, Tag> values = new HashMap<>(nbt.getValue());
// Positions are kept in NBT, we don't want that.
values.remove("x");
values.remove("y");
values.remove("z");
values.put("Id", new StringTag(block.getNbtId()));
// Remove 'id' if it exists. We want 'Id'.
// Do this after we get "getNbtId" cos otherwise "getNbtId" doesn't work.
// Dum.
values.remove("id");
values.put("Pos", new IntArrayTag(new int[]{
pos.getX(),
pos.getY(),
pos.getZ()
}));
numTiles++;
tilesOut.writeTagPayload(new CompoundTag(values));
}
int ordinal = block.getOrdinal();
if (ordinal == 0) {
ordinal = 1;
}
char value = palette[ordinal];
if (value == Character.MAX_VALUE) {
int size = paletteMax++;
palette[ordinal] = value = (char) size;
paletteList.add(ordinal);
}
blocksOut.writeVarInt(value);
}
// close
tilesOut.close();
blocksOut.close();
out.writeNamedTag("PaletteMax", paletteMax);
out.writeLazyCompoundTag("Palette", out12 -> {
for (int i = 0; i < paletteList.size(); i++) {
int stateOrdinal = paletteList.get(i);
BlockState state = BlockTypesCache.states[stateOrdinal];
out12.writeNamedTag(state.getAsString(), i);
}
});
out.writeNamedTagName("BlockData", NBTConstants.TYPE_BYTE_ARRAY);
rawStream.writeInt(blocksOut.size());
try (LZ4BlockInputStream in = new LZ4BlockInputStream(new ByteArrayInputStream(blocksCompressed.toByteArray()))) {
IOUtil.copy(in, rawStream);
}
if (numTiles != 0) {
out.writeNamedTagName("BlockEntities", NBTConstants.TYPE_LIST);
rawStream.write(NBTConstants.TYPE_COMPOUND);
rawStream.writeInt(numTiles);
try (LZ4BlockInputStream in = new LZ4BlockInputStream(new ByteArrayInputStream(tilesCompressed.toByteArray()))) {
IOUtil.copy(in, rawStream);
}
} else {
out.writeNamedEmptyList("BlockEntities");
}
if (finalClipboard.hasBiomes()) {
writeBiomes(finalClipboard, out);
}
List<Tag> entities = new ArrayList<>();
for (Entity entity : finalClipboard.getEntities()) {
BaseEntity state = entity.getState();
if (state != null) {
Map<String, Tag> values = new HashMap<>();
// Put NBT provided data
CompoundTag rawTag = state.getNbtData();
if (rawTag != null) {
values.putAll(rawTag.getValue());
}
// Store our location data, overwriting any
values.remove("id");
Location loc = entity.getLocation();
if (!brokenEntities) {
loc = loc.setPosition(loc.add(min.toVector3()));
}
values.put("Id", new StringTag(state.getType().getId()));
values.put("Pos", writeVector(loc));
values.put("Rotation", writeRotation(entity.getLocation()));
CompoundTag entityTag = new CompoundTag(values);
entities.add(entityTag);
}
}
if (entities.isEmpty()) {
out.writeNamedEmptyList("Entities");
} else {
out.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
}
});
}
private void writeBiomes(Clipboard clipboard, NBTOutputStream out) throws IOException {
ByteArrayOutputStream biomesCompressed = new ByteArrayOutputStream();
DataOutputStream biomesOut = new DataOutputStream(new LZ4BlockOutputStream(biomesCompressed));
List<Integer> paletteList = new ArrayList<>();
int[] palette = new int[BiomeTypes.getMaxId() + 1];
Arrays.fill(palette, Integer.MAX_VALUE);
int[] paletteMax = {0};
IntValueReader task = new IntValueReader() {
@Override
public void applyInt(int index, int ordinal) {
try {
int value = palette[ordinal];
if (value == Integer.MAX_VALUE) {
int size = paletteMax[0]++;
palette[ordinal] = value = size;
paletteList.add(ordinal);
}
IOUtil.writeVarInt(biomesOut, value);
} catch (IOException e) {
e.printStackTrace();
}
}
};
BlockVector3 min = clipboard.getMinimumPoint();
int width = clipboard.getRegion().getWidth();
int length = clipboard.getRegion().getLength();
for (int z = 0, i = 0; z < length; z++) {
int z0 = min.getBlockZ() + z;
for (int x = 0; x < width; x++, i++) {
int x0 = min.getBlockX() + x;
BlockVector3 pt = BlockVector3.at(x0, min.getBlockY(), z0);
BiomeType biome = clipboard.getBiome(pt);
task.applyInt(i, biome.getInternalId());
}
}
biomesOut.close();
out.writeNamedTag("BiomePaletteMax", paletteMax[0]);
out.writeLazyCompoundTag("BiomePalette", out12 -> {
for (int i = 0; i < paletteList.size(); i++) {
int ordinal = paletteList.get(i);
BiomeType state = BiomeTypes.get(ordinal);
out12.writeNamedTag(state.getId(), i);
}
});
out.writeNamedTagName("BiomeData", NBTConstants.TYPE_BYTE_ARRAY);
out.writeInt(biomesOut.size());
try (LZ4BlockInputStream in = new LZ4BlockInputStream(new ByteArrayInputStream(biomesCompressed.toByteArray()))) {
IOUtil.copy(in, (DataOutput) out);
}
}
@Override
public void close() throws IOException {
outputStream.close();
}
}

View File

@ -222,7 +222,9 @@ public class MCEditSchematicReader extends NBTSchematicReader {
}
if (fixer != null && t != null) {
//FAWE start
t = (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, t.asBinaryTag(), -1));
//FAWE end
}
BlockVector3 vec = BlockVector3.at(x, y, z);

View File

@ -26,7 +26,7 @@ import java.util.Map;
import javax.annotation.Nullable;
/**
* Base class for NBT schematic readers
* Base class for NBT schematic readers.
*/
public abstract class NBTSchematicReader implements ClipboardReader {

View File

@ -125,7 +125,9 @@ public class SpongeSchematicReader extends NBTSchematicReader {
BlockArrayClipboard clip = readVersion1(schematicTag);
return readVersion2(clip, schematicTag);
}
throw new IOException("This schematic version is not supported; Version: " + schematicVersion + ", DataVersion: " + dataVersion + ". It's very likely your schematic has an invalid file extension, if the schematic has been created on a version lower than 1.13.2, the extension MUST be `.schematic`, elsewise the schematic can't be read properly.");
throw new IOException("This schematic version is not supported; Version: " + schematicVersion + ", DataVersion: " + dataVersion + "." +
"It's very likely your schematic has an invalid file extension, if the schematic has been created on a version lower than" +
"1.13.2, the extension MUST be `.schematic`, elsewise the schematic can't be read properly.");
}
@Override
@ -248,7 +250,10 @@ public class SpongeSchematicReader extends NBTSchematicReader {
values.remove("Id");
values.remove("Pos");
if (fixer != null) {
tileEntity = ((CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, new CompoundTag(values).asBinaryTag(), dataVersion))).getValue();
//FAWE start
tileEntity = ((CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY,
new CompoundTag(values).asBinaryTag(), dataVersion))).getValue();
//FAWE end
} else {
tileEntity = values;
}
@ -386,7 +391,9 @@ public class SpongeSchematicReader extends NBTSchematicReader {
entityTag = entityTag.createBuilder().putString("id", id).remove("Id").build();
if (fixer != null) {
//FAWE start
entityTag = (CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp(DataFixer.FixTypes.ENTITY, entityTag.asBinaryTag(), dataVersion));
//FAWE end
}
EntityType entityType = EntityTypes.get(id);

View File

@ -39,8 +39,10 @@ import javax.annotation.Nullable;
*/
public class BlockBagExtent extends AbstractDelegateExtent {
//FAWE start
private final boolean mine;
private int[] missingBlocks = new int[BlockTypes.size()];
//FAWE end
private BlockBag blockBag;
/**
@ -49,6 +51,7 @@ public class BlockBagExtent extends AbstractDelegateExtent {
* @param extent the extent
* @param blockBag the block bag
*/
//FAWE start
public BlockBagExtent(Extent extent, @Nullable BlockBag blockBag) {
this(extent, blockBag, false);
}
@ -58,6 +61,7 @@ public class BlockBagExtent extends AbstractDelegateExtent {
this.blockBag = blockBag;
this.mine = mine;
}
//FAWe end
/**
* Get the block bag.
@ -85,6 +89,7 @@ public class BlockBagExtent extends AbstractDelegateExtent {
* @return a map of missing blocks
*/
public Map<BlockType, Integer> popMissing() {
//FAWE start - Use an Array
HashMap<BlockType, Integer> map = new HashMap<>();
for (int i = 0; i < missingBlocks.length; i++) {
int count = missingBlocks[i];
@ -94,6 +99,7 @@ public class BlockBagExtent extends AbstractDelegateExtent {
}
Arrays.fill(missingBlocks, 0);
return map;
//FAWE end
}
@Override
@ -111,10 +117,13 @@ public class BlockBagExtent extends AbstractDelegateExtent {
} catch (UnplaceableBlockException e) {
throw FaweCache.BLOCK_BAG;
} catch (BlockBagException e) {
//FAWE start - listen for internal ids
missingBlocks[block.getBlockType().getInternalId()]++;
throw FaweCache.BLOCK_BAG;
//FAWE end
}
}
//FAWE start
if (mine) {
if (!existing.getBlockType().getMaterial().isAir()) {
try {
@ -123,6 +132,7 @@ public class BlockBagExtent extends AbstractDelegateExtent {
}
}
}
//FAWE end
}
return super.setBlock(x, y, z, block);

View File

@ -26,7 +26,7 @@ import com.sk89q.worldedit.world.block.BlockType;
*/
public class OutOfSpaceException extends BlockBagException {
private BlockType type;
private final BlockType type;
/**
* Construct the object.

View File

@ -1,17 +0,0 @@
package com.sk89q.worldedit.extent.inventory;
import com.sk89q.worldedit.blocks.BaseItem;
public interface SlottableBlockBag {
BaseItem getItem(int slot);
void setItem(int slot, BaseItem block);
default int size() {
return 36;
}
default int getSelectedSlot() {
return -1;
}
}

View File

@ -132,15 +132,19 @@ public class MultiStageReorder extends AbstractBufferingExtent implements Reorde
BlockCategories.DOORS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.FINAL));
BlockCategories.BANNERS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.FINAL));
BlockCategories.SIGNS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.FINAL));
priorityMap.put(BlockTypes.SIGN, PlacementPriority.FINAL);
priorityMap.put(BlockTypes.WALL_SIGN, PlacementPriority.FINAL);
@SuppressWarnings("deprecation")
BlockType sign = BlockTypes.SIGN;
priorityMap.put(sign, PlacementPriority.FINAL);
@SuppressWarnings("deprecation")
BlockType wallSign = BlockTypes.WALL_SIGN;
priorityMap.put(wallSign, PlacementPriority.FINAL);
priorityMap.put(BlockTypes.CACTUS, PlacementPriority.FINAL);
priorityMap.put(BlockTypes.SUGAR_CANE, PlacementPriority.FINAL);
priorityMap.put(BlockTypes.PISTON_HEAD, PlacementPriority.FINAL);
priorityMap.put(BlockTypes.MOVING_PISTON, PlacementPriority.FINAL);
}
private Map<PlacementPriority, BlockMap<BaseBlock>> stages = new HashMap<>();
private final Map<PlacementPriority, BlockMap<BaseBlock>> stages = new HashMap<>();
private boolean enabled;
@ -233,6 +237,8 @@ public class MultiStageReorder extends AbstractBufferingExtent implements Reorde
case LAST:
stages.get(PlacementPriority.CLEAR_LAST).put(location, replacement);
break;
default:
break;
}
if (block.getBlockType().getMaterial().isAir()) {

View File

@ -20,7 +20,7 @@
package com.sk89q.worldedit.extent.transform;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.object.extent.ResettableExtent;
import com.fastasyncworldedit.core.extent.ResettableExtent;
import com.google.common.collect.ImmutableMap;
import com.sk89q.jnbt.ByteTag;
import com.sk89q.jnbt.CompoundTag;
@ -36,8 +36,8 @@ import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.registry.state.AbstractProperty;
import com.sk89q.worldedit.registry.state.DirectionalProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.registry.state.PropertyKey;
import com.sk89q.worldedit.registry.state.PropertyKeySet;
import com.fastasyncworldedit.core.registry.state.PropertyKey;
import com.fastasyncworldedit.core.registry.state.PropertyKeySet;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
@ -83,6 +83,7 @@ import static com.sk89q.worldedit.util.Direction.values;
*/
public class BlockTransformExtent extends ResettableExtent {
//FAWE start
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Set<PropertyKey> directional = PropertyKeySet.of(
@ -115,6 +116,7 @@ public class BlockTransformExtent extends ResettableExtent {
public BlockTransformExtent(Extent parent) {
this(parent, new AffineTransform());
}
//FAWE end
/**
* Create a new instance.
@ -125,11 +127,14 @@ public class BlockTransformExtent extends ResettableExtent {
super(extent);
checkNotNull(transform);
this.transform = transform;
//FAWE start - cache this
this.transformInverse = this.transform.inverse();
cache();
//FAWE end
}
//FAWE start
private static long combine(Direction... directions) {
long mask = 0;
for (Direction dir : directions) {
@ -444,6 +449,7 @@ public class BlockTransformExtent extends ResettableExtent {
}
}
}
//FAWE end
/**
* Get the transform.
@ -497,8 +503,10 @@ public class BlockTransformExtent extends ResettableExtent {
public void setTransform(Transform affine) {
this.transform = affine;
//FAWE start - cache this
this.transformInverse = this.transform.inverse();
cache();
//FAWE end
}
/**
@ -511,6 +519,7 @@ public class BlockTransformExtent extends ResettableExtent {
* @return the same block
*/
public static <B extends BlockStateHolder<B>> B transform(@NotNull B block, @NotNull Transform transform) {
//FAWE start - use own logic
// performance critical
BlockState state = block.toImmutableState();
@ -520,8 +529,10 @@ public class BlockTransformExtent extends ResettableExtent {
return (B) transformBaseBlockNBT(transformed, block.getNbtData(), transform);
}
return (B) (block instanceof BaseBlock ? transformed.toBaseBlock() : transformed);
//FAWE end
}
//FAWE start - use own logic
private BlockState transform(BlockState state, int[][] transformArray, Transform transform) {
int typeId = state.getInternalBlockTypeId();
int[] arr = transformArray[typeId];
@ -570,4 +581,5 @@ public class BlockTransformExtent extends ResettableExtent {
private BlockState transformInverse(BlockState block) {
return transform(block, BLOCK_TRANSFORM_INVERSE, transformInverse);
}
//FAWE end
}

View File

@ -52,7 +52,7 @@ public class DataValidatorExtent extends AbstractDelegateExtent {
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
final int y = location.getBlockY();
final BlockType type = block.getBlockType();
if (y < 0 || y > world.getMaxY()) {
if (y < world.getMinY() || y > world.getMaxY()) {
return false;
}

View File

@ -3,18 +3,18 @@
* 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
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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.
* 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 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/>.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extent.world;
@ -45,6 +45,6 @@ public class BiomeQuirkExtent extends AbstractDelegateExtent {
// Also place at Y = 0 for proper handling
success = super.setBiome(position.withY(0), biome);
}
return success || super.setBiome(position, biome);
return super.setBiome(position, biome) || success;
}
}

View File

@ -33,7 +33,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* Handles various quirks when setting blocks, such as ice turning
* into water or containers dropping their contents.
*
* @deprecated Handled by the world entirely now
*/
@Deprecated
public class BlockQuirkExtent extends AbstractDelegateExtent {
private final World world;

View File

@ -35,7 +35,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class ChunkLoadingExtent extends AbstractDelegateExtent {
private final World world;
private boolean enabled;
private final boolean enabled;
/**
* Create a new instance.

View File

@ -96,7 +96,9 @@ public class SurvivalModeExtent extends AbstractDelegateExtent {
} else {
// Can't be an inlined check due to inconsistent generic return type
if (stripNbt) {
//FAWE start - Use CompoundBinaryTag
return super.setBlock(location, block.toBaseBlock((CompoundBinaryTag) null));
//FAWE end
} else {
return super.setBlock(location, block);
}