mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-23 01:37:37 +00:00
Remove hardcoding of world limits (#1199)
* Remove hardcoding of world limits - seems to be working fine without the datapack for world height changing - particular attention should be given to LocalBlockVectorSet and MathMan changes * update adapters * Override getMinY in various classes and ensure selections have a world attached to them * no message * Address comments - Fix for lighting mode 1 * A few more changes * Fix LocalBlockVectorSet * Fix range statement * Various fixes/comment-addressing - There's not much point in having a different file name now for history. We've broken it before... - Fix history read/write - Fix range on for loops in CharBlocks * undo bad CharBlocks change * Fix history y level * Fix biome history * Fix lighting * Fix /up * Make regen fail not because of these changes * Fixes for y < 0 * Fix isEmpty where only the uppermost chunksection is edited * Fix javadocs/FAWE annotations * Better explain why BiomeMath is removed * If history task throws an error, it should only be caught and printed if not completing now. * Min|max world heights for new patterns * Load biomes from NMS instead of bukkit (#1200) * Update adapters * Update adapters * Don't initialise BlockTypes when biomes aren't set up yet so all BiomeTypes.BIOME are no longer null thanks. * Address some comments. * rename layer -> sectionIndex to imply inclusivity * Javadoctored. Co-authored-by: NotMyFault <mc.cache@web.de> Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
This commit is contained in:
parent
5b2bd45d86
commit
1d9b1a3d5e
@ -266,8 +266,8 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
||||
});
|
||||
}
|
||||
|
||||
source = new SingleThreadQueueExtent();
|
||||
source.init(null, initSourceQueueCache(), null);
|
||||
source = new SingleThreadQueueExtent(originalBukkitWorld.getMinHeight(), originalBukkitWorld.getMaxHeight());
|
||||
source.init(target, initSourceQueueCache(), null);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ import javax.annotation.Nonnull;
|
||||
public class MinecraftVersion implements Comparable<MinecraftVersion> {
|
||||
|
||||
public static final MinecraftVersion NETHER = new MinecraftVersion(1, 16);
|
||||
public static final MinecraftVersion CAVES_17 = new MinecraftVersion(1, 17);
|
||||
|
||||
private final int major;
|
||||
private final int minor;
|
||||
|
@ -49,6 +49,7 @@ import com.sk89q.worldedit.util.lifecycle.Lifecycled;
|
||||
import com.sk89q.worldedit.util.lifecycle.SimpleLifecycled;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockCategory;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.gamemode.GameModes;
|
||||
@ -59,6 +60,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Tag;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.command.BlockCommandSender;
|
||||
@ -234,17 +236,18 @@ public class WorldEditPlugin extends JavaPlugin {
|
||||
// datapacks aren't loaded until just before the world is, and bukkit has no event for this
|
||||
// so the earliest we can do this is in WorldInit
|
||||
setupTags();
|
||||
setupBiomes(); // FAWE - load biomes later
|
||||
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent(platform));
|
||||
}
|
||||
|
||||
@SuppressWarnings({"deprecation", "unchecked"})
|
||||
private void initializeRegistries() {
|
||||
// Biome
|
||||
/* // FAWE start - move Biomes to their own method
|
||||
for (Biome biome : Biome.values()) {
|
||||
String lowerCaseBiomeName = biome.name().toLowerCase(Locale.ROOT);
|
||||
BiomeType.REGISTRY.register("minecraft:" + lowerCaseBiomeName, new BiomeType("minecraft:" + lowerCaseBiomeName));
|
||||
}
|
||||
/*
|
||||
// FAWE end
|
||||
|
||||
// Block & Item
|
||||
for (Material material : Material.values()) {
|
||||
@ -304,6 +307,30 @@ public class WorldEditPlugin extends JavaPlugin {
|
||||
"The version of Spigot/Paper you are using doesn't support Tags. The usage of tags with WorldEdit will not work until you update.");
|
||||
}
|
||||
}
|
||||
|
||||
// FAWE start
|
||||
private void setupBiomes() {
|
||||
if (this.adapter.value().isPresent()) {
|
||||
// We don't know which world is the one with the data packs
|
||||
// so we just loop over them. Doesn't hurt
|
||||
for (org.bukkit.World world : Bukkit.getWorlds()) {
|
||||
// cast is needed, thanks to raw types <3
|
||||
for (final NamespacedKey biome : ((BukkitImplAdapter<?>) adapter.value().get()).getRegisteredBiomes(world)) {
|
||||
if (BiomeType.REGISTRY.get(biome.toString()) == null) { // only register once
|
||||
BiomeType.REGISTRY.register(biome.toString(), new BiomeType(biome.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOGGER.warn("Failed to load biomes via adapter (not present). Will load via bukkit");
|
||||
for (Biome biome : Biome.values()) {
|
||||
if (BiomeType.REGISTRY.get(biome.toString()) == null) { // only register once
|
||||
BiomeType.REGISTRY.register(biome.getKey().toString(), new BiomeType(biome.getKey().toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// FAWE end
|
||||
|
||||
private void loadAdapter() {
|
||||
WorldEdit worldEdit = WorldEdit.getInstance();
|
||||
|
@ -50,7 +50,9 @@ import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.block.Biome;
|
||||
@ -60,9 +62,11 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* An interface for adapters of various Bukkit implementations.
|
||||
@ -304,6 +308,18 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
|
||||
return Biome.BADLANDS.ordinal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterable of all biomes known to the server.
|
||||
*
|
||||
* @param world the world to load the registered biomes from.
|
||||
* @return all biomes known to the server.
|
||||
*/
|
||||
default Iterable<NamespacedKey> getRegisteredBiomes(World world) {
|
||||
return Arrays.stream(Biome.values())
|
||||
.map(Keyed::getKey)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
default RelighterFactory getRelighterFactory() {
|
||||
return new NMSRelighterFactory(); // TODO implement in adapters instead
|
||||
}
|
||||
|
Binary file not shown.
@ -270,17 +270,22 @@ public class FaweAPI {
|
||||
RegionWrapper bounds = new RegionWrapper(
|
||||
origin.getBlockX() - radius,
|
||||
origin.getBlockX() + radius,
|
||||
extent.getMinY(),
|
||||
extent.getMaxY(),
|
||||
origin.getBlockZ() - radius,
|
||||
origin.getBlockZ() + radius
|
||||
);
|
||||
RegionWrapper boundsPlus = new RegionWrapper(bounds.minX - 64, bounds.maxX + 512, bounds.minZ - 64, bounds.maxZ + 512);
|
||||
RegionWrapper boundsPlus = new RegionWrapper(bounds.minX - 64, bounds.maxX + 512, bounds.minY, bounds.maxY,
|
||||
bounds.minZ - 64,
|
||||
bounds.maxZ + 512);
|
||||
HashSet<RegionWrapper> regionSet = Sets.<RegionWrapper>newHashSet(bounds);
|
||||
ArrayList<DiskStorageHistory> result = new ArrayList<>();
|
||||
for (File file : files) {
|
||||
UUID uuid = UUID.fromString(file.getParentFile().getName());
|
||||
DiskStorageHistory dsh = new DiskStorageHistory(world, uuid, Integer.parseInt(file.getName().split("\\.")[0]));
|
||||
SimpleChangeSetSummary summary = dsh.summarize(boundsPlus, shallow);
|
||||
RegionWrapper region = new RegionWrapper(summary.minX, summary.maxX, summary.minZ, summary.maxZ);
|
||||
RegionWrapper region = new RegionWrapper(summary.minX, summary.maxX, extent.getMinY(), extent.getMaxY(), summary.minZ,
|
||||
summary.maxZ);
|
||||
boolean encompassed = false;
|
||||
boolean isIn = false;
|
||||
for (RegionWrapper allowed : regionSet) {
|
||||
|
@ -64,9 +64,6 @@ public enum FaweCache implements Trimable {
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
public final int BLOCKS_PER_LAYER = 4096;
|
||||
public final int CHUNK_LAYERS = 16;
|
||||
public final int WORLD_HEIGHT = CHUNK_LAYERS << 4;
|
||||
public final int WORLD_MAX_Y = WORLD_HEIGHT - 1;
|
||||
|
||||
public final char[] EMPTY_CHAR_4096 = new char[4096];
|
||||
|
||||
|
@ -24,7 +24,8 @@ public class BlendBall implements Brush {
|
||||
|
||||
int[] frequency = new int[BlockTypes.size()];
|
||||
|
||||
int maxY = editSession.getMaximumPoint().getBlockY();
|
||||
int maxY = editSession.getMaxY();
|
||||
int minY = editSession.getMinY();
|
||||
|
||||
for (int x = -outsetSize; x <= outsetSize; x++) {
|
||||
int x0 = x + tx;
|
||||
@ -43,7 +44,7 @@ public class BlendBall implements Brush {
|
||||
for (int ox = -1; ox <= 1; ox++) {
|
||||
for (int oz = -1; oz <= 1; oz++) {
|
||||
for (int oy = -1; oy <= 1; oy++) {
|
||||
if (oy + y0 < 0 || oy + y0 > maxY) {
|
||||
if (oy + y0 < minY || oy + y0 > maxY) {
|
||||
continue;
|
||||
}
|
||||
BlockState state = editSession.getBlock(x0 + ox, y0 + oy, z0 + oz);
|
||||
|
@ -41,7 +41,8 @@ public class CommandBrush implements Brush {
|
||||
.replace("{size}", Integer.toString(radius));
|
||||
|
||||
Player player = editSession.getPlayer();
|
||||
Location face = player.getBlockTraceFace(256, true);
|
||||
//Use max world height to allow full coverage of the world height
|
||||
Location face = player.getBlockTraceFace(editSession.getWorld().getMaxY(), true);
|
||||
if (face == null) {
|
||||
position = position.add(0, 1, 1);
|
||||
} else {
|
||||
|
@ -78,7 +78,8 @@ public class CopyPastaBrush implements Brush, ResettableTool {
|
||||
};
|
||||
// Add origin
|
||||
mask.test(position);
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(mask, new NullRegionFunction(), (int) size);
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(mask, new NullRegionFunction(), (int) size, editSession.getMinY(),
|
||||
editSession.getMaxY());
|
||||
visitor.visit(position);
|
||||
Operations.completeBlindly(visitor);
|
||||
// Build the clipboard
|
||||
|
@ -16,6 +16,7 @@ public class FallingSphere implements Brush {
|
||||
int py = position.getBlockY();
|
||||
int pz = position.getBlockZ();
|
||||
int maxY = editSession.getMaxY();
|
||||
int minY = editSession.getMinY();
|
||||
|
||||
int radius = (int) Math.round(size);
|
||||
int radiusSqr = (int) Math.round(size * size);
|
||||
@ -37,10 +38,10 @@ public class FallingSphere implements Brush {
|
||||
}
|
||||
|
||||
int yRadius = MathMan.usqrt(remainingY);
|
||||
int startY = Math.max(0, py - yRadius);
|
||||
int startY = Math.max(minY, py - yRadius);
|
||||
int endY = Math.min(maxY, py + yRadius);
|
||||
|
||||
int heightY = editSession.getHighestTerrainBlock(ax, az, 0, endY);
|
||||
int heightY = editSession.getHighestTerrainBlock(ax, az, startY, endY);
|
||||
if (heightY < startY) {
|
||||
int diff = startY - heightY;
|
||||
startY -= diff;
|
||||
|
@ -21,9 +21,11 @@ public class FlattenBrush extends HeightBrush {
|
||||
boolean layers,
|
||||
boolean smooth,
|
||||
Clipboard clipboard,
|
||||
ScalableHeightMap.Shape shape
|
||||
ScalableHeightMap.Shape shape,
|
||||
int minY,
|
||||
int maxY
|
||||
) {
|
||||
super(stream, rotation, yscale, layers, smooth, clipboard, shape);
|
||||
super(stream, rotation, yscale, layers, smooth, clipboard, shape, minY, maxY);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -27,8 +27,9 @@ public class HeightBrush implements Brush {
|
||||
public final boolean layers;
|
||||
public final boolean smooth;
|
||||
|
||||
public HeightBrush(InputStream stream, int rotation, double yscale, boolean layers, boolean smooth, Clipboard clipboard) {
|
||||
this(stream, rotation, yscale, layers, smooth, clipboard, ScalableHeightMap.Shape.CONE);
|
||||
public HeightBrush(InputStream stream, int rotation, double yscale, boolean layers, boolean smooth, Clipboard clipboard,
|
||||
int minY, int maxY) {
|
||||
this(stream, rotation, yscale, layers, smooth, clipboard, ScalableHeightMap.Shape.CONE, minY, maxY);
|
||||
}
|
||||
|
||||
public HeightBrush(
|
||||
@ -38,7 +39,9 @@ public class HeightBrush implements Brush {
|
||||
boolean layers,
|
||||
boolean smooth,
|
||||
Clipboard clipboard,
|
||||
ScalableHeightMap.Shape shape
|
||||
ScalableHeightMap.Shape shape,
|
||||
int minY,
|
||||
int maxY
|
||||
) {
|
||||
this.rotation = (rotation / 90) % 4;
|
||||
this.yscale = yscale;
|
||||
@ -46,14 +49,14 @@ public class HeightBrush implements Brush {
|
||||
this.smooth = smooth;
|
||||
if (stream != null) {
|
||||
try {
|
||||
heightMap = ScalableHeightMap.fromPNG(stream);
|
||||
heightMap = ScalableHeightMap.fromPNG(stream, minY, maxY);
|
||||
} catch (IOException e) {
|
||||
throw new FaweException(Caption.of("fawe.worldedit.brush.brush.height.invalid"));
|
||||
}
|
||||
} else if (clipboard != null) {
|
||||
heightMap = ScalableHeightMap.fromClipboard(clipboard);
|
||||
heightMap = ScalableHeightMap.fromClipboard(clipboard, minY, maxY);
|
||||
} else {
|
||||
heightMap = ScalableHeightMap.fromShape(shape);
|
||||
heightMap = ScalableHeightMap.fromShape(shape, minY, maxY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ public class ImageBrush implements Brush {
|
||||
colorFunction,
|
||||
editSession,
|
||||
session.getTextureUtil()
|
||||
), vector -> true, Integer.MAX_VALUE);
|
||||
), vector -> true, Integer.MAX_VALUE, editSession.getMinY(), editSession.getMaxY());
|
||||
visitor.setDirections(Arrays.asList(BreadthFirstSearch.DIAGONAL_DIRECTIONS));
|
||||
visitor.visit(center);
|
||||
Operations.completeBlindly(visitor);
|
||||
|
@ -36,10 +36,12 @@ public class LayerBrush implements Brush {
|
||||
BlockTypes.AIR,
|
||||
BlockTypes.CAVE_AIR,
|
||||
BlockTypes.VOID_AIR
|
||||
));
|
||||
), editSession.getMinY(), editSession.getMaxY());
|
||||
final SolidBlockMask solid = new SolidBlockMask(editSession);
|
||||
final RadiusMask radius = new RadiusMask(0, (int) size);
|
||||
visitor = new RecursiveVisitor(new MaskIntersection(adjacent, solid, radius), function -> true);
|
||||
visitor = new RecursiveVisitor(new MaskIntersection(adjacent, solid, radius), funcion -> true, Integer.MAX_VALUE,
|
||||
editSession.getMinY(),
|
||||
editSession.getMaxY());
|
||||
visitor.visit(position);
|
||||
visitor.setDirections(Arrays.asList(BreadthFirstSearch.DIAGONAL_DIRECTIONS));
|
||||
Operations.completeBlindly(visitor);
|
||||
@ -48,7 +50,7 @@ public class LayerBrush implements Brush {
|
||||
int depth = visitor.getDepth();
|
||||
Pattern currentPattern = layers[depth];
|
||||
return currentPattern.apply(editSession, pos, pos);
|
||||
}, layers.length - 1);
|
||||
}, layers.length - 1, editSession.getMinY(), editSession.getMaxY());
|
||||
for (BlockVector3 pos : visited) {
|
||||
visitor.visit(pos);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ public class RecurseBrush implements Brush {
|
||||
visitor.visit(position);
|
||||
Operations.completeBlindly(visitor);
|
||||
} else {
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, radius) {
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, radius, editSession.getMinY(), editSession.getMaxY()) {
|
||||
@Override
|
||||
public boolean isVisitable(BlockVector3 from, BlockVector3 to) {
|
||||
int y = to.getBlockY();
|
||||
|
@ -52,7 +52,8 @@ public class ScatterBrush implements Brush {
|
||||
|
||||
final int distance = Math.min((int) size, this.distance);
|
||||
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(new MaskIntersection(radius, surface), function -> true);
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(new MaskIntersection(radius, surface), function -> true,
|
||||
Integer.MAX_VALUE, editSession.getMinY(), editSession.getMaxY());
|
||||
visitor.visit(position);
|
||||
visitor.setDirections(Arrays.asList(BreadthFirstSearch.DIAGONAL_DIRECTIONS));
|
||||
Operations.completeBlindly(visitor);
|
||||
|
@ -42,7 +42,7 @@ public class SplatterBrush extends ScatterBrush {
|
||||
SurfaceMask surface = new SurfaceMask(editSession);
|
||||
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(new SplatterBrushMask(editSession, position, size2, surface, placed),
|
||||
vector -> editSession.setBlock(vector, finalPattern), recursion
|
||||
vector -> editSession.setBlock(vector, finalPattern), recursion, editSession.getMinY(), editSession.getMaxY()
|
||||
);
|
||||
visitor.setMaxBranch(2);
|
||||
visitor.setDirections(Arrays.asList(BreadthFirstSearch.DIAGONAL_DIRECTIONS));
|
||||
|
@ -21,8 +21,9 @@ public class StencilBrush extends HeightBrush {
|
||||
|
||||
private final boolean onlyWhite;
|
||||
|
||||
public StencilBrush(InputStream stream, int rotation, double yscale, boolean onlyWhite, Clipboard clipboard) {
|
||||
super(stream, rotation, yscale, false, true, clipboard);
|
||||
public StencilBrush(InputStream stream, int rotation, double yscale, boolean onlyWhite, Clipboard clipboard, int minY,
|
||||
int maxY) {
|
||||
super(stream, rotation, yscale, false, true, clipboard, minY, maxY);
|
||||
this.onlyWhite = onlyWhite;
|
||||
}
|
||||
|
||||
@ -32,15 +33,16 @@ public class StencilBrush extends HeightBrush {
|
||||
int size = (int) sizeDouble;
|
||||
int size2 = (int) (sizeDouble * sizeDouble);
|
||||
int maxY = editSession.getMaxY();
|
||||
int minY = editSession.getMinY();
|
||||
int add;
|
||||
if (yscale < 0) {
|
||||
add = maxY;
|
||||
add = maxY - minY;
|
||||
} else {
|
||||
add = 0;
|
||||
}
|
||||
final HeightMap map = getHeightMap();
|
||||
map.setSize(size);
|
||||
int cutoff = onlyWhite ? maxY : 0;
|
||||
int cutoff = onlyWhite ? maxY - minY : 0;
|
||||
final SolidBlockMask solid = new SolidBlockMask(editSession);
|
||||
|
||||
Location loc = editSession.getPlayer().getLocation();
|
||||
@ -48,7 +50,7 @@ public class StencilBrush extends HeightBrush {
|
||||
float pitch = loc.getPitch();
|
||||
AffineTransform transform = new AffineTransform().rotateY((-yaw) % 360).rotateX(pitch - 90).inverse();
|
||||
|
||||
double scale = (yscale / sizeDouble) * (maxY + 1);
|
||||
double scale = (yscale / sizeDouble) * (maxY - minY + 1);
|
||||
RecursiveVisitor visitor =
|
||||
new RecursiveVisitor(new StencilBrushMask(
|
||||
editSession,
|
||||
@ -63,7 +65,7 @@ public class StencilBrush extends HeightBrush {
|
||||
maxY,
|
||||
pattern
|
||||
),
|
||||
vector -> true, Integer.MAX_VALUE
|
||||
vector -> true, Integer.MAX_VALUE, editSession.getMinY(), editSession.getMaxY()
|
||||
);
|
||||
visitor.setDirections(Arrays.asList(BreadthFirstSearch.DIAGONAL_DIRECTIONS));
|
||||
visitor.visit(center);
|
||||
|
@ -25,7 +25,7 @@ public class SurfaceSphereBrush implements Brush {
|
||||
final RadiusMask radius = new RadiusMask(0, (int) size);
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(
|
||||
new MaskIntersection(surface, radius),
|
||||
vector -> editSession.setBlock(vector, pattern)
|
||||
vector -> editSession.setBlock(vector, pattern), Integer.MAX_VALUE, editSession.getMinY(), editSession.getMaxY()
|
||||
);
|
||||
visitor.visit(position);
|
||||
visitor.setDirections(Arrays.asList(BreadthFirstSearch.DIAGONAL_DIRECTIONS));
|
||||
|
@ -37,13 +37,14 @@ public class SurfaceSpline implements Brush {
|
||||
public void build(EditSession editSession, BlockVector3 pos, Pattern pattern, double radius) throws
|
||||
MaxChangedBlocksException {
|
||||
int maxY = editSession.getMaxY();
|
||||
int minY = editSession.getMinY();
|
||||
if (path.isEmpty() || !pos.equals(path.get(path.size() - 1))) {
|
||||
int max = editSession.getNearestSurfaceTerrainBlock(
|
||||
pos.getBlockX(),
|
||||
pos.getBlockZ(),
|
||||
pos.getBlockY(),
|
||||
0,
|
||||
editSession.getMaxY()
|
||||
minY,
|
||||
maxY
|
||||
);
|
||||
if (max == -1) {
|
||||
return;
|
||||
@ -71,7 +72,7 @@ public class SurfaceSpline implements Brush {
|
||||
final int tipx = MathMan.roundInt(tipv.getX());
|
||||
final int tipz = (int) tipv.getZ();
|
||||
int tipy = MathMan.roundInt(tipv.getY());
|
||||
tipy = editSession.getNearestSurfaceTerrainBlock(tipx, tipz, tipy, 0, maxY);
|
||||
tipy = editSession.getNearestSurfaceTerrainBlock(tipx, tipz, tipy, minY, maxY);
|
||||
if (tipy == -1) {
|
||||
continue;
|
||||
}
|
||||
|
@ -5,9 +5,13 @@ import com.fastasyncworldedit.core.function.mask.AdjacentAnyMask;
|
||||
import com.fastasyncworldedit.core.function.mask.AdjacentMask;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.command.util.SuggestionHelper;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extension.platform.Locatable;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.stream.Stream;
|
||||
@ -43,7 +47,7 @@ public class AdjacentMaskParser extends RichParser<Mask> {
|
||||
max = min;
|
||||
}
|
||||
if (max >= 8 && min == 1) {
|
||||
return new AdjacentAnyMask(subMask);
|
||||
return new AdjacentAnyMask(subMask, context.getMinY(), context.getMaxY());
|
||||
}
|
||||
return new AdjacentMask(subMask, min, max);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ public class RichOffsetMaskParser extends RichParser<Mask> {
|
||||
int y = Integer.parseInt(arguments[1]);
|
||||
int z = Integer.parseInt(arguments[2]);
|
||||
Mask submask = worldEdit.getMaskFactory().parseFromInput(arguments[3], context);
|
||||
return new OffsetMask(submask, BlockVector3.at(x, y, z));
|
||||
return new OffsetMask(submask, BlockVector3.at(x, y, z), context.getMinY(), context.getMaxY());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -58,10 +58,7 @@ public class OffsetPatternParser extends RichParser<Pattern> {
|
||||
} else {
|
||||
x = y = z = Integer.parseInt(arguments[1]);
|
||||
}
|
||||
Extent extent = context.requireExtent();
|
||||
int minY = extent.getMinY();
|
||||
int maxY = extent.getMaxY();
|
||||
return new OffsetPattern(inner, x, y, z, minY, maxY);
|
||||
return new OffsetPattern(inner, x, y, z, context.getMinY(), context.getMaxY());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -58,8 +58,7 @@ public class RandomOffsetPatternParser extends RichParser<Pattern> {
|
||||
} else {
|
||||
x = y = z = Integer.parseInt(arguments[1]);
|
||||
}
|
||||
Extent extent = context.requireExtent();
|
||||
return new RandomOffsetPattern(inner, x, y, z, extent.getMinY(), extent.getMaxY());
|
||||
return new RandomOffsetPattern(inner, x, y, z, context.getMinY(), context.getMaxY());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -41,8 +41,7 @@ public class RelativePatternParser extends RichParser<Pattern> {
|
||||
));
|
||||
}
|
||||
Pattern inner = this.worldEdit.getPatternFactory().parseFromInput(input[0], context);
|
||||
Extent extent = context.requireExtent();
|
||||
return new RelativePattern(inner, extent.getMinY(), extent.getMaxY());
|
||||
return new RelativePattern(inner, context.getMinY(), context.getMaxY());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -58,8 +58,7 @@ public class SolidRandomOffsetPatternParser extends RichParser<Pattern> {
|
||||
} else {
|
||||
x = y = z = Integer.parseInt(arguments[1]);
|
||||
}
|
||||
Extent extent = context.requireExtent();
|
||||
return new SolidRandomOffsetPattern(inner, x, y, z, extent.getMinY(), extent.getMaxY());
|
||||
return new SolidRandomOffsetPattern(inner, x, y, z, context.getMinY(), context.getMaxY());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -47,8 +47,7 @@ public class SurfaceRandomOffsetPatternParser extends RichParser<Pattern> {
|
||||
}
|
||||
Pattern inner = this.worldEdit.getPatternFactory().parseFromInput(arguments[0], context);
|
||||
int distance = Integer.parseInt(arguments[1]);
|
||||
Extent extent = context.requireExtent();
|
||||
return new SurfaceRandomOffsetPattern(inner, distance, extent.getMinY(), extent.getMaxY());
|
||||
return new SurfaceRandomOffsetPattern(inner, distance, context.getMinY(), context.getMaxY());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public class ExtentHeightCacher extends PassthroughExtent {
|
||||
index = rx + (rz << 8);
|
||||
}
|
||||
int result = cacheHeights[index] & 0xFF;
|
||||
if (result == 0) {
|
||||
if (result == minY) {
|
||||
cacheHeights[index] = (byte) (result = lastY = super
|
||||
.getNearestSurfaceTerrainBlock(x, z, lastY, minY, maxY));
|
||||
}
|
||||
|
@ -217,6 +217,11 @@ public class NullExtent extends FaweRegionExtent implements IBatchProcessor {
|
||||
throw reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
throw reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockArrayClipboard lazyCopy(Region region) {
|
||||
throw reason;
|
||||
@ -273,21 +278,6 @@ public class NullExtent extends FaweRegionExtent implements IBatchProcessor {
|
||||
throw reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) {
|
||||
throw reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
|
||||
throw reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) {
|
||||
throw reason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) {
|
||||
throw reason;
|
||||
|
@ -71,7 +71,7 @@ public abstract class ChunkFilterBlock extends AbstractExtentFilterBlock {
|
||||
*/
|
||||
public final IChunkSet filter(IChunk chunk, IChunkGet get, IChunkSet set, Filter filter) {
|
||||
initChunk(chunk.getX(), chunk.getZ());
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
for (int layer = get.getMinSectionIndex(); layer <= get.getMaxSectionIndex(); layer++) {
|
||||
if (set.hasSection(layer)) {
|
||||
initLayer(get, set, layer);
|
||||
filter(filter);
|
||||
@ -87,7 +87,7 @@ public abstract class ChunkFilterBlock extends AbstractExtentFilterBlock {
|
||||
if (region != null) {
|
||||
region.filter(chunk, filter, this, get, set, full);
|
||||
} else {
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
for (int layer = get.getMinSectionIndex(); layer <= get.getMaxSectionIndex(); layer++) {
|
||||
if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -119,92 +119,92 @@ public class LimitExtent extends AbstractDelegateExtent {
|
||||
|
||||
@Override
|
||||
public int getHighestTerrainBlock(int x, int z, int minY, int maxY) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||
try {
|
||||
return super.getHighestTerrainBlock(x, z, minY, maxY);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
return minY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||
try {
|
||||
return super.getHighestTerrainBlock(x, z, minY, maxY, filter);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
return minY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||
try {
|
||||
return super.getNearestSurfaceLayer(x, z, y, minY, maxY);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
return minY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||
try {
|
||||
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
return minY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||
try {
|
||||
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
return minY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||
try {
|
||||
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
return minY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||
try {
|
||||
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
return minY;
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,14 +219,14 @@ public class LimitExtent extends AbstractDelegateExtent {
|
||||
int failedMax,
|
||||
boolean ignoreAir
|
||||
) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||
try {
|
||||
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
return minY;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,15 @@ public class ArrayHeightMap extends ScalableHeightMap {
|
||||
private double rx;
|
||||
private double rz;
|
||||
|
||||
public ArrayHeightMap(byte[][] height) {
|
||||
/**
|
||||
* New height map represented by byte array[][] of values x*z to be scaled given a set size
|
||||
*
|
||||
* @param height array of height values
|
||||
* @param minY min y value allowed to be set. Inclusive.
|
||||
* @param maxY max y value allowed to be set. Inclusive.
|
||||
*/
|
||||
public ArrayHeightMap(byte[][] height, int minY, int maxY) {
|
||||
super(minY, maxY);
|
||||
setSize(5);
|
||||
this.height = height;
|
||||
this.width = height.length;
|
||||
|
@ -2,8 +2,15 @@ package com.fastasyncworldedit.core.extent.processor.heightmap;
|
||||
|
||||
public class FlatScalableHeightMap extends ScalableHeightMap {
|
||||
|
||||
public FlatScalableHeightMap() {
|
||||
super();
|
||||
/**
|
||||
* New height map where the returned height is the minmum height value if outside the size, otherwise returns height equal
|
||||
* to size.
|
||||
*
|
||||
* @param minY min y value allowed to be set. Inclusive.
|
||||
* @param maxY max y value allowed to be set. Inclusive.
|
||||
*/
|
||||
public FlatScalableHeightMap(int minY, int maxY) {
|
||||
super(minY, maxY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -12,7 +19,7 @@ public class FlatScalableHeightMap extends ScalableHeightMap {
|
||||
int dz = Math.abs(z);
|
||||
int d2 = dx * dx + dz * dz;
|
||||
if (d2 > size2) {
|
||||
return 0;
|
||||
return minY;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ public interface HeightMap {
|
||||
|
||||
void setSize(int size);
|
||||
|
||||
|
||||
default void perform(
|
||||
EditSession session,
|
||||
Mask mask,
|
||||
@ -83,8 +82,8 @@ public interface HeightMap {
|
||||
boolean towards,
|
||||
final boolean layers
|
||||
) {
|
||||
BlockVector3 top = session.getMaximumPoint();
|
||||
int maxY = top.getBlockY();
|
||||
int maxY = session.getMaxY();
|
||||
int minY = session.getMinY();
|
||||
int diameter = 2 * size + 1;
|
||||
int centerX = pos.getBlockX();
|
||||
int centerZ = pos.getBlockZ();
|
||||
@ -121,15 +120,15 @@ public interface HeightMap {
|
||||
}
|
||||
int height;
|
||||
if (layers) {
|
||||
height = tmpY = session.getNearestSurfaceLayer(xx, zz, tmpY, 0, maxY);
|
||||
height = tmpY = session.getNearestSurfaceLayer(xx, zz, tmpY, minY, maxY);
|
||||
} else {
|
||||
height = tmpY = session.getNearestSurfaceTerrainBlock(xx, zz, tmpY, 0, maxY);
|
||||
height = tmpY = session.getNearestSurfaceTerrainBlock(xx, zz, tmpY, minY, maxY);
|
||||
if (height == -1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
oldData[index] = height;
|
||||
if (height == 0) {
|
||||
if (height == minY) {
|
||||
newData[index] = centerY;
|
||||
continue;
|
||||
}
|
||||
@ -137,8 +136,9 @@ public interface HeightMap {
|
||||
int diff = targetY - height;
|
||||
double raiseScaled = diff * (raisePow * sizePowInv);
|
||||
double raiseScaledAbs = Math.abs(raiseScaled);
|
||||
int random = ThreadLocalRandom.current().nextInt(256) < (int) ((Math.ceil(raiseScaledAbs) - Math.floor(
|
||||
raiseScaledAbs)) * 256) ? (diff > 0 ? 1 : -1) : 0;
|
||||
int random =
|
||||
ThreadLocalRandom.current().nextInt(maxY + 1 - minY) - minY < (int) ((Math.ceil(raiseScaledAbs) - Math.floor(
|
||||
raiseScaledAbs)) * (maxY + 1 - minY)) ? (diff > 0 ? 1 : -1) : 0;
|
||||
int raiseScaledInt = (int) raiseScaled + random;
|
||||
newData[index] = height + raiseScaledInt;
|
||||
}
|
||||
@ -166,20 +166,22 @@ public interface HeightMap {
|
||||
break;
|
||||
}
|
||||
if (layers) {
|
||||
height = session.getNearestSurfaceLayer(xx, zz, height, 0, maxY);
|
||||
height = session.getNearestSurfaceLayer(xx, zz, height, minY, maxY);
|
||||
} else {
|
||||
height = session.getNearestSurfaceTerrainBlock(xx, zz, height, 0, maxY);
|
||||
if (height == -1) {
|
||||
height = session.getNearestSurfaceTerrainBlock(xx, zz, height, minY, maxY);
|
||||
if (height == minY - 1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
oldData[index] = height;
|
||||
if (height == 0) {
|
||||
if (height == minY) {
|
||||
newData[index] = centerY;
|
||||
continue;
|
||||
}
|
||||
raise = (yscale * raise);
|
||||
int random = ThreadLocalRandom.current().nextInt(256) < (int) ((raise - (int) raise) * (256)) ? 1 : 0;
|
||||
int random =
|
||||
ThreadLocalRandom.current().nextInt(maxY + 1 - minY) - minY < (int) ((raise - (int) raise) * (maxY - minY + 1))
|
||||
? 1 : 0;
|
||||
int newHeight = height + (int) raise + random;
|
||||
newData[index] = newHeight;
|
||||
}
|
||||
|
@ -18,20 +18,26 @@ public class ScalableHeightMap implements HeightMap {
|
||||
|
||||
public int size2;
|
||||
public int size;
|
||||
protected int minY;
|
||||
protected int maxY;
|
||||
|
||||
public enum Shape {
|
||||
CONE,
|
||||
CYLINDER,
|
||||
}
|
||||
|
||||
public ScalableHeightMap() {
|
||||
/**
|
||||
* New height map.
|
||||
*
|
||||
* @param minY min y value allowed to be set. Inclusive.
|
||||
* @param maxY max y value allowed to be set. Inclusive.
|
||||
*/
|
||||
public ScalableHeightMap(final int minY, final int maxY) {
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
setSize(5);
|
||||
}
|
||||
|
||||
public ScalableHeightMap(int size) {
|
||||
setSize(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
@ -44,29 +50,29 @@ public class ScalableHeightMap implements HeightMap {
|
||||
int dz = Math.abs(z);
|
||||
int d2 = dx * dx + dz * dz;
|
||||
if (d2 > size2) {
|
||||
return 0;
|
||||
return minY;
|
||||
}
|
||||
return Math.max(0, size - MathMan.sqrtApprox(d2));
|
||||
return Math.max(minY, size - MathMan.sqrtApprox(d2));
|
||||
}
|
||||
|
||||
public static ScalableHeightMap fromShape(Shape shape) {
|
||||
public static ScalableHeightMap fromShape(Shape shape, int minY, int maxY) {
|
||||
switch (shape) {
|
||||
default:
|
||||
case CONE:
|
||||
return new ScalableHeightMap();
|
||||
return new ScalableHeightMap(minY, maxY);
|
||||
case CYLINDER:
|
||||
return new FlatScalableHeightMap();
|
||||
return new FlatScalableHeightMap(minY, maxY);
|
||||
}
|
||||
}
|
||||
|
||||
public static ScalableHeightMap fromClipboard(Clipboard clipboard) {
|
||||
public static ScalableHeightMap fromClipboard(Clipboard clipboard, int minY, int maxY) {
|
||||
BlockVector3 dim = clipboard.getDimensions();
|
||||
byte[][] heightArray = new byte[dim.getBlockX()][dim.getBlockZ()];
|
||||
int minX = clipboard.getMinimumPoint().getBlockX();
|
||||
int minZ = clipboard.getMinimumPoint().getBlockZ();
|
||||
int minY = clipboard.getMinimumPoint().getBlockY();
|
||||
int maxY = clipboard.getMaximumPoint().getBlockY();
|
||||
int clipHeight = maxY - minY + 1;
|
||||
int clipMinX = clipboard.getMinimumPoint().getBlockX();
|
||||
int clipMinZ = clipboard.getMinimumPoint().getBlockZ();
|
||||
int clipMinY = clipboard.getMinimumPoint().getBlockY();
|
||||
int clipMaxY = clipboard.getMaximumPoint().getBlockY();
|
||||
int clipHeight = clipMaxY - clipMinY + 1;
|
||||
HashSet<IntPair> visited = new HashSet<>();
|
||||
MutableBlockVector3 bv = new MutableBlockVector3();
|
||||
for (BlockVector3 pos : clipboard.getRegion()) {
|
||||
@ -77,24 +83,24 @@ public class ScalableHeightMap implements HeightMap {
|
||||
visited.add(pair);
|
||||
int xx = pos.getBlockX();
|
||||
int zz = pos.getBlockZ();
|
||||
int highestY = minY;
|
||||
int highestY = clipMinY;
|
||||
bv.setComponents(pos);
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
for (int y = clipMinY; y <= clipMaxY; y++) {
|
||||
bv.mutY(y);
|
||||
BlockState block = clipboard.getBlock(bv);
|
||||
if (!block.getBlockType().getMaterial().isAir()) {
|
||||
highestY = y + 1;
|
||||
}
|
||||
}
|
||||
int pointHeight = Math.min(255, (256 * (highestY - minY)) / clipHeight);
|
||||
int x = xx - minX;
|
||||
int z = zz - minZ;
|
||||
int pointHeight = Math.min(clipMaxY, ((maxY - minY + 1 ) * (highestY - clipMinY)) / clipHeight);
|
||||
int x = xx - clipMinX;
|
||||
int z = zz - clipMinZ;
|
||||
heightArray[x][z] = (byte) pointHeight;
|
||||
}
|
||||
return new ArrayHeightMap(heightArray);
|
||||
return new ArrayHeightMap(heightArray, minY, maxY);
|
||||
}
|
||||
|
||||
public static ScalableHeightMap fromPNG(InputStream stream) throws IOException {
|
||||
public static ScalableHeightMap fromPNG(InputStream stream, int minY, int maxY) throws IOException {
|
||||
BufferedImage heightFile = MainUtil.readImage(stream);
|
||||
int width = heightFile.getWidth();
|
||||
int length = heightFile.getHeight();
|
||||
@ -113,7 +119,7 @@ public class ScalableHeightMap implements HeightMap {
|
||||
array[x][z] = (byte) intensity;
|
||||
}
|
||||
}
|
||||
return new ArrayHeightMap(array);
|
||||
return new ArrayHeightMap(array, minY, maxY);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -60,11 +60,12 @@ public class NMSRelighter implements Relighter {
|
||||
private final ConcurrentHashMap<Long, long[][][]> concurrentLightQueue;
|
||||
private final RelightMode relightMode;
|
||||
private final int maxY;
|
||||
private final int minY;
|
||||
private final ReentrantLock lightingLock;
|
||||
private final AtomicBoolean finished = new AtomicBoolean(false);
|
||||
private boolean removeFirst;
|
||||
|
||||
public NMSRelighter(IQueueExtent<IQueueChunk> queue, boolean calculateHeightMaps) {
|
||||
public NMSRelighter(IQueueExtent<IQueueChunk> queue) {
|
||||
this(queue, null);
|
||||
}
|
||||
|
||||
@ -75,6 +76,7 @@ public class NMSRelighter implements Relighter {
|
||||
this.chunksToSend = new Long2ObjectOpenHashMap<>(12);
|
||||
this.concurrentLightQueue = new ConcurrentHashMap<>(12);
|
||||
this.maxY = queue.getMaxY();
|
||||
this.minY = queue.getMinY();
|
||||
this.relightMode = relightMode != null ? relightMode : RelightMode.valueOf(Settings.IMP.LIGHTING.MODE);
|
||||
this.lightingLock = new ReentrantLock();
|
||||
}
|
||||
@ -118,6 +120,8 @@ public class NMSRelighter implements Relighter {
|
||||
if (m2 == null) {
|
||||
m2 = m1[x] = new long[4];
|
||||
}
|
||||
// Account for negative y values by "adding" minY
|
||||
y -= minY;
|
||||
m2[y >> 6] |= 1L << y;
|
||||
}
|
||||
|
||||
@ -132,6 +136,8 @@ public class NMSRelighter implements Relighter {
|
||||
this.lightQueue.put(index, currentMap);
|
||||
}
|
||||
set(x & 15, y, z & 15, currentMap);
|
||||
this.lightQueue.putAll(concurrentLightQueue);
|
||||
concurrentLightQueue.clear();
|
||||
} finally {
|
||||
lightLock.set(false);
|
||||
}
|
||||
@ -154,7 +160,7 @@ public class NMSRelighter implements Relighter {
|
||||
}
|
||||
|
||||
public boolean addChunk(int cx, int cz, byte[] fix, int bitmask) {
|
||||
RelightSkyEntry toPut = new RelightSkyEntry(cx, cz, fix, bitmask);
|
||||
RelightSkyEntry toPut = new RelightSkyEntry(cx, cz, fix, bitmask, minY, maxY);
|
||||
extendSkyToRelight.add(toPut);
|
||||
return true;
|
||||
}
|
||||
@ -188,7 +194,7 @@ public class NMSRelighter implements Relighter {
|
||||
if (!iChunk.isInit()) {
|
||||
iChunk.init(queue, chunk.x, chunk.z);
|
||||
}
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int i = minY >> 4; i <= maxY >> 4; i++) {
|
||||
iChunk.removeSectionLighting(i, true);
|
||||
}
|
||||
iter.remove();
|
||||
@ -238,7 +244,7 @@ public class NMSRelighter implements Relighter {
|
||||
for (int j = 0; j < 64; j++) {
|
||||
if (((value >> j) & 1) == 1) {
|
||||
int x = lx + bx;
|
||||
int y = yStart + j;
|
||||
int y = yStart + j + minY;
|
||||
int z = lz + bz;
|
||||
int oldLevel = iChunk.getEmittedLight(lx, y, lz);
|
||||
int newLevel = iChunk.getBrightness(lx, y, lz);
|
||||
@ -287,7 +293,7 @@ public class NMSRelighter implements Relighter {
|
||||
removalVisited,
|
||||
visited
|
||||
);
|
||||
if (node.getY() > 0) {
|
||||
if (node.getY() > minY) {
|
||||
this.computeRemoveBlockLight(
|
||||
node.getX(),
|
||||
node.getY() - 1,
|
||||
@ -299,7 +305,7 @@ public class NMSRelighter implements Relighter {
|
||||
visited
|
||||
);
|
||||
}
|
||||
if (node.getY() < 255) {
|
||||
if (node.getY() < maxY) {
|
||||
this.computeRemoveBlockLight(
|
||||
node.getX(),
|
||||
node.getY() + 1,
|
||||
@ -650,7 +656,7 @@ public class NMSRelighter implements Relighter {
|
||||
this.computeSpreadBlockLight(x, y - 1, z, currentLight, queue, visited);
|
||||
}
|
||||
state = this.queue.getBlock(x, y + 1, z);
|
||||
if (y < 255 && !top && isSlabOrTrueValue(state, "top") && isStairOrTrueTop(state, true)) {
|
||||
if (y < maxY && !top && isSlabOrTrueValue(state, "top") && isStairOrTrueTop(state, true)) {
|
||||
this.computeSpreadBlockLight(x, y + 1, z, currentLight, queue, visited);
|
||||
}
|
||||
}
|
||||
@ -696,7 +702,7 @@ public class NMSRelighter implements Relighter {
|
||||
this.computeSpreadBlockLight(x, y - 1, z, currentLight, queue, visited);
|
||||
}
|
||||
state = this.queue.getBlock(x, y + 1, z);
|
||||
if (y < 255 && isSlabOrTrueValue(state, "top") && isStairOrTrueTop(state, false)) {
|
||||
if (y < maxY && isSlabOrTrueValue(state, "top") && isStairOrTrueTop(state, false)) {
|
||||
this.computeSpreadBlockLight(x, y + 1, z, currentLight, queue, visited);
|
||||
}
|
||||
}
|
||||
@ -944,7 +950,7 @@ public class NMSRelighter implements Relighter {
|
||||
int z = MathMan.unpairIntY(pair);
|
||||
ChunkHolder<?> chunk = (ChunkHolder<?>) queue.getOrCreateChunk(x, z);
|
||||
chunk.setBitMask(bitMask);
|
||||
chunk.flushLightToGet(true);
|
||||
chunk.flushLightToGet();
|
||||
Fawe.imp().getPlatformAdapter().sendChunk(chunk.getOrCreateGet(), bitMask, true);
|
||||
iter.remove();
|
||||
}
|
||||
@ -984,7 +990,7 @@ public class NMSRelighter implements Relighter {
|
||||
}
|
||||
}
|
||||
|
||||
public void fill(byte[] mask, int chunkX, int y, int chunkZ, byte reason) {
|
||||
public void fill(byte[] mask, ChunkHolder<?> iChunk, int y, byte reason) {
|
||||
if (y >= 16) {
|
||||
Arrays.fill(mask, (byte) 15);
|
||||
return;
|
||||
@ -995,12 +1001,10 @@ public class NMSRelighter implements Relighter {
|
||||
return;
|
||||
}
|
||||
case SkipReason.AIR: {
|
||||
int bx = chunkX << 4;
|
||||
int bz = chunkZ << 4;
|
||||
int index = 0;
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
mask[index++] = (byte) queue.getSkyLight(bx + x, y, bz + z);
|
||||
mask[index++] = (byte) iChunk.getSkyLight(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1026,19 +1030,19 @@ public class NMSRelighter implements Relighter {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int y = 255; y > 0; y--) {
|
||||
for (int y = maxY; y > minY; y--) {
|
||||
for (RelightSkyEntry chunk : chunks) { // Propagate skylight
|
||||
int layer = y >> 4;
|
||||
int layer = (y - minY) >> 4;
|
||||
byte[] mask = chunk.mask;
|
||||
if (chunk.fix[layer] != SkipReason.NONE) {
|
||||
if ((y & 15) == 0 && layer != 0 && chunk.fix[layer - 1] == SkipReason.NONE) {
|
||||
fill(mask, chunk.x, y, chunk.z, chunk.fix[layer]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
int bx = chunk.x << 4;
|
||||
int bz = chunk.z << 4;
|
||||
ChunkHolder<?> iChunk = (ChunkHolder<?>) queue.getOrCreateChunk(chunk.x, chunk.z);
|
||||
if (chunk.fix[layer] != SkipReason.NONE) {
|
||||
if ((y & 15) == 0 && layer != 0 && chunk.fix[layer - 1] == SkipReason.NONE) {
|
||||
fill(mask, iChunk, y, chunk.fix[layer]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!iChunk.isInit()) {
|
||||
iChunk.init(queue, chunk.x, chunk.z);
|
||||
}
|
||||
@ -1157,29 +1161,29 @@ public class NMSRelighter implements Relighter {
|
||||
}
|
||||
byte value = mask[j];
|
||||
if (x != 0 && z != 0) {
|
||||
if ((value = (byte) Math.max(iChunk.getSkyLight(x - 1, y, z) - 1, value)) >= 14) {
|
||||
} else if ((value = (byte) Math.max(iChunk.getSkyLight(x, y, z - 1) - 1, value)) >= 14) {
|
||||
if ((value = (byte) Math.max(iChunk.getSkyLight(x - 1, y, z) - 1, value)) < 14) {
|
||||
value = (byte) Math.max(iChunk.getSkyLight(x, y, z - 1) - 1, value);
|
||||
}
|
||||
if (value > mask[j]) {
|
||||
iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
}
|
||||
} else if (x == 0 && z == 0) {
|
||||
if ((value = (byte) Math.max(iChunkx.getSkyLight(15, y, z) - 1, value)) >= 14) {
|
||||
} else if ((value = (byte) Math.max(iChunkz.getSkyLight(x, y, 15) - 1, value)) >= 14) {
|
||||
if ((value = (byte) Math.max(iChunkx.getSkyLight(15, y, z) - 1, value)) < 14) {
|
||||
value = (byte) Math.max(iChunkz.getSkyLight(x, y, 15) - 1, value);
|
||||
}
|
||||
if (value > mask[j]) {
|
||||
iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
}
|
||||
} else if (x == 0) {
|
||||
if ((value = (byte) Math.max(iChunkx.getSkyLight(15, y, z) - 1, value)) >= 14) {
|
||||
} else if ((value = (byte) Math.max(iChunk.getSkyLight(x, y, z - 1) - 1, value)) >= 14) {
|
||||
if ((value = (byte) Math.max(iChunkx.getSkyLight(15, y, z) - 1, value)) < 14) {
|
||||
value = (byte) Math.max(iChunk.getSkyLight(x, y, z - 1) - 1, value);
|
||||
}
|
||||
if (value > mask[j]) {
|
||||
iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
}
|
||||
} else {
|
||||
if ((value = (byte) Math.max(iChunk.getSkyLight(x - 1, y, z) - 1, value)) >= 14) {
|
||||
} else if ((value = (byte) Math.max(iChunkz.getSkyLight(x, y, 15) - 1, value)) >= 14) {
|
||||
if ((value = (byte) Math.max(iChunk.getSkyLight(x - 1, y, z) - 1, value)) < 14) {
|
||||
value = (byte) Math.max(iChunkz.getSkyLight(x, y, 15) - 1, value);
|
||||
}
|
||||
if (value > mask[j]) {
|
||||
iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
@ -1203,29 +1207,29 @@ public class NMSRelighter implements Relighter {
|
||||
}
|
||||
byte value = mask[j];
|
||||
if (x != 15 && z != 15) {
|
||||
if ((value = (byte) Math.max(iChunk.getSkyLight(x + 1, y, z) - 1, value)) >= 14) {
|
||||
} else if ((value = (byte) Math.max(iChunk.getSkyLight(x, y, z + 1) - 1, value)) >= 14) {
|
||||
if ((value = (byte) Math.max(iChunk.getSkyLight(x + 1, y, z) - 1, value)) < 14) {
|
||||
value = (byte) Math.max(iChunk.getSkyLight(x, y, z + 1) - 1, value);
|
||||
}
|
||||
if (value > mask[j]) {
|
||||
iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
}
|
||||
} else if (x == 15 && z == 15) {
|
||||
if ((value = (byte) Math.max(iChunkx.getSkyLight(0, y, z) - 1, value)) >= 14) {
|
||||
} else if ((value = (byte) Math.max(iChunkz.getSkyLight(x, y, 0) - 1, value)) >= 14) {
|
||||
if ((value = (byte) Math.max(iChunkx.getSkyLight(0, y, z) - 1, value)) < 14) {
|
||||
value = (byte) Math.max(iChunkz.getSkyLight(x, y, 0) - 1, value);
|
||||
}
|
||||
if (value > mask[j]) {
|
||||
iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
}
|
||||
} else if (x == 15) {
|
||||
if ((value = (byte) Math.max(iChunkx.getSkyLight(0, y, z) - 1, value)) >= 14) {
|
||||
} else if ((value = (byte) Math.max(iChunk.getSkyLight(x, y, z + 1) - 1, value)) >= 14) {
|
||||
if ((value = (byte) Math.max(iChunkx.getSkyLight(0, y, z) - 1, value)) < 14) {
|
||||
value = (byte) Math.max(iChunk.getSkyLight(x, y, z + 1) - 1, value);
|
||||
}
|
||||
if (value > mask[j]) {
|
||||
iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
}
|
||||
} else {
|
||||
if ((value = (byte) Math.max(iChunk.getSkyLight(x + 1, y, z) - 1, value)) >= 14) {
|
||||
} else if ((value = (byte) Math.max(iChunkz.getSkyLight(x, y, 0) - 1, value)) >= 14) {
|
||||
if ((value = (byte) Math.max(iChunk.getSkyLight(x + 1, y, z) - 1, value)) < 14) {
|
||||
value = (byte) Math.max(iChunkz.getSkyLight(x, y, 0) - 1, value);
|
||||
}
|
||||
if (value > mask[j]) {
|
||||
iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
@ -1235,7 +1239,7 @@ public class NMSRelighter implements Relighter {
|
||||
}
|
||||
}
|
||||
|
||||
private class RelightSkyEntry implements Comparable<RelightSkyEntry> {
|
||||
private static class RelightSkyEntry implements Comparable<RelightSkyEntry> {
|
||||
|
||||
public final int x;
|
||||
public final int z;
|
||||
@ -1244,7 +1248,7 @@ public class NMSRelighter implements Relighter {
|
||||
public int bitmask;
|
||||
public boolean smooth;
|
||||
|
||||
public RelightSkyEntry(int x, int z, byte[] fix, int bitmask) {
|
||||
private RelightSkyEntry(int x, int z, byte[] fix, int bitmask, int minY, int maxY) {
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
byte[] array = new byte[256];
|
||||
@ -1252,13 +1256,14 @@ public class NMSRelighter implements Relighter {
|
||||
this.mask = array;
|
||||
this.bitmask = bitmask;
|
||||
if (fix == null) {
|
||||
this.fix = new byte[(maxY + 1) >> 4];
|
||||
this.fix = new byte[(maxY - minY + 1) >> 4];
|
||||
Arrays.fill(this.fix, SkipReason.NONE);
|
||||
} else {
|
||||
this.fix = fix;
|
||||
}
|
||||
}
|
||||
|
||||
//Following are public because they are public in Object. NONE of this nested class is API.
|
||||
@Override
|
||||
public String toString() {
|
||||
return x + "," + z;
|
||||
|
@ -28,11 +28,12 @@ public class RelightProcessor implements IBatchProcessor {
|
||||
if (Settings.IMP.LIGHTING.MODE == 2) {
|
||||
relighter.addChunk(chunk.getX(), chunk.getZ(), null, chunk.getBitMask());
|
||||
} else if (Settings.IMP.LIGHTING.MODE == 1) {
|
||||
byte[] fix = new byte[16];
|
||||
byte[] fix = new byte[get.getSectionCount()];
|
||||
boolean relight = false;
|
||||
for (int i = 15; i >= 0; i--) {
|
||||
for (int i = get.getMaxSectionIndex(); i >= get.getMinSectionIndex(); i--) {
|
||||
if (!set.hasSection(i)) {
|
||||
fix[i] = Relighter.SkipReason.AIR;
|
||||
// Array index cannot be < 0 so "add" the min
|
||||
fix[i - get.getMinSectionIndex()] = Relighter.SkipReason.AIR;
|
||||
continue;
|
||||
}
|
||||
relight = true;
|
||||
|
@ -189,11 +189,11 @@ public class CavesGen extends GenBase {
|
||||
n = 16;
|
||||
}
|
||||
|
||||
if (i1 < 1) {
|
||||
i1 = 1;
|
||||
if (i1 < chunk.getMinY() + 1) {
|
||||
i1 = chunk.getMinY();
|
||||
}
|
||||
if (i2 > 256 - 8) {
|
||||
i2 = 256 - 8;
|
||||
if (i2 >= chunk.getMaxY() - 8) {
|
||||
i2 = chunk.getMaxY() - 8;
|
||||
}
|
||||
if (i3 < 0) {
|
||||
i3 = 0;
|
||||
@ -207,7 +207,7 @@ public class CavesGen extends GenBase {
|
||||
for (int local_x = m; !waterFound && local_x < n; local_x++) {
|
||||
for (int local_z = i3; !waterFound && local_z < i4; local_z++) {
|
||||
for (int local_y = i2 + 1; !waterFound && local_y >= i1 - 1; local_y--) {
|
||||
if (local_y < 255) {
|
||||
if (local_y < chunk.getMaxY()) {
|
||||
BlockState material = chunk.getBlock(bx + local_x, local_y, bz + local_z);
|
||||
if (material.getBlockType() == BlockTypes.WATER) {
|
||||
waterFound = true;
|
||||
|
@ -78,11 +78,11 @@ public class OreGen implements Resource {
|
||||
double d12o2 = d12 * ONE_2;
|
||||
|
||||
int minX = MathMan.floorZero(d7 - d11o2);
|
||||
int minY = Math.max(1, MathMan.floorZero(d8 - d12o2));
|
||||
int minY = Math.max(this.minY + 1, MathMan.floorZero(d8 - d12o2));
|
||||
int minZ = MathMan.floorZero(d9 - d11o2);
|
||||
|
||||
int maxX = MathMan.floorZero(d7 + d11o2);
|
||||
int maxY = Math.min(255, MathMan.floorZero(d8 + d12o2));
|
||||
int maxY = Math.min(this.maxY, MathMan.floorZero(d8 + d12o2));
|
||||
int maxZ = MathMan.floorZero(d9 + d11o2);
|
||||
|
||||
double id11o2 = 1.0 / (d11o2);
|
||||
|
@ -33,7 +33,7 @@ public class SchemGen implements Resource {
|
||||
public boolean spawn(Random random, int x, int z) throws WorldEditException {
|
||||
mutable.mutX(x);
|
||||
mutable.mutZ(z);
|
||||
int y = extent.getNearestSurfaceTerrainBlock(x, z, mutable.getBlockY(), 0, 255);
|
||||
int y = extent.getNearestSurfaceTerrainBlock(x, z, mutable.getBlockY(), this.extent.getMinY(), this.extent.getMaxY());
|
||||
if (y == -1) {
|
||||
return false;
|
||||
}
|
||||
|
@ -12,10 +12,14 @@ public class AdjacentAnyMask extends AbstractMask implements ResettableMask {
|
||||
|
||||
private final CachedMask mask;
|
||||
private final MutableBlockVector3 mutable;
|
||||
private final int minY;
|
||||
private final int maxY;
|
||||
|
||||
public AdjacentAnyMask(Mask mask) {
|
||||
public AdjacentAnyMask(Mask mask, int minY, int maxY) {
|
||||
this.mask = CachedMask.cache(mask);
|
||||
mutable = new MutableBlockVector3();
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -44,9 +48,9 @@ public class AdjacentAnyMask extends AbstractMask implements ResettableMask {
|
||||
return mutable.setComponents(0, 0, 1);
|
||||
} else if (mask.test(x, y, z - 1)) {
|
||||
return mutable.setComponents(0, 0, -1);
|
||||
} else if (y < 256 && mask.test(x, y + 1, z)) {
|
||||
} else if (y < maxY && mask.test(x, y + 1, z)) {
|
||||
return mutable.setComponents(0, 1, 0);
|
||||
} else if (y > 0 && mask.test(x, y - 1, z)) {
|
||||
} else if (y > minY && mask.test(x, y - 1, z)) {
|
||||
return mutable.setComponents(0, -1, 0);
|
||||
} else {
|
||||
return null;
|
||||
@ -55,7 +59,7 @@ public class AdjacentAnyMask extends AbstractMask implements ResettableMask {
|
||||
|
||||
@Override
|
||||
public Mask copy() {
|
||||
return new AdjacentAnyMask(mask.copy());
|
||||
return new AdjacentAnyMask(mask.copy(), minY, maxY);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ public class AngleMask extends SolidBlockMask implements ResettableMask {
|
||||
protected final boolean overlay;
|
||||
protected final boolean checkFirst;
|
||||
protected final int maxY;
|
||||
protected final int minY;
|
||||
protected final int distance;
|
||||
|
||||
public AngleMask(Extent extent, double min, double max, boolean overlay, int distance) {
|
||||
@ -26,7 +27,8 @@ public class AngleMask extends SolidBlockMask implements ResettableMask {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.checkFirst = max >= (Math.tan(90 * (Math.PI / 180)));
|
||||
this.maxY = extent.getMaximumPoint().getBlockY();
|
||||
this.maxY = extent.getMaxY();
|
||||
this.minY = extent.getMinY();
|
||||
this.overlay = overlay;
|
||||
this.distance = distance;
|
||||
}
|
||||
@ -77,7 +79,7 @@ public class AngleMask extends SolidBlockMask implements ResettableMask {
|
||||
}
|
||||
int result = cacheHeights[index] & 0xFF;
|
||||
if (y > result) {
|
||||
cacheHeights[index] = (byte) (result = lastY = extent.getNearestSurfaceTerrainBlock(x, z, lastY, 0, maxY));
|
||||
cacheHeights[index] = (byte) (result = lastY = extent.getNearestSurfaceTerrainBlock(x, z, lastY, minY, maxY));
|
||||
}
|
||||
return result;
|
||||
} catch (Throwable e) {
|
||||
@ -141,10 +143,10 @@ public class AngleMask extends SolidBlockMask implements ResettableMask {
|
||||
if (!mask.test(x, y, z - 1)) {
|
||||
return true;
|
||||
}
|
||||
if (y < 255 && !mask.test(x, y + 1, z)) {
|
||||
if (y < maxY && !mask.test(x, y + 1, z)) {
|
||||
return true;
|
||||
}
|
||||
return y > 0 && !mask.test(x, y - 1, z);
|
||||
return y > minY && !mask.test(x, y - 1, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -164,7 +166,7 @@ public class AngleMask extends SolidBlockMask implements ResettableMask {
|
||||
return false;
|
||||
}
|
||||
if (overlay) {
|
||||
if (y < 255 && !adjacentAir(vector)) {
|
||||
if (y < maxY && !adjacentAir(vector)) {
|
||||
return lastValue = false;
|
||||
}
|
||||
}
|
||||
|
@ -57,9 +57,10 @@ public class CachedMask extends AbstractDelegateMask implements ResettableMask {
|
||||
return result;
|
||||
} catch (UnsupportedOperationException ignored) {
|
||||
boolean result = getMask().test(mutable.setComponents(x, y, z));
|
||||
if (y < 0 || y > 255) {
|
||||
return result;
|
||||
}
|
||||
// Assume that the mask won't be given y outside the world range
|
||||
// if (y < 0 || y > 255) {
|
||||
// return result;
|
||||
//}
|
||||
resetCache();
|
||||
cache_checked.setOffset(x, z);
|
||||
cache_results.setOffset(x, z);
|
||||
|
@ -25,10 +25,10 @@ public class MaskedTargetBlock extends TargetBlock {
|
||||
if (!mask.test(current.toBlockPoint())) {
|
||||
if (searchForLastBlock) {
|
||||
lastBlock = current;
|
||||
if (lastBlock.getBlockY() <= 0 || lastBlock.getBlockY() >= world.getMaxY()) {
|
||||
if (lastBlock.getBlockY() <= world.getMinY() || lastBlock.getBlockY() >= world.getMaxY()) {
|
||||
searchForLastBlock = false;
|
||||
}
|
||||
} else if (current.getBlockY() <= 0) {
|
||||
} else if (current.getBlockY() <= world.getMinY()) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
@ -9,7 +9,7 @@ import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
public class SurfaceMask extends AdjacentAnyMask {
|
||||
|
||||
public SurfaceMask(Extent extent) {
|
||||
super(getMask(extent));
|
||||
super(getMask(extent), extent.getMinY(), extent.getMaxY());
|
||||
}
|
||||
|
||||
public static AbstractExtentMask getMask(Extent extent) {
|
||||
|
@ -45,8 +45,8 @@ public class AngleColorPattern extends AnglePattern {
|
||||
int x = vector.getBlockX();
|
||||
int y = vector.getBlockY();
|
||||
int z = vector.getBlockZ();
|
||||
int height = extent.getNearestSurfaceTerrainBlock(x, z, y, 0, maxY);
|
||||
if (height > 0) {
|
||||
int height = extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY);
|
||||
if (height > minY) {
|
||||
BlockState below = extent.getBlock(x, height - 1, z);
|
||||
if (!below.getBlockType().getMaterial().isMovementBlocker()) {
|
||||
return Integer.MAX_VALUE;
|
||||
|
@ -13,6 +13,7 @@ public abstract class AnglePattern extends AbstractPattern {
|
||||
public final double factor;
|
||||
public final Extent extent;
|
||||
public final int maxY;
|
||||
public final int minY;
|
||||
public final int distance;
|
||||
|
||||
/**
|
||||
@ -23,9 +24,10 @@ public abstract class AnglePattern extends AbstractPattern {
|
||||
*/
|
||||
public AnglePattern(Extent extent, int distance) {
|
||||
this.extent = new ExtentHeightCacher(extent);
|
||||
this.maxY = extent.getMaximumPoint().getBlockY();
|
||||
this.maxY = extent.getMaxY();
|
||||
this.minY = extent.getMinY();
|
||||
this.distance = distance;
|
||||
this.factor = (1D / distance) * (1D / 255);
|
||||
this.factor = (1D / distance) * (1D / maxY);
|
||||
}
|
||||
|
||||
public <T extends BlockStateHolder<T>> int getSlope(T block, BlockVector3 vector, Extent extent) {
|
||||
@ -36,29 +38,29 @@ public abstract class AnglePattern extends AbstractPattern {
|
||||
return -1;
|
||||
}
|
||||
int slope = Math.abs(
|
||||
extent.getNearestSurfaceTerrainBlock(x + distance, z, y, 0, maxY) - extent
|
||||
.getNearestSurfaceTerrainBlock(x - distance, z, y, 0, maxY)) * 7;
|
||||
extent.getNearestSurfaceTerrainBlock(x + distance, z, y, minY, maxY) - extent
|
||||
.getNearestSurfaceTerrainBlock(x - distance, z, y, minY, maxY)) * 7;
|
||||
slope += Math.abs(extent.getNearestSurfaceTerrainBlock(
|
||||
x,
|
||||
z + distance,
|
||||
y,
|
||||
0,
|
||||
minY,
|
||||
maxY
|
||||
) - extent.getNearestSurfaceTerrainBlock(x, z - distance, y, 0, maxY)) * 7;
|
||||
) - extent.getNearestSurfaceTerrainBlock(x, z - distance, y, minY, maxY)) * 7;
|
||||
slope += Math.abs(extent.getNearestSurfaceTerrainBlock(
|
||||
x + distance,
|
||||
z + distance,
|
||||
y,
|
||||
0,
|
||||
minY,
|
||||
maxY
|
||||
) - extent.getNearestSurfaceTerrainBlock(x - distance, z - distance, y, 0, maxY)) * 5;
|
||||
) - extent.getNearestSurfaceTerrainBlock(x - distance, z - distance, y, minY, maxY)) * 5;
|
||||
slope += Math.abs(extent.getNearestSurfaceTerrainBlock(
|
||||
x - distance,
|
||||
z + distance,
|
||||
y,
|
||||
0,
|
||||
minY,
|
||||
maxY
|
||||
) - extent.getNearestSurfaceTerrainBlock(x + distance, z - distance, y, 0, maxY)) * 5;
|
||||
) - extent.getNearestSurfaceTerrainBlock(x + distance, z - distance, y, minY, maxY)) * 5;
|
||||
return slope;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import com.sk89q.worldedit.function.pattern.AbstractPattern;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
public class OffsetPattern extends AbstractPattern {
|
||||
|
||||
@ -42,6 +43,9 @@ public class OffsetPattern extends AbstractPattern {
|
||||
mutable.mutX(position.getX() + dx);
|
||||
mutable.mutY(position.getY() + dy);
|
||||
mutable.mutZ(position.getZ() + dz);
|
||||
if (mutable.getY() < minY || mutable.getY() > maxY) {
|
||||
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
||||
}
|
||||
return pattern.applyBlock(mutable);
|
||||
}
|
||||
|
||||
@ -49,10 +53,10 @@ public class OffsetPattern extends AbstractPattern {
|
||||
public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException {
|
||||
mutable.mutX(get.getX() + dx);
|
||||
mutable.mutY(get.getY() + dy);
|
||||
if (mutable.getY() < minY || mutable.getY() > maxY) {
|
||||
mutable.mutZ(get.getZ() + dz);
|
||||
if (mutable.getY() < extent.getMinY() || mutable.getY() > extent.getMaxY()) {
|
||||
return false;
|
||||
}
|
||||
mutable.mutZ(get.getZ() + dz);
|
||||
return pattern.apply(extent, get, mutable);
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import com.sk89q.worldedit.function.pattern.AbstractPattern;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import java.util.SplittableRandom;
|
||||
|
||||
@ -32,8 +33,8 @@ public class RandomOffsetPattern extends AbstractPattern {
|
||||
* @param dx offset x
|
||||
* @param dy offset y
|
||||
* @param dz offset z
|
||||
* @param minY min applicable y (inclusive
|
||||
* @param maxY max applicable y (inclusive
|
||||
* @param minY min applicable y (inclusive)
|
||||
* @param maxY max applicable y (inclusive)
|
||||
*/
|
||||
public RandomOffsetPattern(Pattern pattern, int dx, int dy, int dz, int minY, int maxY) {
|
||||
this.pattern = pattern;
|
||||
@ -54,6 +55,9 @@ public class RandomOffsetPattern extends AbstractPattern {
|
||||
mutable.mutX((position.getX() + r.nextInt(dx2) - dx));
|
||||
mutable.mutY((position.getY() + r.nextInt(dy2) - dy));
|
||||
mutable.mutZ((position.getZ() + r.nextInt(dz2) - dz));
|
||||
if (mutable.getY() < minY || mutable.getY() > maxY) {
|
||||
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
||||
}
|
||||
return pattern.applyBlock(mutable);
|
||||
}
|
||||
|
||||
@ -62,7 +66,7 @@ public class RandomOffsetPattern extends AbstractPattern {
|
||||
mutable.mutX((set.getX() + r.nextInt(dx2) - dx));
|
||||
mutable.mutY((set.getY() + r.nextInt(dy2) - dy));
|
||||
mutable.mutZ((set.getZ() + r.nextInt(dz2) - dz));
|
||||
if (mutable.getY() < minY || mutable.getY() > maxY) {
|
||||
if (mutable.getY() < extent.getMinY() || mutable.getY() > extent.getMaxY()) {
|
||||
return false;
|
||||
}
|
||||
return pattern.apply(extent, get, mutable);
|
||||
|
@ -7,6 +7,7 @@ import com.sk89q.worldedit.function.pattern.AbstractPattern;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
public class RelativePattern extends AbstractPattern implements ResettablePattern {
|
||||
|
||||
@ -37,6 +38,9 @@ public class RelativePattern extends AbstractPattern implements ResettablePatter
|
||||
mutable.mutX(pos.getX() - origin.getX());
|
||||
mutable.mutY(pos.getY() - origin.getY());
|
||||
mutable.mutZ(pos.getZ() - origin.getZ());
|
||||
if (mutable.getY() < minY || mutable.getY() > maxY) {
|
||||
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
||||
}
|
||||
return pattern.applyBlock(mutable);
|
||||
}
|
||||
|
||||
@ -47,10 +51,10 @@ public class RelativePattern extends AbstractPattern implements ResettablePatter
|
||||
}
|
||||
mutable.mutX(set.getX() - origin.getX());
|
||||
mutable.mutY(set.getY() - origin.getY());
|
||||
if (mutable.getY() < minY || mutable.getY() > maxY) {
|
||||
mutable.mutZ(set.getZ() - origin.getZ());
|
||||
if (mutable.getY() < extent.getMinY() || mutable.getY() > extent.getMaxY()) {
|
||||
return false;
|
||||
}
|
||||
mutable.mutZ(set.getZ() - origin.getZ());
|
||||
return pattern.apply(extent, get, mutable);
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,12 @@ public class SolidRandomOffsetPattern extends AbstractPattern {
|
||||
mutable.mutX(position.getX() + r.nextInt(dx2) - dx);
|
||||
mutable.mutY(position.getY() + r.nextInt(dy2) - dy);
|
||||
mutable.mutZ(position.getZ() + r.nextInt(dz2) - dz);
|
||||
if (mutable.getY() < minY || mutable.getY() > maxY) {
|
||||
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
||||
}
|
||||
if (mutable.getY() < minY || mutable.getY() > maxY) {
|
||||
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
||||
}
|
||||
BaseBlock block = pattern.applyBlock(mutable);
|
||||
if (block.getMaterial().isSolid()) {
|
||||
return block;
|
||||
@ -77,10 +83,10 @@ public class SolidRandomOffsetPattern extends AbstractPattern {
|
||||
public boolean apply(Extent extent, BlockVector3 get, BlockVector3 set) throws WorldEditException {
|
||||
mutable.mutX(set.getX() + r.nextInt(dx2) - dx);
|
||||
mutable.mutY(set.getY() + r.nextInt(dy2) - dy);
|
||||
if (mutable.getY() < minY || mutable.getY() > maxY) {
|
||||
mutable.mutZ(set.getZ() + r.nextInt(dz2) - dz);
|
||||
if (mutable.getY() < extent.getMinY() || mutable.getY() > extent.getMaxY()) {
|
||||
return false;
|
||||
}
|
||||
mutable.mutZ(set.getZ() + r.nextInt(dz2) - dz);
|
||||
BaseBlock block = pattern.applyBlock(mutable);
|
||||
if (block.getMaterial().isSolid()) {
|
||||
return pattern.apply(extent, get, mutable);
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.fastasyncworldedit.core.function.pattern;
|
||||
|
||||
import com.fastasyncworldedit.core.math.MutableBlockVector3;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.pattern.AbstractPattern;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.function.visitor.BreadthFirstSearch;
|
||||
@ -41,6 +43,11 @@ public class SurfaceRandomOffsetPattern extends AbstractPattern {
|
||||
allowed = new MutableBlockVector3[buffer.length];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(final Extent extent, final BlockVector3 get, final BlockVector3 set) throws WorldEditException {
|
||||
return super.apply(extent, get, set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock applyBlock(BlockVector3 position) {
|
||||
return pattern.applyBlock(travel(position));
|
||||
|
@ -22,13 +22,12 @@ public class AboveVisitor extends RecursiveVisitor {
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
* @param baseY the base Y
|
||||
* @param depth maximum number of iterations
|
||||
* @param minY min visitable y value. Inclusive.
|
||||
* @param maxY max visitable y value. Inclusive.
|
||||
*/
|
||||
public AboveVisitor(Mask mask, RegionFunction function, int baseY) {
|
||||
this(mask, function, baseY, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public AboveVisitor(Mask mask, RegionFunction function, int baseY, int depth) {
|
||||
super(mask, function, depth);
|
||||
public AboveVisitor(Mask mask, RegionFunction function, int baseY, int depth, int minY, int maxY) {
|
||||
super(mask, function, depth, minY, maxY);
|
||||
checkNotNull(mask);
|
||||
|
||||
this.baseY = baseY;
|
||||
|
@ -19,12 +19,22 @@ public class DirectionalVisitor extends RecursiveVisitor {
|
||||
private final BlockVector3 origin;
|
||||
private final BlockVector3 dirVec;
|
||||
|
||||
public DirectionalVisitor(Mask mask, RegionFunction function, BlockVector3 origin, BlockVector3 direction) {
|
||||
this(mask, function, origin, direction, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public DirectionalVisitor(Mask mask, RegionFunction function, BlockVector3 origin, BlockVector3 direction, int distance) {
|
||||
super(mask, function, distance);
|
||||
/**
|
||||
* New visitor. Only visits in the given direction
|
||||
*
|
||||
* @param mask block mask
|
||||
* @param function function to apply
|
||||
* @param origin start position
|
||||
* @param direction allowable direction to visit between
|
||||
* @param distance max number of iterations
|
||||
* @param minY min visitable y value. Inclusive.
|
||||
* @param maxY max visitable y value. Inclusive.
|
||||
*/
|
||||
public DirectionalVisitor(
|
||||
Mask mask, RegionFunction function, BlockVector3 origin, BlockVector3 direction, int distance,
|
||||
int minY, int maxY
|
||||
) {
|
||||
super(mask, function, distance, minY, maxY);
|
||||
checkNotNull(mask);
|
||||
this.origin = origin;
|
||||
this.dirVec = direction;
|
||||
|
@ -102,6 +102,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
nbttFile = new File(folder, index + ".nbtt");
|
||||
entfFile = new File(folder, index + ".entf");
|
||||
enttFile = new File(folder, index + ".entt");
|
||||
//Switch file ending due to new (sort-of) format. (Added e for Extended height)
|
||||
bdFile = new File(folder, index + ".bd");
|
||||
bioFile = new File(folder, index + ".bio");
|
||||
}
|
||||
@ -431,6 +432,8 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
final FaweInputStream gis = MainUtil.getCompressedIS(fis);
|
||||
// skip mode
|
||||
gis.skipFully(1);
|
||||
// skip version
|
||||
gis.skipFully(1);
|
||||
// origin
|
||||
ox = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + gis.read());
|
||||
oz = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + gis.read());
|
||||
|
@ -157,7 +157,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
|
||||
addEntityCreate(tag);
|
||||
}
|
||||
}
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
for (int layer = get.getMinSectionIndex(); layer <= get.getMaxSectionIndex(); layer++) {
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
@ -172,6 +172,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
|
||||
char[] blocksSet;
|
||||
System.arraycopy(set.load(layer), 0, (blocksSet = new char[4096]), 0, 4096);
|
||||
|
||||
// Account for negative layers
|
||||
int by = layer << 4;
|
||||
for (int y = 0, index = 0; y < 16; y++) {
|
||||
int yy = y + by;
|
||||
@ -195,14 +196,21 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
|
||||
|
||||
BiomeType[] biomes = set.getBiomes();
|
||||
if (biomes != null) {
|
||||
for (int y = 0, index = 0; y < 64; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, index++) {
|
||||
BiomeType newBiome = biomes[index];
|
||||
if (newBiome != null) {
|
||||
BiomeType oldBiome = get.getBiomeType(x, y, z);
|
||||
if (oldBiome != newBiome) {
|
||||
addBiomeChange(bx + (x << 2), y << 2, bz + (z << 2), oldBiome, newBiome);
|
||||
int index = 0;
|
||||
for (int layer = get.getMinSectionIndex(); layer <= get.getMaxSectionIndex(); layer++) {
|
||||
if (!set.hasBiomes(layer)) {
|
||||
continue;
|
||||
}
|
||||
int yy = layer << 4;
|
||||
for (int y = 0; y < 4; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, index++) {
|
||||
BiomeType newBiome = biomes[index];
|
||||
if (newBiome != null) {
|
||||
BiomeType oldBiome = get.getBiomeType(x, y, z);
|
||||
if (oldBiome != newBiome) {
|
||||
addBiomeChange(bx + (x << 2), yy + (y << 2), bz + (z << 2), oldBiome, newBiome);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -341,11 +349,17 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
|
||||
return addWriteTask(writeTask, Fawe.isMainThread());
|
||||
}
|
||||
|
||||
public Future<?> addWriteTask(Runnable writeTask, boolean completeNow) {
|
||||
public Future<?> addWriteTask(final Runnable writeTask, final boolean completeNow) {
|
||||
AbstractChangeSet.this.waitingCombined.incrementAndGet();
|
||||
Runnable wrappedTask = () -> {
|
||||
try {
|
||||
writeTask.run();
|
||||
} catch (Throwable t) {
|
||||
if (completeNow) {
|
||||
throw t;
|
||||
} else {
|
||||
t.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
if (AbstractChangeSet.this.waitingCombined.decrementAndGet() <= 0) {
|
||||
synchronized (AbstractChangeSet.this.waitingAsync) {
|
||||
|
@ -28,11 +28,16 @@ import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* FAWE stream ChangeSet offering support for extended-height worlds
|
||||
*/
|
||||
public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
|
||||
public static final int HEADER_SIZE = 9;
|
||||
private static final int version = 1;
|
||||
private int mode;
|
||||
private final int compression;
|
||||
private final int minY;
|
||||
|
||||
protected FaweStreamIdDelegate idDel;
|
||||
protected FaweStreamPositionDelegate posDel;
|
||||
@ -44,6 +49,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
public FaweStreamChangeSet(World world, int compression, boolean storeRedo, boolean smallLoc) {
|
||||
super(world);
|
||||
this.compression = compression;
|
||||
this.minY = world.getMinY();
|
||||
init(storeRedo, smallLoc);
|
||||
}
|
||||
|
||||
@ -139,6 +145,10 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
|
||||
@Override
|
||||
public void write(OutputStream out, int x, int y, int z) throws IOException {
|
||||
if (y < 0 || y > 255) {
|
||||
throw new UnsupportedOperationException("y cannot be outside range 0-255 for " +
|
||||
"small-edits=true");
|
||||
}
|
||||
int rx = -lx + (lx = x);
|
||||
int ry = -ly + (ly = y);
|
||||
int rz = -lz + (lz = z);
|
||||
@ -174,7 +184,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
};
|
||||
} else {
|
||||
posDel = new FaweStreamPositionDelegate() {
|
||||
final byte[] buffer = new byte[5];
|
||||
final byte[] buffer = new byte[6];
|
||||
int lx;
|
||||
int ly;
|
||||
int lz;
|
||||
@ -188,7 +198,8 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
stream.write(((rx) >> 8) & 0xff);
|
||||
stream.write((rz) & 0xff);
|
||||
stream.write(((rz) >> 8) & 0xff);
|
||||
stream.write((byte) ry);
|
||||
stream.write((ry) & 0xff);
|
||||
stream.write(((ry) >> 8) & 0xff);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -199,7 +210,7 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
|
||||
@Override
|
||||
public int readY(FaweInputStream is) throws IOException {
|
||||
return (ly = (ly + (buffer[4]))) & 0xFF;
|
||||
return ly = (ly + (buffer[4] & 0xFF) + (buffer[5] << 8));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -212,6 +223,8 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
|
||||
public void writeHeader(OutputStream os, int x, int y, int z) throws IOException {
|
||||
os.write(mode);
|
||||
// Allows for version detection of history in case of changes to format.
|
||||
os.write(version);
|
||||
setOrigin(x, z);
|
||||
os.write((byte) (x >> 24));
|
||||
os.write((byte) (x >> 16));
|
||||
@ -227,6 +240,10 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
public void readHeader(InputStream is) throws IOException {
|
||||
// skip mode
|
||||
int mode = is.read();
|
||||
int version = is.read();
|
||||
if (version != FaweStreamChangeSet.version) {
|
||||
throw new UnsupportedOperationException(String.format("Version %s history not supported!", version));
|
||||
}
|
||||
// origin
|
||||
int x = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + is.read());
|
||||
int z = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + is.read());
|
||||
@ -290,10 +307,6 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
public abstract NBTInputStream getTileRemoveIS() throws IOException;
|
||||
|
||||
protected int blockSize;
|
||||
public int entityCreateSize;
|
||||
public int entityRemoveSize;
|
||||
public int tileCreateSize;
|
||||
public int tileRemoveSize;
|
||||
|
||||
private int originX;
|
||||
private int originZ;
|
||||
@ -325,9 +338,12 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBiomeChange(int x, int y, int z, BiomeType from, BiomeType to) {
|
||||
public void addBiomeChange(int bx, int by, int bz, BiomeType from, BiomeType to) {
|
||||
blockSize++;
|
||||
try {
|
||||
int x = bx >> 2;
|
||||
int y = by >> 2;
|
||||
int z = bz >> 2;
|
||||
FaweOutputStream os = getBiomeOS();
|
||||
os.write((byte) (x >> 24));
|
||||
os.write((byte) (x >> 16));
|
||||
@ -337,7 +353,9 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
os.write((byte) (z >> 16));
|
||||
os.write((byte) (z >> 8));
|
||||
os.write((byte) (z));
|
||||
os.write((byte) (y));
|
||||
// only need to store biomes in the 4x4x4 chunks so only need one byte for y still (signed byte -128 -> 127)
|
||||
// means -512 -> 508. Add 128 to avoid negative value casting.
|
||||
os.write((byte) (y + 128));
|
||||
os.writeVarInt(from.getInternalId());
|
||||
os.writeVarInt(to.getInternalId());
|
||||
} catch (Throwable e) {
|
||||
@ -465,9 +483,9 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet {
|
||||
try {
|
||||
int int1 = is.read();
|
||||
if (int1 != -1) {
|
||||
int x = ((int1 << 24) + (is.read() << 16) + (is.read() << 8) + is.read());
|
||||
int z = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + is.read());
|
||||
int y = is.read();
|
||||
int x = ((int1 << 24) + (is.read() << 16) + (is.read() << 8) + is.read()) << 2;
|
||||
int z = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + is.read()) << 2;
|
||||
int y = (is.read() - 128) << 2;
|
||||
int from = is.readVarInt();
|
||||
int to = is.readVarInt();
|
||||
change.setBiome(x, y, z, from, to);
|
||||
|
@ -3,26 +3,26 @@ package com.fastasyncworldedit.core.math;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.fastasyncworldedit.core.util.collection.IAdaptedMap;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import it.unimi.dsi.fastutil.shorts.Short2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class BlockVector3ChunkMap<T> implements IAdaptedMap<BlockVector3, T, Short, T> {
|
||||
public class BlockVector3ChunkMap<T> implements IAdaptedMap<BlockVector3, T, Integer, T> {
|
||||
|
||||
private final Short2ObjectArrayMap<T> map = new Short2ObjectArrayMap<>();
|
||||
private final Int2ObjectArrayMap<T> map = new Int2ObjectArrayMap<>();
|
||||
|
||||
@Override
|
||||
public Map<Short, T> getParent() {
|
||||
public Map<Integer, T> getParent() {
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Short adaptKey(BlockVector3 key) {
|
||||
public Integer adaptKey(BlockVector3 key) {
|
||||
return MathMan.tripleBlockCoord(key.getX(), key.getY(), key.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector3 adaptKey2(Short key) {
|
||||
public BlockVector3 adaptKey2(Integer key) {
|
||||
int x = MathMan.untripleBlockCoordX(key);
|
||||
int y = MathMan.untripleBlockCoordY(key);
|
||||
int z = MathMan.untripleBlockCoordZ(key);
|
||||
@ -40,23 +40,23 @@ public class BlockVector3ChunkMap<T> implements IAdaptedMap<BlockVector3, T, Sho
|
||||
}
|
||||
|
||||
public T put(int x, int y, int z, T value) {
|
||||
short key = MathMan.tripleBlockCoord(x, y, z);
|
||||
int key = MathMan.tripleBlockCoord(x, y, z);
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
|
||||
public T get(int x, int y, int z) {
|
||||
short key = MathMan.tripleBlockCoord(x, y, z);
|
||||
int key = MathMan.tripleBlockCoord(x, y, z);
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
public T remove(int x, int y, int z) {
|
||||
short key = MathMan.tripleBlockCoord(x, y, z);
|
||||
int key = MathMan.tripleBlockCoord(x, y, z);
|
||||
return map.remove(key);
|
||||
}
|
||||
|
||||
public boolean contains(int x, int y, int z) {
|
||||
short key = MathMan.tripleBlockCoord(x, y, z);
|
||||
int key = MathMan.tripleBlockCoord(x, y, z);
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
|
@ -44,14 +44,14 @@ public class BlockVectorSet extends AbstractCollection<BlockVector3> implements
|
||||
int newSize = count + size;
|
||||
if (newSize > index) {
|
||||
int localIndex = index - count;
|
||||
BlockVector3 pos = set.getIndex(localIndex);
|
||||
MutableBlockVector3 pos = set.getIndex(localIndex);
|
||||
if (pos != null) {
|
||||
int pair = entry.getIntKey();
|
||||
int cx = MathMan.unpairX(pair);
|
||||
int cz = MathMan.unpairY(pair);
|
||||
pos = pos.mutX((cx << 11) + pos.getBlockX());
|
||||
pos = pos.mutZ((cz << 11) + pos.getBlockZ());
|
||||
return pos;
|
||||
pos.mutX((cx << 11) + pos.getBlockX());
|
||||
pos.mutZ((cz << 11) + pos.getBlockZ());
|
||||
return pos.toImmutable();
|
||||
}
|
||||
}
|
||||
count += newSize;
|
||||
@ -91,7 +91,7 @@ public class BlockVectorSet extends AbstractCollection<BlockVector3> implements
|
||||
if (!entries.hasNext()) {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
return new Iterator<BlockVector3>() {
|
||||
return new Iterator<>() {
|
||||
Int2ObjectMap.Entry<LocalBlockVectorSet> entry = entries.next();
|
||||
Iterator<BlockVector3> entryIter = entry.getValue().iterator();
|
||||
final MutableBlockVector3 mutable = new MutableBlockVector3();
|
||||
|
@ -11,14 +11,14 @@ import java.util.Set;
|
||||
|
||||
/**
|
||||
* The LocalBlockVectorSet is a Memory and CPU optimized Set for storing BlockVectors which are all in a local region
|
||||
* - All vectors must be in a 2048 * 2048 area centered around the first entry
|
||||
* - All vectors must be in a 2048 * 512 * 2048 area centered around the first entry
|
||||
* - This will use 8 bytes for every 64 BlockVectors (about 800x less than a HashSet)
|
||||
*/
|
||||
public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
|
||||
private final SparseBitSet set;
|
||||
private int offsetX;
|
||||
private int offsetZ;
|
||||
private final SparseBitSet set;
|
||||
|
||||
public LocalBlockVectorSet() {
|
||||
offsetX = offsetZ = Integer.MAX_VALUE;
|
||||
@ -42,7 +42,8 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
}
|
||||
|
||||
public boolean contains(int x, int y, int z) {
|
||||
return set.get(MathMan.tripleSearchCoords(x - offsetX, y, z - offsetZ));
|
||||
// take 128 to fit -256<y<255
|
||||
return set.get(MathMan.tripleSearchCoords(x - offsetX, y - 128, z - offsetZ));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -67,12 +68,15 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
if (size() < length * length * length) {
|
||||
int index = -1;
|
||||
while ((index = set.nextSetBit(index + 1)) != -1) {
|
||||
int b1 = (byte) (index >> 0) & 0xFF;
|
||||
int b2 = (byte) (index >> 8) & 0x7F;
|
||||
int b3 = (byte) (index >> 15) & 0xFF;
|
||||
int b4 = (byte) (index >> 23) & 0xFF;
|
||||
if (Math.abs((offsetX + (((b3 + ((MathMan.unpair8x(b2)) << 8)) << 21) >> 21)) - x) <= radius && Math.abs((offsetZ + (((b4 + ((MathMan
|
||||
.unpair8y(b2)) << 8)) << 21) >> 21)) - z) <= radius && Math.abs((b1) - y) <= radius) {
|
||||
int b1 = (index & 0xFF);
|
||||
int b2 = (index >> 8) & 0xff;
|
||||
int b3 = (index >> 15) & 0xFF;
|
||||
int b4 = (index >> 23) & 0xFF;
|
||||
int ix = (offsetX + (b3 + (((b2 & 0x7)) << 8)) << 21) >> 21;
|
||||
// Add 128 as we shift y by 128 to fit -256<y<255
|
||||
int iy = 128 + b1 * (((b2 >> 6) & 0x1) == 0 ? 1 : -1);
|
||||
int iz = (offsetZ + (b4 + (((b2 >> 3) & 0x7) << 8)) << 21) >> 21;
|
||||
if (Math.abs(ix - x) <= radius && Math.abs(iz - z) <= radius && Math.abs(iy - y) <= radius) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -100,7 +104,7 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
this.offsetZ = z;
|
||||
}
|
||||
|
||||
protected BlockVector3 getIndex(int getIndex) {
|
||||
protected MutableBlockVector3 getIndex(int getIndex) {
|
||||
int size = size();
|
||||
if (getIndex > size) {
|
||||
return null;
|
||||
@ -110,13 +114,15 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
index = set.nextSetBit(index + 1);
|
||||
}
|
||||
if (index != -1) {
|
||||
int b1 = (byte) (index >> 0) & 0xFF;
|
||||
int b2 = (byte) (index >> 8) & 0x7F;
|
||||
int b3 = (byte) (index >> 15) & 0xFF;
|
||||
int b4 = (byte) (index >> 23) & 0xFF;
|
||||
int x = offsetX + (((b3 + (MathMan.unpair8x(b2) << 8)) << 21) >> 21);
|
||||
int z = offsetZ + (((b4 + (MathMan.unpair8y(b2) << 8)) << 21) >> 21);
|
||||
return MutableBlockVector3.get(x, b1, z);
|
||||
int b1 = (index & 0xFF);
|
||||
int b2 = (index >> 8) & 0xff;
|
||||
int b3 = (index >> 15) & 0xFF;
|
||||
int b4 = (index >> 23) & 0xFF;
|
||||
int x = (offsetX + (b3 + (((b2 & 0x7)) << 8)) << 21) >> 21;
|
||||
// Add 128 as we shift y by 128 to fit -256<y<255
|
||||
int y = 128 + b1 * (((b2 >> 6) & 0x1) == 0 ? 1 : -1);
|
||||
int z = (offsetZ + (b4 + (((b2 >> 3) & 0x7) << 8)) << 21) >> 21;
|
||||
return MutableBlockVector3.get(x, y, z);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -125,9 +131,9 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
@Override
|
||||
public Iterator<BlockVector3> iterator() {
|
||||
return new Iterator<BlockVector3>() {
|
||||
final MutableBlockVector3 mutable = new MutableBlockVector3(0, 0, 0);
|
||||
int index = set.nextSetBit(0);
|
||||
int previous = -1;
|
||||
final MutableBlockVector3 mutable = new MutableBlockVector3(0, 0, 0);
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
@ -143,12 +149,16 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
public BlockVector3 next() {
|
||||
if (index != -1) {
|
||||
int b1 = (index & 0xFF);
|
||||
int b2 = ((byte) (index >> 8)) & 0x7F;
|
||||
int b3 = ((byte) (index >> 15)) & 0xFF;
|
||||
int b4 = ((byte) (index >> 23)) & 0xFF;
|
||||
mutable.mutX(offsetX + (((b3 + (MathMan.unpair8x(b2) << 8)) << 21) >> 21));
|
||||
mutable.mutY(b1);
|
||||
mutable.mutZ(offsetZ + (((b4 + (MathMan.unpair8y(b2) << 8)) << 21) >> 21));
|
||||
int b2 = (index >> 8) & 0xff;
|
||||
int b3 = (index >> 15) & 0xFF;
|
||||
int b4 = (index >> 23) & 0xFF;
|
||||
int x = (offsetX + (b3 + (((b2 & 0x7)) << 8)) << 21) >> 21;
|
||||
// Add 128 as we shift y by 128 to fit -256<y<255
|
||||
int y = 128 + b1 * (((b2 >> 6) & 0x1) == 0 ? 1 : -1);
|
||||
int z = (offsetZ + (b4 + (((b2 >> 3) & 0x7) << 8)) << 21) >> 21;
|
||||
mutable.mutX(x);
|
||||
mutable.mutY(y);
|
||||
mutable.mutZ(z);
|
||||
previous = index;
|
||||
index = set.nextSetBit(index + 1);
|
||||
return mutable;
|
||||
@ -175,12 +185,14 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
for (int i = 0; i < size; i++) {
|
||||
index = set.nextSetBit(index);
|
||||
int b1 = (index & 0xFF);
|
||||
int b2 = ((byte) (index >> 8)) & 0x7F;
|
||||
int b3 = ((byte) (index >> 15)) & 0xFF;
|
||||
int b4 = ((byte) (index >> 23)) & 0xFF;
|
||||
int x = offsetX + (((b3 + ((MathMan.unpair8x(b2)) << 8)) << 21) >> 21);
|
||||
int z = offsetZ + (((b4 + ((MathMan.unpair8y(b2)) << 8)) << 21) >> 21);
|
||||
array[i] = (T) BlockVector3.at(x, b1, z);
|
||||
int b2 = (index >> 8) & 0xff;
|
||||
int b3 = (index >> 15) & 0xFF;
|
||||
int b4 = (index >> 23) & 0xFF;
|
||||
int x = (offsetX + (b3 + (((b2 & 0x7)) << 8)) << 21) >> 21;
|
||||
// Add 128 as we shift y by 128 to fit -256<y<255
|
||||
int y = 128 + b1 * (((b2 >> 6) & 0x1) == 0 ? 1 : -1);
|
||||
int z = (offsetZ + (b4 + (((b2 >> 3) & 0x7) << 8)) << 21) >> 21;
|
||||
array[i] = (T) BlockVector3.at(x, y, z);
|
||||
index++;
|
||||
}
|
||||
return array;
|
||||
@ -195,7 +207,7 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
if (relX > 1023 || relX < -1024 || relZ > 1023 || relZ < -1024) {
|
||||
return false;
|
||||
}
|
||||
return y >= 0 && y <= 256;
|
||||
return y >= -128 && y <= 383;
|
||||
}
|
||||
|
||||
public boolean add(int x, int y, int z) {
|
||||
@ -209,8 +221,8 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
throw new UnsupportedOperationException(
|
||||
"LocalVectorSet can only contain vectors within 1024 blocks (cuboid) of the first entry. ");
|
||||
}
|
||||
if (y < 0 || y > 255) {
|
||||
throw new UnsupportedOperationException("LocalVectorSet can only contain vectors from y elem:[0,255]");
|
||||
if (y < -128 || y > 383) {
|
||||
throw new UnsupportedOperationException("LocalVectorSet can only contain vectors from y elem:[-128,383]");
|
||||
}
|
||||
int index = getIndex(x, y, z);
|
||||
if (set.get(index)) {
|
||||
@ -227,11 +239,17 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
}
|
||||
|
||||
private int getIndex(BlockVector3 vector) {
|
||||
return MathMan.tripleSearchCoords(vector.getBlockX() - offsetX, vector.getBlockY(), vector.getBlockZ() - offsetZ);
|
||||
// take 128 to fit -256<y<255
|
||||
return MathMan.tripleSearchCoords(
|
||||
vector.getBlockX() - offsetX,
|
||||
vector.getBlockY() - 128,
|
||||
vector.getBlockZ() - offsetZ
|
||||
);
|
||||
}
|
||||
|
||||
private int getIndex(int x, int y, int z) {
|
||||
return MathMan.tripleSearchCoords(x - offsetX, y, z - offsetZ);
|
||||
// take 128 to fit -256<y<255
|
||||
return MathMan.tripleSearchCoords(x - offsetX, y - 128, z - offsetZ);
|
||||
}
|
||||
|
||||
public boolean remove(int x, int y, int z) {
|
||||
@ -240,7 +258,8 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
if (relX > 1023 || relX < -1024 || relZ > 1023 || relZ < -1024) {
|
||||
return false;
|
||||
}
|
||||
int index = MathMan.tripleSearchCoords(relX, y, relZ);
|
||||
// take 128 to fit -256<y<255
|
||||
int index = MathMan.tripleSearchCoords(relX, y - 128, relZ);
|
||||
boolean value = set.get(index);
|
||||
set.clear(index);
|
||||
return value;
|
||||
@ -283,12 +302,16 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
for (int i = 0; i < size; i++) {
|
||||
index = set.nextSetBit(index + 1);
|
||||
int b1 = (index & 0xFF);
|
||||
int b2 = ((byte) (index >> 8)) & 0x7F;
|
||||
int b3 = ((byte) (index >> 15)) & 0xFF;
|
||||
int b4 = ((byte) (index >> 23)) & 0xFF;
|
||||
mVec.mutX(offsetX + (((b3 + ((MathMan.unpair8x(b2)) << 8)) << 21) >> 21));
|
||||
mVec.mutY(b1);
|
||||
mVec.mutZ(offsetZ + (((b4 + ((MathMan.unpair8y(b2)) << 8)) << 21) >> 21));
|
||||
int b2 = (index >> 8) & 0xff;
|
||||
int b3 = (index >> 15) & 0xFF;
|
||||
int b4 = (index >> 23) & 0xFF;
|
||||
int x = (offsetX + (b3 + (((b2 & 0x7)) << 8)) << 21) >> 21;
|
||||
// Add 128 as we shift y by 128 to fit -256<y<255
|
||||
int y = 128 + b1 * (((b2 >> 6) & 0x1) == 0 ? 1 : -1);
|
||||
int z = (offsetZ + (b4 + (((b2 >> 3) & 0x7) << 8)) << 21) >> 21;
|
||||
mVec.mutX(x);
|
||||
mVec.mutY(y);
|
||||
mVec.mutZ(z);
|
||||
if (!c.contains(mVec)) {
|
||||
result = true;
|
||||
set.clear(index);
|
||||
@ -312,21 +335,17 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
for (int i = 0; i < size; i++) {
|
||||
index = set.nextSetBit(index + 1);
|
||||
int b1 = (index & 0xFF);
|
||||
int b2 = ((byte) (index >> 8)) & 0x7F;
|
||||
int b3 = ((byte) (index >> 15)) & 0xFF;
|
||||
int b4 = ((byte) (index >> 23)) & 0xFF;
|
||||
int x = offsetX + (((b3 + ((MathMan.unpair8x(b2)) << 8)) << 21) >> 21);
|
||||
int z = offsetZ + (((b4 + ((MathMan.unpair8y(b2)) << 8)) << 21) >> 21);
|
||||
visitor.run(x, b1, z, index);
|
||||
int b2 = (index >> 8) & 0xff;
|
||||
int b3 = (index >> 15) & 0xFF;
|
||||
int b4 = (index >> 23) & 0xFF;
|
||||
int x = (offsetX + (b3 + (((b2 & 0x7)) << 8)) << 21) >> 21;
|
||||
// Add 128 as we shift y by 128 to fit -256<y<255
|
||||
int y = 128 + b1 * (((b2 >> 6) & 0x1) == 0 ? 1 : -1);
|
||||
int z = (offsetZ + (b4 + (((b2 >> 3) & 0x7) << 8)) << 21) >> 21;
|
||||
visitor.run(x, y, z, index);
|
||||
}
|
||||
}
|
||||
|
||||
public interface BlockVectorSetVisitor {
|
||||
|
||||
void run(int x, int y, int z, int index);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
offsetZ = Integer.MAX_VALUE;
|
||||
@ -334,4 +353,10 @@ public class LocalBlockVectorSet implements Set<BlockVector3> {
|
||||
set.clear();
|
||||
}
|
||||
|
||||
public interface BlockVectorSetVisitor {
|
||||
|
||||
void run(int x, int y, int z, int index);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.fastasyncworldedit.core.queue;
|
||||
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.extent.processor.EmptyBatchProcessor;
|
||||
import com.fastasyncworldedit.core.extent.processor.MultiBatchProcessor;
|
||||
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
|
||||
@ -42,7 +41,7 @@ public interface IBatchProcessor {
|
||||
*/
|
||||
default boolean trimY(IChunkSet set, int minY, int maxY) {
|
||||
int minLayer = (minY - 1) >> 4;
|
||||
for (int layer = 0; layer <= minLayer; layer++) {
|
||||
for (int layer = set.getMinSectionIndex(); layer <= minLayer; layer++) {
|
||||
if (set.hasSection(layer)) {
|
||||
if (layer == minLayer) {
|
||||
char[] arr = set.load(layer);
|
||||
@ -57,7 +56,7 @@ public interface IBatchProcessor {
|
||||
}
|
||||
}
|
||||
int maxLayer = (maxY + 1) >> 4;
|
||||
for (int layer = maxLayer; layer < FaweCache.IMP.CHUNK_LAYERS; layer++) {
|
||||
for (int layer = maxLayer; layer < set.getMaxSectionIndex(); layer++) {
|
||||
if (set.hasSection(layer)) {
|
||||
if (layer == minLayer) {
|
||||
char[] arr = set.load(layer);
|
||||
@ -74,10 +73,8 @@ public interface IBatchProcessor {
|
||||
try {
|
||||
int layer = (minY - 15) >> 4;
|
||||
while (layer < (maxY + 15) >> 4) {
|
||||
if (layer > -1) {
|
||||
if (set.hasSection(layer)) {
|
||||
return true;
|
||||
}
|
||||
if (set.hasSection(layer)) {
|
||||
return true;
|
||||
}
|
||||
layer++;
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.registry.BlockRegistry;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
@ -23,7 +22,14 @@ import java.util.stream.IntStream;
|
||||
*/
|
||||
public interface IBlocks extends Trimable {
|
||||
|
||||
boolean hasSection(@Range(from = 0, to = 15) int layer);
|
||||
/**
|
||||
* Returns if the chunk has a BLOCKS section at the given layer. May not be indicative of presence
|
||||
* of entities, tile entites, biomes, etc.
|
||||
*
|
||||
* @param layer chunk section layer
|
||||
* @return if blocks/a block section is present
|
||||
*/
|
||||
boolean hasSection(int layer);
|
||||
|
||||
char[] load(int layer);
|
||||
|
||||
@ -38,7 +44,7 @@ public interface IBlocks extends Trimable {
|
||||
BiomeType getBiomeType(int x, int y, int z);
|
||||
|
||||
default int getBitMask() {
|
||||
return IntStream.range(0, FaweCache.IMP.CHUNK_LAYERS).filter(this::hasSection)
|
||||
return IntStream.range(getMinSectionIndex(), getMaxSectionIndex() + 1).filter(this::hasSection)
|
||||
.map(layer -> (1 << layer)).sum();
|
||||
}
|
||||
|
||||
@ -48,6 +54,21 @@ public interface IBlocks extends Trimable {
|
||||
|
||||
IBlocks reset();
|
||||
|
||||
/**
|
||||
* Get the number of stores sections
|
||||
*/
|
||||
int getSectionCount();
|
||||
|
||||
/**
|
||||
* Max ChunkSection array index
|
||||
*/
|
||||
int getMaxSectionIndex();
|
||||
|
||||
/**
|
||||
* Min ChunkSection array index
|
||||
*/
|
||||
int getMinSectionIndex();
|
||||
|
||||
default byte[] toByteArray(boolean full, boolean stretched) {
|
||||
return toByteArray(null, getBitMask(), full, stretched);
|
||||
}
|
||||
@ -61,7 +82,7 @@ public interface IBlocks extends Trimable {
|
||||
.queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry();
|
||||
FastByteArrayOutputStream sectionByteArray = new FastByteArrayOutputStream(buffer);
|
||||
try (FaweOutputStream sectionWriter = new FaweOutputStream(sectionByteArray)) {
|
||||
for (int layer = 0; layer < FaweCache.IMP.CHUNK_LAYERS; layer++) {
|
||||
for (int layer = 0; layer < this.getSectionCount(); layer++) {
|
||||
if (!this.hasSection(layer) || (bitMask & (1 << layer)) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ 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 org.jetbrains.annotations.Range;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -37,7 +36,7 @@ public interface IChunkExtent<T extends IChunk> extends Extent {
|
||||
T getOrCreateChunk(int chunkX, int chunkZ);
|
||||
|
||||
@Override
|
||||
default <B extends BlockStateHolder<B>> boolean setBlock(int x, @Range(from = 0, to = 255) int y, int z, B state) {
|
||||
default <B extends BlockStateHolder<B>> boolean setBlock(int x, int y, int z, B state) {
|
||||
final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4);
|
||||
return chunk.setBlock(x & 15, y, z & 15, state);
|
||||
}
|
||||
|
@ -48,19 +48,43 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput {
|
||||
|
||||
CompoundTag getEntity(UUID uuid);
|
||||
|
||||
void setCreateCopy(boolean createCopy);
|
||||
|
||||
boolean isCreateCopy();
|
||||
|
||||
void setCreateCopy(boolean createCopy);
|
||||
|
||||
@Nullable
|
||||
default IChunkGet getCopy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
void setLightingToGet(char[][] lighting);
|
||||
/**
|
||||
* Flush the block lighting array (section*blocks) to the chunk GET between the given section indices. Negative allowed.
|
||||
*
|
||||
* @param lighting lighting array
|
||||
* @param startSectionIndex lowest section index
|
||||
* @param endSectionIndex highest section index
|
||||
*/
|
||||
void setLightingToGet(char[][] lighting, int startSectionIndex, int endSectionIndex);
|
||||
|
||||
void setSkyLightingToGet(char[][] lighting);
|
||||
/**
|
||||
* Flush the sky lighting array (section*blocks) to the chunk GET between the given section indices. Negative allowed.
|
||||
*
|
||||
* @param lighting sky lighting array
|
||||
* @param startSectionIndex lowest section index
|
||||
* @param endSectionIndex highest section index
|
||||
*/
|
||||
void setSkyLightingToGet(char[][] lighting, int startSectionIndex, int endSectionIndex);
|
||||
|
||||
void setHeightmapToGet(HeightMapType type, int[] data);
|
||||
|
||||
/**
|
||||
* Max y value for the chunk's world (inclusive)
|
||||
*/
|
||||
int getMaxY();
|
||||
|
||||
/**
|
||||
* Min y value for the chunk's world (inclusive)
|
||||
*/
|
||||
int getMinY();
|
||||
|
||||
}
|
||||
|
@ -107,4 +107,12 @@ public interface IChunkSet extends IBlocks, OutputExtent {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given layer has biomes stored to be set to the world. Can be negative
|
||||
*
|
||||
* @param layer layer to check
|
||||
* @return if the layer has biomes stored to be set to the world
|
||||
*/
|
||||
boolean hasBiomes(int layer);
|
||||
|
||||
}
|
||||
|
@ -25,11 +25,17 @@ public class Flood {
|
||||
private int chunkYLayer;
|
||||
private int chunkZ;
|
||||
private final ConcurrentLinkedQueue<int[]> queuePool = new ConcurrentLinkedQueue<>();
|
||||
private final int minSectionIndex;
|
||||
private final int maxSectionIndex;
|
||||
private final int sectionCount;
|
||||
|
||||
public Flood(int maxBranch, int maxDepth, Direction[] directions) {
|
||||
public Flood(int maxBranch, int maxDepth, Direction[] directions, int minSectionIndex, int maxSectionIndex) {
|
||||
this.maxBranch = maxBranch;
|
||||
this.maxDepth = maxDepth;
|
||||
this.directions = directions;
|
||||
this.minSectionIndex = minSectionIndex;
|
||||
this.maxSectionIndex = maxSectionIndex;
|
||||
this.sectionCount = maxSectionIndex - minSectionIndex + 1;
|
||||
|
||||
this.queues = new int[27][];
|
||||
this.visits = new long[27][];
|
||||
@ -64,7 +70,7 @@ public class Flood {
|
||||
int chunkX = x >> 4;
|
||||
int chunkZ = z >> 4;
|
||||
long pair = MathMan.pairInt(chunkX, chunkZ);
|
||||
int layer = y >> 4;
|
||||
int layer = (y >> 4) - minSectionIndex;
|
||||
int[] section = getOrCreateQueue(pair, layer);
|
||||
int val = (x & 15) + ((z & 15) << 4) + ((y & 15) << 8) + (depth << 12);
|
||||
push(section, val);
|
||||
@ -73,7 +79,7 @@ public class Flood {
|
||||
private int[] getOrCreateQueue(long pair, int layer) {
|
||||
int[][] arrs = chunkQueues.get(pair);
|
||||
if (arrs == null) {
|
||||
chunkQueues.put(pair, arrs = new int[16][]);
|
||||
chunkQueues.put(pair, arrs = new int[sectionCount][]);
|
||||
}
|
||||
int[] section = arrs[layer];
|
||||
if (section == null) {
|
||||
@ -154,7 +160,7 @@ public class Flood {
|
||||
if (visit == null || queue == null) {
|
||||
long pair = MathMan.pairInt(this.chunkX + nextX, this.chunkZ + nextZ);
|
||||
int layer = this.chunkYLayer + nextY;
|
||||
if (layer < 0 || layer > 15) {
|
||||
if (layer < minSectionIndex || layer > maxSectionIndex) {
|
||||
continue;
|
||||
}
|
||||
queues[sectionIndex] = queue = getOrCreateQueue(pair, layer);
|
||||
|
@ -52,6 +52,10 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
||||
// Chunks currently being queued / worked on
|
||||
private final Long2ObjectLinkedOpenHashMap<IQueueChunk> chunks = new Long2ObjectLinkedOpenHashMap<>();
|
||||
|
||||
private World world = null;
|
||||
private int minY = 0;
|
||||
private int maxY = 255;
|
||||
|
||||
private IChunkCache<IChunkGet> cacheGet;
|
||||
private IChunkCache<IChunkSet> cacheSet;
|
||||
private boolean initialized;
|
||||
@ -68,7 +72,15 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
||||
|
||||
private final ReentrantLock getChunkLock = new ReentrantLock();
|
||||
|
||||
private World world = null;
|
||||
public SingleThreadQueueExtent() {}
|
||||
|
||||
/**
|
||||
* New instance given inclusive world height bounds.
|
||||
*/
|
||||
public SingleThreadQueueExtent(int minY, int maxY) {
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safety check to ensure that the thread being used matches the one being initialized on. - Can
|
||||
@ -111,6 +123,16 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
||||
return fastmode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
return minY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxY() {
|
||||
return maxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the queue.
|
||||
*/
|
||||
@ -142,6 +164,8 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
||||
@Override
|
||||
public synchronized void init(Extent extent, IChunkCache<IChunkGet> get, IChunkCache<IChunkSet> set) {
|
||||
reset();
|
||||
this.minY = extent.getMinY();
|
||||
this.maxY = extent.getMaxY();
|
||||
currentThread = Thread.currentThread();
|
||||
if (get == null) {
|
||||
get = (x, z) -> {
|
||||
|
@ -20,14 +20,21 @@ public class BitSetBlocks implements IChunkSet {
|
||||
|
||||
private final MemBlockSet.RowZ row;
|
||||
private final BlockState blockState;
|
||||
private final int minSectionIndex;
|
||||
private final int maxSectionIndex;
|
||||
private final int layers;
|
||||
|
||||
public BitSetBlocks(BlockState blockState) {
|
||||
this.row = new MemBlockSet.RowZ();
|
||||
public BitSetBlocks(BlockState blockState, int minSectionIndex, int maxSectionIndex) {
|
||||
this.row = new MemBlockSet.RowZ(minSectionIndex, maxSectionIndex);
|
||||
this.blockState = blockState;
|
||||
this.minSectionIndex = minSectionIndex;
|
||||
this.maxSectionIndex = maxSectionIndex;
|
||||
this.layers = maxSectionIndex - minSectionIndex + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
layer -= minSectionIndex;
|
||||
return row.rows[layer] != MemBlockSet.NULL_ROW_Y;
|
||||
}
|
||||
|
||||
@ -39,19 +46,21 @@ public class BitSetBlocks implements IChunkSet {
|
||||
|
||||
@Override
|
||||
public <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T holder) {
|
||||
row.set(null, x, y, z);
|
||||
y -= minSectionIndex << 4;
|
||||
row.set(null, x, y, z, minSectionIndex, maxSectionIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlocks(int layer, char[] data) {
|
||||
layer -= minSectionIndex;
|
||||
row.reset(layer);
|
||||
int by = layer << 4;
|
||||
for (int y = 0, index = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++, index++) {
|
||||
if (data[index] != 0) {
|
||||
row.set(null, x, by + y, z);
|
||||
row.set(null, x, by + y, z, minSectionIndex, maxSectionIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,6 +123,7 @@ public class BitSetBlocks implements IChunkSet {
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
layer -= minSectionIndex;
|
||||
char[] arr = FaweCache.IMP.SECTION_BITS_TO_CHAR.get();
|
||||
MemBlockSet.IRow nullRowY = row.getRow(layer);
|
||||
if (nullRowY instanceof MemBlockSet.RowY) {
|
||||
@ -189,6 +199,26 @@ public class BitSetBlocks implements IChunkSet {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBiomes(final int layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionCount() {
|
||||
return layers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSectionIndex() {
|
||||
return minSectionIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinSectionIndex() {
|
||||
return maxSectionIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return false;
|
||||
|
@ -7,7 +7,6 @@ import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
public abstract class CharBlocks implements IBlocks {
|
||||
|
||||
@ -15,30 +14,30 @@ public abstract class CharBlocks implements IBlocks {
|
||||
|
||||
protected static final Section FULL = new Section() {
|
||||
@Override
|
||||
public final char[] get(CharBlocks blocks, int layer) {
|
||||
public char[] get(CharBlocks blocks, int layer) {
|
||||
return blocks.blocks[layer];
|
||||
}
|
||||
|
||||
// Ignore aggressive switch here.
|
||||
@Override
|
||||
public char[] get(CharBlocks blocks, @Range(from = 0, to = 15) int layer, boolean aggressive) {
|
||||
public char[] get(CharBlocks blocks, int layer, boolean aggressive) {
|
||||
return blocks.blocks[layer];
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isFull() {
|
||||
public boolean isFull() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
protected final Section empty = new Section() {
|
||||
@Override
|
||||
public final synchronized char[] get(CharBlocks blocks, int layer) {
|
||||
public synchronized char[] get(CharBlocks blocks, int layer) {
|
||||
// Defaults to aggressive as it should only be avoided where we know we've reset a chunk during an edit
|
||||
return get(blocks, layer, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized char[] get(CharBlocks blocks, @Range(from = 0, to = 15) int layer, boolean aggressive) {
|
||||
public synchronized char[] get(CharBlocks blocks, int layer, boolean aggressive) {
|
||||
char[] arr = blocks.blocks[layer];
|
||||
if (arr == null) {
|
||||
arr = blocks.blocks[layer] = blocks.update(layer, null, aggressive);
|
||||
@ -58,17 +57,26 @@ public abstract class CharBlocks implements IBlocks {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isFull() {
|
||||
public boolean isFull() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
public final char[][] blocks;
|
||||
public final Section[] sections;
|
||||
public char[][] blocks;
|
||||
public Section[] sections;
|
||||
protected int minSectionIndex;
|
||||
protected int maxSectionIndex;
|
||||
protected int sectionCount;
|
||||
|
||||
public CharBlocks() {
|
||||
blocks = new char[16][];
|
||||
sections = new Section[16];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
/**
|
||||
* New instance given initial min/max section indices. Can be negative.
|
||||
*/
|
||||
public CharBlocks(int minSectionIndex, int maxSectionIndex) {
|
||||
this.minSectionIndex = minSectionIndex;
|
||||
this.maxSectionIndex = maxSectionIndex;
|
||||
this.sectionCount = maxSectionIndex - minSectionIndex + 1;
|
||||
blocks = new char[sectionCount][];
|
||||
sections = new Section[sectionCount];
|
||||
for (int i = 0; i < sectionCount; i++) {
|
||||
sections[i] = empty;
|
||||
}
|
||||
}
|
||||
@ -76,7 +84,7 @@ public abstract class CharBlocks implements IBlocks {
|
||||
@Override
|
||||
public synchronized boolean trim(boolean aggressive) {
|
||||
boolean result = true;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int i = 0; i < sectionCount; i++) {
|
||||
if (!sections[i].isFull() && blocks[i] != null) {
|
||||
blocks[i] = null;
|
||||
} else {
|
||||
@ -99,13 +107,14 @@ public abstract class CharBlocks implements IBlocks {
|
||||
|
||||
@Override
|
||||
public synchronized IChunkSet reset() {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int i = 0; i < sectionCount; i++) {
|
||||
sections[i] = empty;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized void reset(@Range(from = 0, to = 15) int layer) {
|
||||
public synchronized void reset(int layer) {
|
||||
layer -= minSectionIndex;
|
||||
sections[layer] = empty;
|
||||
}
|
||||
|
||||
@ -121,12 +130,14 @@ public abstract class CharBlocks implements IBlocks {
|
||||
|
||||
// Not synchronized as any subsequent methods called from this class will be, or the section shouldn't appear as loaded anyway.
|
||||
@Override
|
||||
public boolean hasSection(@Range(from = 0, to = 15) int layer) {
|
||||
return sections[layer].isFull();
|
||||
public boolean hasSection(int layer) {
|
||||
layer -= minSectionIndex;
|
||||
return layer >= 0 && layer < sections.length && sections[layer].isFull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(@Range(from = 0, to = 15) int layer) {
|
||||
public char[] load(int layer) {
|
||||
layer -= minSectionIndex;
|
||||
synchronized (sections[layer]) {
|
||||
return sections[layer].get(this, layer);
|
||||
}
|
||||
@ -137,17 +148,17 @@ public abstract class CharBlocks implements IBlocks {
|
||||
return BlockTypesCache.states[get(x, y, z)];
|
||||
}
|
||||
|
||||
public char get(int x, @Range(from = 0, to = 255) int y, int z) {
|
||||
final int layer = y >> 4;
|
||||
public char get(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
final int index = (y & 15) << 8 | z << 4 | x;
|
||||
if (layer >= sections.length || layer < 0) {
|
||||
if (layer > maxSectionIndex || layer < minSectionIndex) {
|
||||
return 0;
|
||||
}
|
||||
return sections[layer].get(this, layer, index);
|
||||
return get(layer, index);
|
||||
}
|
||||
|
||||
// Not synchronized as it refers to a synchronized method and includes nothing that requires synchronization
|
||||
public void set(int x, @Range(from = 0, to = 255) int y, int z, char value) {
|
||||
public void set(int x, int y, int z, char value) {
|
||||
final int layer = y >> 4;
|
||||
final int index = (y & 15) << 8 | z << 4 | x;
|
||||
try {
|
||||
@ -163,24 +174,26 @@ public abstract class CharBlocks implements IBlocks {
|
||||
Section
|
||||
*/
|
||||
|
||||
public final char get(@Range(from = 0, to = 15) int layer, int index) {
|
||||
public final char get(int layer, int index) {
|
||||
layer -= minSectionIndex;
|
||||
return sections[layer].get(this, layer, index);
|
||||
}
|
||||
|
||||
public synchronized final void set(@Range(from = 0, to = 15) int layer, int index, char value) throws
|
||||
public synchronized final void set(int layer, int index, char value) throws
|
||||
ArrayIndexOutOfBoundsException {
|
||||
layer -= minSectionIndex;
|
||||
sections[layer].set(this, layer, index, value);
|
||||
}
|
||||
|
||||
public abstract static class Section {
|
||||
|
||||
public abstract char[] get(CharBlocks blocks, @Range(from = 0, to = 15) int layer);
|
||||
public abstract char[] get(CharBlocks blocks, int layer);
|
||||
|
||||
public abstract char[] get(CharBlocks blocks, @Range(from = 0, to = 15) int layer, boolean aggressive);
|
||||
public abstract char[] get(CharBlocks blocks, int layer, boolean aggressive);
|
||||
|
||||
public abstract boolean isFull();
|
||||
|
||||
public final char get(CharBlocks blocks, @Range(from = 0, to = 15) int layer, int index) {
|
||||
public final char get(CharBlocks blocks, int layer, int index) {
|
||||
char[] section = get(blocks, layer);
|
||||
if (section == null) {
|
||||
blocks.reset(layer);
|
||||
@ -189,7 +202,7 @@ public abstract class CharBlocks implements IBlocks {
|
||||
return section[index];
|
||||
}
|
||||
|
||||
public final void set(CharBlocks blocks, @Range(from = 0, to = 15) int layer, int index, char value) {
|
||||
public final void set(CharBlocks blocks, int layer, int index, char value) {
|
||||
get(blocks, layer)[index] = value;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,13 @@ import java.util.Arrays;
|
||||
|
||||
public abstract class CharGetBlocks extends CharBlocks implements IChunkGet {
|
||||
|
||||
/**
|
||||
* New instance given the min/max section indices
|
||||
*/
|
||||
public CharGetBlocks(final int minSectionIndex, final int maxSectionIndex) {
|
||||
super(minSectionIndex, maxSectionIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
BlockState state = BlockTypesCache.states[get(x, y, z)];
|
||||
@ -18,7 +25,7 @@ public abstract class CharGetBlocks extends CharBlocks implements IChunkGet {
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int i = 0; i < sectionCount; i++) {
|
||||
sections[i] = empty;
|
||||
blocks[i] = null;
|
||||
}
|
||||
@ -36,6 +43,7 @@ public abstract class CharGetBlocks extends CharBlocks implements IChunkGet {
|
||||
|
||||
@Override
|
||||
public synchronized boolean trim(boolean aggressive, int layer) {
|
||||
layer -= minSectionIndex;
|
||||
sections[layer] = empty;
|
||||
blocks[layer] = null;
|
||||
return true;
|
||||
@ -47,4 +55,9 @@ public abstract class CharGetBlocks extends CharBlocks implements IChunkGet {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionCount() {
|
||||
return sectionCount;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -45,6 +44,8 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
private int bitMask = -1;
|
||||
|
||||
private CharSetBlocks() {
|
||||
// Expand as we go
|
||||
super(0, 15);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -59,9 +60,10 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
if (biomes == null) {
|
||||
if (biomes == null || (y >> 4) < minSectionIndex || (y >> 4) > maxSectionIndex) {
|
||||
return null;
|
||||
}
|
||||
y -= minSectionIndex << 4;
|
||||
return biomes[(y >> 2) << 4 | (z >> 2) << 2 | x >> 2];
|
||||
}
|
||||
|
||||
@ -92,15 +94,18 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int y, int z, BiomeType biome) {
|
||||
updateSectionIndexRange(y >> 4);
|
||||
y -= minSectionIndex << 4;
|
||||
if (biomes == null) {
|
||||
biomes = new BiomeType[1024];
|
||||
biomes = new BiomeType[64 * sectionCount];
|
||||
}
|
||||
biomes[(y >> 2) << 4 | (z >> 2) << 2 | x >> 2] = biome;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockStateHolder<T>> boolean setBlock(int x, @Range(from = 0, to = 255) int y, int z, T holder) {
|
||||
public <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T holder) {
|
||||
updateSectionIndexRange(y >> 4);
|
||||
set(x, y, z, holder.getOrdinalChar());
|
||||
holder.applyTileEntity(this, x, y, z);
|
||||
return true;
|
||||
@ -108,6 +113,8 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
|
||||
@Override
|
||||
public void setBlocks(int layer, char[] data) {
|
||||
updateSectionIndexRange(layer);
|
||||
layer -= minSectionIndex;
|
||||
this.blocks[layer] = data;
|
||||
this.sections[layer] = data == null ? empty : FULL;
|
||||
}
|
||||
@ -123,38 +130,41 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
if (tiles == null) {
|
||||
tiles = new BlockVector3ChunkMap<>();
|
||||
}
|
||||
updateSectionIndexRange(y >> 4);
|
||||
tiles.put(x, y, z, tile);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockLight(int x, int y, int z, int value) {
|
||||
updateSectionIndexRange(y >> 4);
|
||||
if (light == null) {
|
||||
light = new char[16][];
|
||||
light = new char[sectionCount][];
|
||||
}
|
||||
final int layer = y >> 4;
|
||||
final int layer = (y >> 4) - minSectionIndex;
|
||||
if (light[layer] == null) {
|
||||
char[] c = new char[4096];
|
||||
Arrays.fill(c, (char) 16);
|
||||
light[layer] = c;
|
||||
}
|
||||
final int index = (y & 15) << 8 | (z & 15) << 4 | (x & 15);
|
||||
light[y >> 4][index] = (char) value;
|
||||
light[layer][index] = (char) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLight(int x, int y, int z, int value) {
|
||||
updateSectionIndexRange(y >> 4);
|
||||
if (skyLight == null) {
|
||||
skyLight = new char[16][];
|
||||
skyLight = new char[sectionCount][];
|
||||
}
|
||||
final int layer = y >> 4;
|
||||
final int layer = (y >> 4) - minSectionIndex;
|
||||
if (skyLight[layer] == null) {
|
||||
char[] c = new char[4096];
|
||||
Arrays.fill(c, (char) 16);
|
||||
skyLight[layer] = c;
|
||||
}
|
||||
final int index = (y & 15) << 8 | (z & 15) << 4 | (x & 15);
|
||||
skyLight[y >> 4][index] = (char) value;
|
||||
skyLight[layer][index] = (char) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -167,17 +177,21 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
|
||||
@Override
|
||||
public void setLightLayer(int layer, char[] toSet) {
|
||||
updateSectionIndexRange(layer);
|
||||
if (light == null) {
|
||||
light = new char[16][];
|
||||
light = new char[sectionCount][];
|
||||
}
|
||||
layer -= minSectionIndex;
|
||||
light[layer] = toSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightLayer(int layer, char[] toSet) {
|
||||
updateSectionIndexRange(layer);
|
||||
if (skyLight == null) {
|
||||
skyLight = new char[16][];
|
||||
skyLight = new char[sectionCount][];
|
||||
}
|
||||
layer -= minSectionIndex;
|
||||
skyLight[layer] = toSet;
|
||||
}
|
||||
|
||||
@ -193,8 +207,10 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {
|
||||
updateSectionIndexRange(layer);
|
||||
layer -= minSectionIndex;
|
||||
if (light == null) {
|
||||
light = new char[16][];
|
||||
light = new char[sectionCount][];
|
||||
}
|
||||
if (light[layer] == null) {
|
||||
light[layer] = new char[4096];
|
||||
@ -202,7 +218,7 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
Arrays.fill(light[layer], (char) 0);
|
||||
if (sky) {
|
||||
if (skyLight == null) {
|
||||
skyLight = new char[16][];
|
||||
skyLight = new char[sectionCount][];
|
||||
}
|
||||
if (skyLight[layer] == null) {
|
||||
skyLight[layer] = new char[4096];
|
||||
@ -213,14 +229,16 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
|
||||
@Override
|
||||
public void setFullBright(int layer) {
|
||||
updateSectionIndexRange(layer);
|
||||
layer -= minSectionIndex;
|
||||
if (light == null) {
|
||||
light = new char[16][];
|
||||
light = new char[sectionCount][];
|
||||
}
|
||||
if (light[layer] == null) {
|
||||
light[layer] = new char[4096];
|
||||
}
|
||||
if (skyLight == null) {
|
||||
skyLight = new char[16][];
|
||||
skyLight = new char[sectionCount][];
|
||||
}
|
||||
if (skyLight[layer] == null) {
|
||||
skyLight[layer] = new char[4096];
|
||||
@ -275,7 +293,7 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
if (biomes != null || light != null || skyLight != null) {
|
||||
return false;
|
||||
}
|
||||
return IntStream.range(0, 16).noneMatch(this::hasSection);
|
||||
return IntStream.range(minSectionIndex, maxSectionIndex + 1).noneMatch(this::hasSection);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -288,4 +306,98 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBiomes(int layer) {
|
||||
layer -= minSectionIndex;
|
||||
if (layer < 0 || layer >= sections.length) {
|
||||
return false;
|
||||
}
|
||||
return biomes != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(final int layer) {
|
||||
updateSectionIndexRange(layer);
|
||||
return super.load(layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionCount() {
|
||||
return sectionCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSectionIndex() {
|
||||
return maxSectionIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinSectionIndex() {
|
||||
return minSectionIndex;
|
||||
}
|
||||
|
||||
// Checks and updates the various section arrays against the new layer index
|
||||
private void updateSectionIndexRange(int layer) {
|
||||
if (layer >= minSectionIndex && layer <= maxSectionIndex) {
|
||||
return;
|
||||
}
|
||||
if (layer < minSectionIndex) {
|
||||
int diff = minSectionIndex - layer;
|
||||
sectionCount += diff;
|
||||
char[][] tmpBlocks = new char[sectionCount][];
|
||||
Section[] tmpSections = new Section[sectionCount];
|
||||
System.arraycopy(blocks, 0, tmpBlocks, diff, blocks.length);
|
||||
System.arraycopy(sections, 0, tmpSections, diff, sections.length);
|
||||
for (int i = 0; i < diff; i++) {
|
||||
tmpSections[i] = empty;
|
||||
}
|
||||
blocks = tmpBlocks;
|
||||
sections = tmpSections;
|
||||
minSectionIndex = layer;
|
||||
if (biomes != null) {
|
||||
BiomeType[] tmpBiomes = new BiomeType[sectionCount * 64];
|
||||
System.arraycopy(biomes, 0, tmpBiomes, 64*diff, biomes.length);
|
||||
biomes = tmpBiomes;
|
||||
}
|
||||
if (light != null) {
|
||||
char[][] tmplight = new char[sectionCount][];
|
||||
System.arraycopy(light, 0, tmplight, diff, light.length);
|
||||
light = tmplight;
|
||||
}
|
||||
if (skyLight != null) {
|
||||
char[][] tmplight = new char[sectionCount][];
|
||||
System.arraycopy(skyLight, 0, tmplight, diff, skyLight.length);
|
||||
skyLight = tmplight;
|
||||
}
|
||||
} else {
|
||||
int diff = layer - maxSectionIndex;
|
||||
sectionCount += diff;
|
||||
char[][] tmpBlocks = new char[sectionCount][];
|
||||
Section[] tmpSections = new Section[sectionCount];
|
||||
System.arraycopy(blocks, 0, tmpBlocks, 0, blocks.length);
|
||||
System.arraycopy(sections, 0, tmpSections, 0, sections.length);
|
||||
for (int i = sectionCount - diff; i < sectionCount; i++) {
|
||||
tmpSections[i] = empty;
|
||||
}
|
||||
blocks = tmpBlocks;
|
||||
sections = tmpSections;
|
||||
maxSectionIndex = layer;
|
||||
if (biomes != null) {
|
||||
BiomeType[] tmpBiomes = new BiomeType[sectionCount * 64];
|
||||
System.arraycopy(biomes, 0, tmpBiomes, 0, biomes.length);
|
||||
biomes = tmpBiomes;
|
||||
}
|
||||
if (light != null) {
|
||||
char[][] tmplight = new char[sectionCount][];
|
||||
System.arraycopy(light, 0, tmplight, 0, light.length);
|
||||
light = tmplight;
|
||||
}
|
||||
if (skyLight != null) {
|
||||
char[][] tmplight = new char[sectionCount][];
|
||||
System.arraycopy(skyLight, 0, tmplight, 0, skyLight.length);
|
||||
skyLight = tmplight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -78,17 +78,37 @@ public final class NullChunkGet implements IChunkGet {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] lighting) {
|
||||
public void setLightingToGet(char[][] lighting, int startSectionIndex, int endSectionIndex) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] lighting) {
|
||||
public void setSkyLightingToGet(char[][] lighting, int minSectionIndex, int maxSectionIndex) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSectionIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinSectionIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean trim(boolean aggressive) {
|
||||
return true;
|
||||
}
|
||||
@ -129,6 +149,11 @@ public final class NullChunkGet implements IChunkGet {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private NullChunkGet() {
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,6 @@ 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 org.jetbrains.annotations.Range;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
@ -140,6 +139,12 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
return bitMask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBiomes(final int layer) {
|
||||
// No need to go through delegate. hasBiomes is SET only.
|
||||
return getOrCreateSet().hasBiomes(layer);
|
||||
}
|
||||
|
||||
public boolean isInit() {
|
||||
return isInit;
|
||||
}
|
||||
@ -160,12 +165,12 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] lighting) {
|
||||
public void setLightingToGet(char[][] lighting, int minSectionIndex, int maxSectionIndex) {
|
||||
delegate.setLightingToGet(this, lighting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] lighting) {
|
||||
public void setSkyLightingToGet(char[][] lighting, int minSectionIndex, int maxSectionIndex) {
|
||||
delegate.setSkyLightingToGet(this, lighting);
|
||||
}
|
||||
|
||||
@ -174,8 +179,28 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
delegate.setHeightmapToGet(this, type, data);
|
||||
}
|
||||
|
||||
public void flushLightToGet(boolean heightmaps) {
|
||||
delegate.flushLightToGet(this, heightmaps);
|
||||
@Override
|
||||
public int getMaxY() {
|
||||
return getOrCreateGet().getMaxY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
return getOrCreateGet().getMinY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSectionIndex() {
|
||||
return getOrCreateGet().getMaxSectionIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinSectionIndex() {
|
||||
return getOrCreateGet().getMinSectionIndex();
|
||||
}
|
||||
|
||||
public void flushLightToGet() {
|
||||
delegate.flushLightToGet(this);
|
||||
}
|
||||
|
||||
private static final IBlockDelegate BOTH = new IBlockDelegate() {
|
||||
@ -260,6 +285,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
public int getSkyLight(ChunkHolder chunk, int x, int y, int z) {
|
||||
if (chunk.chunkSet.getSkyLight() != null) {
|
||||
int layer = y >> 4;
|
||||
layer -= chunk.chunkSet.getMinSectionIndex();
|
||||
if (chunk.chunkSet.getSkyLight()[layer] != null) {
|
||||
int setLightValue = chunk.chunkSet.getSkyLight()[layer][(y & 15) << 8 | (z & 15) << 4 | (x & 15)];
|
||||
if (setLightValue < 16) {
|
||||
@ -274,6 +300,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
public int getEmittedLight(ChunkHolder chunk, int x, int y, int z) {
|
||||
if (chunk.chunkSet.getLight() != null) {
|
||||
int layer = y >> 4;
|
||||
layer -= chunk.chunkSet.getMinSectionIndex();
|
||||
if (chunk.chunkSet.getLight()[layer] != null) {
|
||||
int setLightValue = chunk.chunkSet.getLight()[layer][(y & 15) << 8 | (z & 15) << 4 | (x & 15)];
|
||||
if (setLightValue < 16) {
|
||||
@ -300,19 +327,21 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushLightToGet(ChunkHolder chunk, boolean heightmaps) {
|
||||
chunk.chunkExisting.setLightingToGet(chunk.chunkSet.getLight());
|
||||
chunk.chunkExisting.setSkyLightingToGet(chunk.chunkSet.getSkyLight());
|
||||
public void flushLightToGet(ChunkHolder chunk) {
|
||||
chunk.chunkExisting.setLightingToGet(chunk.chunkSet.getLight(), chunk.chunkSet.getMinSectionIndex(),
|
||||
chunk.chunkSet.getMaxSectionIndex());
|
||||
chunk.chunkExisting.setSkyLightingToGet(chunk.chunkSet.getSkyLight(), chunk.chunkSet.getMinSectionIndex(),
|
||||
chunk.chunkSet.getMaxSectionIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(ChunkHolder chunk, char[][] lighting) {
|
||||
chunk.chunkExisting.setLightingToGet(lighting);
|
||||
chunk.chunkExisting.setLightingToGet(lighting, chunk.chunkSet.getMinSectionIndex(), chunk.chunkSet.getMaxSectionIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(ChunkHolder chunk, char[][] lighting) {
|
||||
chunk.chunkExisting.setSkyLightingToGet(lighting);
|
||||
chunk.chunkExisting.setSkyLightingToGet(lighting, chunk.chunkSet.getMinSectionIndex(), chunk.chunkSet.getMaxSectionIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -447,18 +476,18 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushLightToGet(ChunkHolder chunk, boolean heightmaps) {
|
||||
public void flushLightToGet(ChunkHolder chunk) {
|
||||
// Do nothing as no lighting to flush to GET
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(ChunkHolder chunk, char[][] lighting) {
|
||||
chunk.chunkExisting.setLightingToGet(lighting);
|
||||
chunk.chunkExisting.setLightingToGet(lighting, chunk.chunkSet.getMinSectionIndex(), chunk.chunkSet.getMaxSectionIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(ChunkHolder chunk, char[][] lighting) {
|
||||
chunk.chunkExisting.setSkyLightingToGet(lighting);
|
||||
chunk.chunkExisting.setSkyLightingToGet(lighting, chunk.chunkSet.getMinSectionIndex(), chunk.chunkSet.getMaxSectionIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -493,7 +522,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
public <B extends BlockStateHolder<B>> boolean setBlock(
|
||||
ChunkHolder chunk,
|
||||
int x,
|
||||
@Range(from = 0, to = 255) int y,
|
||||
int y,
|
||||
int z,
|
||||
B block
|
||||
) {
|
||||
@ -568,6 +597,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
public int getSkyLight(ChunkHolder chunk, int x, int y, int z) {
|
||||
if (chunk.chunkSet.getSkyLight() != null) {
|
||||
int layer = y >> 4;
|
||||
layer -= chunk.chunkSet.getMinSectionIndex();
|
||||
if (chunk.chunkSet.getSkyLight()[layer] != null) {
|
||||
int setLightValue = chunk.chunkSet.getSkyLight()[layer][(y & 15) << 8 | (z & 15) << 4 | (x & 15)];
|
||||
if (setLightValue < 16) {
|
||||
@ -585,6 +615,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
public int getEmittedLight(ChunkHolder chunk, int x, int y, int z) {
|
||||
if (chunk.chunkSet.getLight() != null) {
|
||||
int layer = y >> 4;
|
||||
layer -= chunk.chunkSet.getMinSectionIndex();
|
||||
if (chunk.chunkSet.getLight()[layer] != null) {
|
||||
int setLightValue = chunk.chunkSet.getLight()[layer][(y & 15) << 8 | (z & 15) << 4 | (x & 15)];
|
||||
if (setLightValue < 16) {
|
||||
@ -623,12 +654,11 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushLightToGet(ChunkHolder chunk, boolean heightmaps) {
|
||||
public void flushLightToGet(ChunkHolder chunk) {
|
||||
chunk.getOrCreateGet();
|
||||
chunk.delegate = BOTH;
|
||||
chunk.chunkExisting.trim(false);
|
||||
chunk.chunkExisting.setLightingToGet(chunk.chunkSet.getLight());
|
||||
chunk.chunkExisting.setSkyLightingToGet(chunk.chunkSet.getSkyLight());
|
||||
chunk.flushLightToGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -636,7 +666,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
chunk.getOrCreateGet();
|
||||
chunk.delegate = BOTH;
|
||||
chunk.chunkExisting.trim(false);
|
||||
chunk.chunkExisting.setLightingToGet(lighting);
|
||||
chunk.setLightingToGet(lighting, chunk.chunkSet.getMinSectionIndex(), chunk.chunkSet.getMaxSectionIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -644,7 +674,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
chunk.getOrCreateGet();
|
||||
chunk.delegate = BOTH;
|
||||
chunk.chunkExisting.trim(false);
|
||||
chunk.chunkExisting.setSkyLightingToGet(lighting);
|
||||
chunk.setSkyLightingToGet(lighting, chunk.chunkSet.getMinSectionIndex(), chunk.chunkSet.getMaxSectionIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -652,7 +682,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
chunk.getOrCreateGet();
|
||||
chunk.delegate = BOTH;
|
||||
chunk.chunkExisting.trim(false);
|
||||
chunk.chunkExisting.setHeightmapToGet(type, data);
|
||||
chunk.setHeightmapToGet(type, data);
|
||||
}
|
||||
};
|
||||
|
||||
@ -804,7 +834,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushLightToGet(ChunkHolder chunk, boolean heightmaps) {
|
||||
public void flushLightToGet(ChunkHolder chunk) {
|
||||
// Do nothing as no light to flush
|
||||
}
|
||||
|
||||
@ -813,7 +843,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
chunk.getOrCreateGet();
|
||||
chunk.delegate = GET;
|
||||
chunk.chunkExisting.trim(false);
|
||||
chunk.setLightingToGet(lighting);
|
||||
chunk.setLightingToGet(lighting, chunk.chunkSet.getMinSectionIndex(), chunk.chunkSet.getMaxSectionIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -821,7 +851,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
chunk.getOrCreateGet();
|
||||
chunk.delegate = GET;
|
||||
chunk.chunkExisting.trim(false);
|
||||
chunk.setSkyLightingToGet(lighting);
|
||||
chunk.setSkyLightingToGet(lighting, chunk.chunkSet.getMinSectionIndex(), chunk.chunkSet.getMaxSectionIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -889,6 +919,11 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
return this.trim(aggressive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionCount() {
|
||||
return getOrCreateGet().getSectionCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return chunkSet == null || chunkSet.isEmpty();
|
||||
@ -1117,7 +1152,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
|
||||
int[] getHeightMap(ChunkHolder chunk, HeightMapType type);
|
||||
|
||||
void flushLightToGet(ChunkHolder chunk, boolean heightmaps);
|
||||
void flushLightToGet(ChunkHolder chunk);
|
||||
|
||||
void setLightingToGet(ChunkHolder chunk, char[][] lighting);
|
||||
|
||||
|
@ -82,6 +82,11 @@ public final class NullChunk implements IQueueChunk {
|
||||
return new char[0][];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBiomes(final int layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public int[] getHeightMap(@Nullable HeightMapType type) {
|
||||
return new int[256];
|
||||
@ -182,17 +187,37 @@ public final class NullChunk implements IQueueChunk {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] lighting) {
|
||||
public void setLightingToGet(char[][] lighting, int minSectionIndex, int maxSectionIndex) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] lighting) {
|
||||
public void setSkyLightingToGet(char[][] lighting, int minSectionIndex, int maxSectionIndex) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSectionIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinSectionIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T extends Future<T>> T call(@Nullable IChunkSet set, @Nullable Runnable finalize) {
|
||||
return null;
|
||||
@ -206,6 +231,11 @@ public final class NullChunk implements IQueueChunk {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private NullChunk() {
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ public class FuzzyRegion extends AbstractRegion {
|
||||
RecursiveVisitor search = new RecursiveVisitor(mask, p -> {
|
||||
setMinMax(p.getBlockX(), p.getBlockY(), p.getBlockZ());
|
||||
return true;
|
||||
}, 256);
|
||||
}, 256, extent.getMinY(), extent.getMaxY());
|
||||
search.setVisited(set);
|
||||
search.visit(BlockVector3.at(x, y, z));
|
||||
Operations.completeBlindly(search);
|
||||
|
@ -7,6 +7,8 @@ import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
public class RegionWrapper extends CuboidRegion {
|
||||
|
||||
private static final RegionWrapper GLOBAL = new RegionWrapper(
|
||||
Integer.MIN_VALUE,
|
||||
Integer.MAX_VALUE,
|
||||
Integer.MIN_VALUE,
|
||||
Integer.MAX_VALUE,
|
||||
Integer.MIN_VALUE,
|
||||
@ -20,16 +22,16 @@ public class RegionWrapper extends CuboidRegion {
|
||||
public int minZ;
|
||||
public int maxZ;
|
||||
|
||||
public static RegionWrapper GLOBAL() {
|
||||
return GLOBAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link RegionWrapper#RegionWrapper(int, int, int, int, int, int)}
|
||||
*/
|
||||
@Deprecated
|
||||
public RegionWrapper(final int minX, final int maxX, final int minZ, final int maxZ) {
|
||||
this(minX, maxX, 0, 255, minZ, maxZ);
|
||||
}
|
||||
|
||||
public RegionWrapper(final int minX, final int maxX, final int minY, final int maxY, final int minZ, final int maxZ) {
|
||||
this(BlockVector3.at(minX, 0, minZ), BlockVector3.at(maxX, 255, maxZ));
|
||||
this(BlockVector3.at(minX, minY, minZ), BlockVector3.at(maxX, maxY, maxZ));
|
||||
}
|
||||
|
||||
public RegionWrapper(final BlockVector3 pos1, final BlockVector3 pos2) {
|
||||
@ -42,6 +44,10 @@ public class RegionWrapper extends CuboidRegion {
|
||||
this.maxY = Math.max(pos1.getBlockY(), pos2.getBlockY());
|
||||
}
|
||||
|
||||
public static RegionWrapper GLOBAL() {
|
||||
return GLOBAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void recalculate() {
|
||||
super.recalculate();
|
||||
@ -134,7 +140,8 @@ public class RegionWrapper extends CuboidRegion {
|
||||
|
||||
@Override
|
||||
public boolean isGlobal() {
|
||||
return minX == Integer.MIN_VALUE && minZ == Integer.MIN_VALUE && maxX == Integer.MAX_VALUE && maxZ == Integer.MAX_VALUE && minY <= 0 && maxY >= 255;
|
||||
return minX == Integer.MIN_VALUE && minY == Integer.MIN_VALUE && minZ == Integer.MIN_VALUE
|
||||
&& maxX == Integer.MAX_VALUE && maxY == Integer.MAX_VALUE && maxZ == Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public boolean contains(RegionWrapper current) {
|
||||
|
@ -152,52 +152,65 @@ public class MathMan {
|
||||
}
|
||||
|
||||
public static long tripleWorldCoord(int x, int y, int z) {
|
||||
return y + (((long) x & 0x3FFFFFF) << 8) + (((long) z & 0x3FFFFFF) << 34);
|
||||
return ((y + 256) & 0xffff) + (((long) x & 0xffffff) << 16) + (((long) z & 0xffffff) << 40);
|
||||
}
|
||||
|
||||
public static long untripleWorldCoordX(long triple) {
|
||||
return (((triple >> 8) & 0x3FFFFFF) << 38) >> 38;
|
||||
return (((triple >> 16) & 0xffffff) << 38) >> 38;
|
||||
}
|
||||
|
||||
public static long untripleWorldCoordY(long triple) {
|
||||
return triple & 0xFF;
|
||||
return (triple & 0xffff) - 256;
|
||||
}
|
||||
|
||||
public static long untripleWorldCoordZ(long triple) {
|
||||
return (((triple >> 34) & 0x3FFFFFF) << 38) >> 38;
|
||||
return (((triple >> 40) & 0xffffff) << 38) >> 38;
|
||||
}
|
||||
|
||||
public static short tripleBlockCoord(int x, int y, int z) {
|
||||
return (short) ((x & 15) << 12 | (z & 15) << 8 | y);
|
||||
public static int tripleBlockCoord(int x, int y, int z) {
|
||||
// account for the fact y can be negative now. Assume it won't be less than -256
|
||||
y += 256;
|
||||
return ((x & 15) << 16 | (z & 15) << 12 | y);
|
||||
}
|
||||
|
||||
public static char tripleBlockCoordChar(int x, int y, int z) {
|
||||
return (char) ((x & 15) << 12 | (z & 15) << 8 | y);
|
||||
return (char) ((x & 15) << 16 | (z & 15) << 12 | y);
|
||||
}
|
||||
|
||||
public static int untripleBlockCoordX(int triple) {
|
||||
return (triple >> 12) & 0xF;
|
||||
return (triple >> 16) & 0xF;
|
||||
}
|
||||
|
||||
public static int untripleBlockCoordY(int triple) {
|
||||
return (triple & 0xFF);
|
||||
return (triple & 0x1ff) - 256;
|
||||
}
|
||||
|
||||
public static int untripleBlockCoordZ(int triple) {
|
||||
return (triple >> 8) & 0xF;
|
||||
return (triple >> 12) & 0xF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain an integer representation of 3 ints, x, y and z. y is represented by the right-most 9 bits and can
|
||||
* be within the range -256 to 255 (inclusive). x and z are represented by 11 bits each and can be within the range
|
||||
* -1024 to 1023 (inclusive).
|
||||
*
|
||||
* @param x x value
|
||||
* @param y y value
|
||||
* @param z z value
|
||||
* @return integer representation of x y z
|
||||
*/
|
||||
public static int tripleSearchCoords(int x, int y, int z) {
|
||||
byte b1 = (byte) y;
|
||||
byte b3 = (byte) (x);
|
||||
byte b4 = (byte) (z);
|
||||
int x16 = (x >> 8) & 0x7;
|
||||
int z16 = (z >> 8) & 0x7;
|
||||
byte b2 = MathMan.pair8(x16, z16);
|
||||
return ((b1 & 0xFF)
|
||||
+ ((b2 & 0x7F) << 8)
|
||||
+ ((b3 & 0xFF) << 15)
|
||||
+ ((b4 & 0xFF) << 23));
|
||||
if (x > 1023 || x < -1024 || y > 255 || y < -256 || z > 1023 || z < -1024) {
|
||||
throw new IndexOutOfBoundsException(String.format("Check range on x=%s, y=%s and z=%s!", x, y, z));
|
||||
}
|
||||
int b1 = Math.abs(y) & 0xff;
|
||||
int b3 = x & 0xff;
|
||||
int b4 = z & 0xff;
|
||||
int x16 = (((x >> 8) & 0x3) | (x < 0 ? 0x4 : 0x00));
|
||||
int z16 = (((z >> 8) & 0x3) | (z < 0 ? 0x4 : 0x00));
|
||||
int y16 = (y < 0 ? 0x1 : 0x00);
|
||||
int b2 = ((x16 + (z16 << 3) + (y16 << 6)));
|
||||
return (((b1) | (b2 << 8)) | (b3 << 15)) | (b4 << 23);
|
||||
}
|
||||
|
||||
public static int pairSearchCoords(int x, int y) {
|
||||
|
@ -28,17 +28,17 @@ public final class MemBlockSet extends BlockSet {
|
||||
public static final IRow NULL_ROW_Y = new NullRowY();
|
||||
public final IRow[] rows;
|
||||
public final MutableBlockVector3 mutable;
|
||||
private final int minSectionIndex;
|
||||
private final int maxSectionIndex;
|
||||
|
||||
public MemBlockSet() {
|
||||
this(16, 0, 0);
|
||||
}
|
||||
|
||||
public MemBlockSet(int size, int offsetX, int offsetZ) {
|
||||
public MemBlockSet(int size, int offsetX, int offsetZ, int minSectionIndex, int maxSectionIndex) {
|
||||
super(offsetX, offsetZ);
|
||||
this.rows = new IRow[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
rows[i] = NULL_ROW_X;
|
||||
}
|
||||
this.minSectionIndex = minSectionIndex;
|
||||
this.maxSectionIndex = maxSectionIndex;
|
||||
this.mutable = new MutableBlockVector3();
|
||||
}
|
||||
|
||||
@ -53,14 +53,14 @@ public final class MemBlockSet extends BlockSet {
|
||||
public boolean add(int x, int y, int z) {
|
||||
x -= getBlockOffsetX();
|
||||
z -= getBlockOffsetZ();
|
||||
return rows[x >> 4].add(this.rows, x, y, z - getBlockOffsetZ());
|
||||
return rows[x >> 4].add(this.rows, x, y, z - getBlockOffsetZ(), minSectionIndex, maxSectionIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(int x, int y, int z) {
|
||||
x -= getBlockOffsetX();
|
||||
z -= getBlockOffsetZ();
|
||||
rows[x >> 4].set(this.rows, x, y, z - getBlockOffsetZ());
|
||||
rows[x >> 4].set(this.rows, x, y, z - getBlockOffsetZ(), minSectionIndex, maxSectionIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -88,11 +88,11 @@ public final class MemBlockSet extends BlockSet {
|
||||
|
||||
@Override
|
||||
public Set<BlockVector2> getChunks() {
|
||||
return new AbstractSet<BlockVector2>() {
|
||||
return new AbstractSet<>() {
|
||||
@Nonnull
|
||||
@Override
|
||||
public Iterator<BlockVector2> iterator() {
|
||||
return new Iterator<BlockVector2>() {
|
||||
return new Iterator<>() {
|
||||
private final MutableBlockVector2 mutable = new MutableBlockVector2();
|
||||
private boolean hasNext;
|
||||
private int X;
|
||||
@ -181,10 +181,10 @@ public final class MemBlockSet extends BlockSet {
|
||||
}
|
||||
|
||||
public Set<BlockVector3> getChunkCubes() {
|
||||
return new AbstractSet<BlockVector3>() {
|
||||
return new AbstractSet<>() {
|
||||
@Override
|
||||
public Iterator<BlockVector3> iterator() {
|
||||
return new Iterator<BlockVector3>() {
|
||||
return new Iterator<>() {
|
||||
private final MutableBlockVector3 mutable = new MutableBlockVector3();
|
||||
private boolean hasNext;
|
||||
private int X;
|
||||
@ -234,7 +234,7 @@ public final class MemBlockSet extends BlockSet {
|
||||
@Override
|
||||
public BlockVector3 next() {
|
||||
mutable.setComponents(
|
||||
setX + getBlockOffsetX(), setY, setZ + getBlockOffsetX());
|
||||
setX + getBlockOffsetX(), setY - (minSectionIndex << 4), setZ + getBlockOffsetX());
|
||||
init();
|
||||
return mutable;
|
||||
}
|
||||
@ -282,7 +282,7 @@ public final class MemBlockSet extends BlockSet {
|
||||
if (rowx instanceof RowX) {
|
||||
IRow rowz = ((RowX) rowx).rows[other.getZ()];
|
||||
if (rowz instanceof RowZ) {
|
||||
return ((RowZ) rowz).rows[other.getY() - getChunkOffsetZ()] instanceof RowY;
|
||||
return ((RowZ) rowz).rows[other.getY() - (minSectionIndex << 4) - getChunkOffsetZ()] instanceof RowY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -293,7 +293,7 @@ public final class MemBlockSet extends BlockSet {
|
||||
|
||||
@Override
|
||||
public int getMinimumY() {
|
||||
int maxY = 15;
|
||||
int maxY = maxSectionIndex;
|
||||
int maxy = 16;
|
||||
int by = Integer.MAX_VALUE;
|
||||
for (IRow nullRowX : rows) {
|
||||
@ -357,7 +357,7 @@ public final class MemBlockSet extends BlockSet {
|
||||
}
|
||||
RowZ rowz = (RowZ) nullRowZ;
|
||||
outer:
|
||||
for (int Y = 15; Y >= maxY; Y--) {
|
||||
for (int Y = maxSectionIndex; Y >= maxY; Y--) {
|
||||
IRow nullRowY = rowz.rows[Y];
|
||||
if (!(nullRowY instanceof RowY)) {
|
||||
continue;
|
||||
@ -376,8 +376,8 @@ public final class MemBlockSet extends BlockSet {
|
||||
maxy = y + 1;
|
||||
}
|
||||
by = (Y << 4) + y;
|
||||
if (by == FaweCache.IMP.WORLD_MAX_Y) {
|
||||
return FaweCache.IMP.WORLD_MAX_Y;
|
||||
if (by == (maxSectionIndex << 4) + 15) {
|
||||
return (maxSectionIndex << 4) + 15;
|
||||
}
|
||||
break outer;
|
||||
}
|
||||
@ -582,7 +582,7 @@ public final class MemBlockSet extends BlockSet {
|
||||
if (!(nullRowY instanceof RowY)) {
|
||||
continue;
|
||||
}
|
||||
int by = Y << 4;
|
||||
int by = ((Y - minSectionIndex) << 4);
|
||||
RowY rowY = (RowY) nullRowY;
|
||||
for (int y = 0, i = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z += 4, i++) {
|
||||
@ -615,7 +615,7 @@ public final class MemBlockSet extends BlockSet {
|
||||
|
||||
@Override
|
||||
public Iterator<BlockVector3> iterator() {
|
||||
return new Iterator<BlockVector3>() {
|
||||
return new Iterator<>() {
|
||||
private int bx;
|
||||
private int by;
|
||||
private int bz;
|
||||
@ -817,10 +817,10 @@ public final class MemBlockSet extends BlockSet {
|
||||
return false;
|
||||
}
|
||||
|
||||
void set(IRow[] rows, int x, int y, int z);
|
||||
void set(IRow[] rows, int x, int y, int z, int minSectionIndex, int maxSectionIndex);
|
||||
|
||||
default boolean add(IRow[] rows, int x, int y, int z) {
|
||||
set(rows, x, y, z);
|
||||
default boolean add(IRow[] rows, int x, int y, int z, int minSectionIndex, int maxSectionIndex) {
|
||||
set(rows, x, y, z, minSectionIndex, maxSectionIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -837,10 +837,10 @@ public final class MemBlockSet extends BlockSet {
|
||||
public static final class NullRowX implements IRow {
|
||||
|
||||
@Override
|
||||
public void set(IRow[] parent, int x, int y, int z) {
|
||||
public void set(IRow[] parent, int x, int y, int z, int minSectionIndex, int maxSectionIndex) {
|
||||
IRow row = new RowX(parent.length);
|
||||
parent[x >> 4] = row;
|
||||
row.set(parent, x, y, z);
|
||||
row.set(parent, x, y, z, minSectionIndex, maxSectionIndex);
|
||||
}
|
||||
|
||||
}
|
||||
@ -848,10 +848,10 @@ public final class MemBlockSet extends BlockSet {
|
||||
public static final class NullRowZ implements IRow {
|
||||
|
||||
@Override
|
||||
public void set(IRow[] parent, int x, int y, int z) {
|
||||
IRow row = new RowZ();
|
||||
public void set(IRow[] parent, int x, int y, int z, int minSectionIndex, int maxSectionIndex) {
|
||||
IRow row = new RowZ(minSectionIndex, maxSectionIndex);
|
||||
parent[z >> 4] = row;
|
||||
row.set(parent, x, y, z);
|
||||
row.set(parent, x, y, z, minSectionIndex, maxSectionIndex);
|
||||
}
|
||||
|
||||
}
|
||||
@ -859,10 +859,10 @@ public final class MemBlockSet extends BlockSet {
|
||||
public static final class NullRowY implements IRow {
|
||||
|
||||
@Override
|
||||
public void set(IRow[] parent, int x, int y, int z) {
|
||||
public void set(IRow[] parent, int x, int y, int z, int minSectionIndex, int maxSectionIndex) {
|
||||
IRow row = new RowY();
|
||||
parent[y >> 4] = row;
|
||||
row.set(parent, x, y, z);
|
||||
row.set(parent, x, y, z, minSectionIndex, maxSectionIndex);
|
||||
}
|
||||
|
||||
}
|
||||
@ -884,13 +884,13 @@ public final class MemBlockSet extends BlockSet {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(IRow[] parent, int x, int y, int z) {
|
||||
this.rows[z >> 4].set(this.rows, x, y, z);
|
||||
public void set(IRow[] parent, int x, int y, int z, int minSectionIndex, int maxSectionIndex) {
|
||||
this.rows[z >> 4].set(this.rows, x, y, z, minSectionIndex, maxSectionIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(IRow[] parent, int x, int y, int z) {
|
||||
return this.rows[z >> 4].add(this.rows, x, y, z);
|
||||
public boolean add(IRow[] parent, int x, int y, int z, int minSectionIndex, int maxSectionIndex) {
|
||||
return this.rows[z >> 4].add(this.rows, x, y, z, minSectionIndex, maxSectionIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -909,8 +909,8 @@ public final class MemBlockSet extends BlockSet {
|
||||
|
||||
public final IRow[] rows;
|
||||
|
||||
public RowZ() {
|
||||
this.rows = new IRow[FaweCache.IMP.CHUNK_LAYERS];
|
||||
public RowZ(int minSectionIndex, int maxSectionIndex) {
|
||||
this.rows = new IRow[maxSectionIndex - minSectionIndex + 1];
|
||||
reset();
|
||||
}
|
||||
|
||||
@ -924,18 +924,19 @@ public final class MemBlockSet extends BlockSet {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(IRow[] parent, int x, int y, int z) {
|
||||
this.rows[y >> 4].set(this.rows, x, y, z);
|
||||
public void set(IRow[] parent, int x, int y, int z, int minSectionIndex, int maxSectionIndex) {
|
||||
this.rows[y >> 4].set(this.rows, x, y, z, minSectionIndex, maxSectionIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(IRow[] parent, int x, int y, int z) {
|
||||
return this.rows[y >> 4].add(this.rows, x, y, z);
|
||||
public boolean add(IRow[] parent, int x, int y, int z, int minSectionIndex, int maxSectionIndex) {
|
||||
return this.rows[y >> 4].add(this.rows, x, y, z, minSectionIndex, maxSectionIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(IRow[] parent, int x, int y, int z) {
|
||||
this.rows[y >> 4].set(this.rows, x, y, z);
|
||||
// min/amx layer does not matter here.
|
||||
this.rows[y >> 4].set(this.rows, x, y, z, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -957,9 +958,7 @@ public final class MemBlockSet extends BlockSet {
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
for (int i = 0; i < FaweCache.IMP.CHUNK_LAYERS; i++) {
|
||||
rows[i] = NULL_ROW_Y;
|
||||
}
|
||||
Arrays.fill(rows, NULL_ROW_Y);
|
||||
}
|
||||
|
||||
}
|
||||
@ -983,13 +982,13 @@ public final class MemBlockSet extends BlockSet {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(IRow[] parent, int x, int y, int z) {
|
||||
public void set(IRow[] parent, int x, int y, int z, int minSectionIndex, int maxSectionIndex) {
|
||||
int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15);
|
||||
bits[i >> 6] |= (1L << (i & 0x3F));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(IRow[] parent, int x, int y, int z) {
|
||||
public boolean add(IRow[] parent, int x, int y, int z, int minSectionIndex, int maxSectionIndex) {
|
||||
int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15);
|
||||
int offset = i >> 6;
|
||||
long value = bits[offset];
|
||||
|
@ -61,6 +61,11 @@ public interface SimpleWorld extends World {
|
||||
return getMaximumPoint().getBlockY();
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getMinY() {
|
||||
return getMinimumPoint().getBlockY();
|
||||
}
|
||||
|
||||
@Override
|
||||
default Mask createLiquidMask() {
|
||||
return new BlockMask(this).add(BlockTypes.LAVA, BlockTypes.WATER);
|
||||
|
@ -85,8 +85,8 @@ public class AsyncPlayer extends PlayerProxy {
|
||||
public boolean ascendToCeiling(int clearance, boolean alwaysGlass) {
|
||||
Location pos = getBlockLocation();
|
||||
int x = pos.getBlockX();
|
||||
int initialY = Math.max(0, pos.getBlockY());
|
||||
int y = Math.max(0, pos.getBlockY() + 2);
|
||||
int initialY = Math.max(getWorld().getMinY(), pos.getBlockY());
|
||||
int y = Math.max(getWorld().getMinY(), pos.getBlockY() + 2);
|
||||
int z = pos.getBlockZ();
|
||||
Extent world = getLocation().getExtent();
|
||||
|
||||
@ -121,15 +121,15 @@ public class AsyncPlayer extends PlayerProxy {
|
||||
public boolean ascendUpwards(int distance, boolean alwaysGlass) {
|
||||
final Location pos = getBlockLocation();
|
||||
final int x = pos.getBlockX();
|
||||
final int initialY = Math.max(0, pos.getBlockY());
|
||||
int y = Math.max(0, pos.getBlockY() + 1);
|
||||
final int initialY = Math.max(getWorld().getMinY(), pos.getBlockY());
|
||||
int y = Math.max(getWorld().getMinY(), pos.getBlockY() + 1);
|
||||
final int z = pos.getBlockZ();
|
||||
final int maxY = Math.min(getWorld().getMaxY() + 1, initialY + distance);
|
||||
final Extent world = getLocation().getExtent();
|
||||
|
||||
MutableBlockVector3 mutable = new MutableBlockVector3(x, y, z);
|
||||
|
||||
while (y <= world.getMaximumPoint().getY() + 2) {
|
||||
while (y <= world.getMaxY() + 2) {
|
||||
if (world.getBlock(mutable.mutY(y)).getBlockType().getMaterial()
|
||||
.isMovementBlocker()) {
|
||||
break; // Hit something
|
||||
|
@ -96,6 +96,11 @@ public class WorldWrapper extends AbstractWorld {
|
||||
return parent.getMaxY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
return parent.getMinY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask createLiquidMask() {
|
||||
return parent.createLiquidMask();
|
||||
|
@ -1184,6 +1184,16 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
return getBlockChangeCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector3 getMinimumPoint() {
|
||||
return getWorld().getMinimumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector3 getMaximumPoint() {
|
||||
return getWorld().getMaximumPoint();
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
public void setSize(int size) {
|
||||
this.changes = size;
|
||||
@ -1276,7 +1286,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
public <B extends BlockStateHolder<B>> int fall(final Region region, boolean fullHeight, final B replace) {
|
||||
FlatRegion flat = asFlatRegion(region);
|
||||
final int startPerformY = region.getMinimumPoint().getBlockY();
|
||||
final int startCheckY = fullHeight ? 0 : startPerformY;
|
||||
final int startCheckY = fullHeight ? getMinY() : startPerformY;
|
||||
final int endY = region.getMaximumPoint().getBlockY();
|
||||
RegionVisitor visitor = new RegionVisitor(flat, pos -> {
|
||||
int x = pos.getX();
|
||||
@ -1353,7 +1363,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
final BlockReplace replace = new BlockReplace(EditSession.this, pattern);
|
||||
|
||||
// Pick how we're going to visit blocks
|
||||
RecursiveVisitor visitor = new DirectionalVisitor(mask, replace, origin, direction, (int) (radius * 2 + 1));
|
||||
RecursiveVisitor visitor = new DirectionalVisitor(mask, replace, origin, direction, (int) (radius * 2 + 1), minY, maxY);
|
||||
|
||||
// Start at the origin
|
||||
visitor.visit(origin);
|
||||
@ -1406,8 +1416,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
Mask mask = new MaskIntersection(
|
||||
new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))),
|
||||
new BoundedHeightMask(
|
||||
Math.max(origin.getBlockY() - depth + 1, getMinimumPoint().getBlockY()),
|
||||
Math.min(getMaxY(), origin.getBlockY())
|
||||
Math.max(origin.getBlockY() - depth + 1, minY),
|
||||
Math.min(maxY, origin.getBlockY())
|
||||
),
|
||||
Masks.negate(new ExistingBlockMask(this))
|
||||
);
|
||||
@ -1417,11 +1427,11 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
|
||||
// Pick how we're going to visit blocks
|
||||
RecursiveVisitor visitor;
|
||||
//FAWE start - provide extent for preloading
|
||||
//FAWE start - provide extent for preloading, min/max y
|
||||
if (recursive) {
|
||||
visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), this);
|
||||
visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), minY, maxY, this);
|
||||
} else {
|
||||
visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1), this);
|
||||
visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1), minY, maxY, this);
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
@ -1938,7 +1948,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
//FAWE end
|
||||
}
|
||||
Mask mask = new MaskIntersection(
|
||||
new BoundedHeightMask(getWorld().getMinY(), getWorld().getMaxY()),
|
||||
new BoundedHeightMask(minY, maxY),
|
||||
new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))),
|
||||
//FAWE start
|
||||
liquidMask
|
||||
@ -1950,8 +1960,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
} else {
|
||||
replace = new BlockReplace(this, BlockTypes.AIR.getDefaultState());
|
||||
}
|
||||
//FAWE start - provide extent for preloading
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), this);
|
||||
//FAWE start - provide extent for preloading, min/max y
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), minY, maxY, this);
|
||||
//FAWE end
|
||||
|
||||
// Around the origin in a 3x3 block
|
||||
@ -1989,14 +1999,14 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
|
||||
// There are boundaries that the routine needs to stay in
|
||||
Mask mask = new MaskIntersection(
|
||||
new BoundedHeightMask(getWorld().getMinY(), Math.min(origin.getBlockY(), getWorld().getMaxY())),
|
||||
new BoundedHeightMask(minY, Math.min(origin.getBlockY(), maxY)),
|
||||
new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))),
|
||||
blockMask
|
||||
);
|
||||
|
||||
BlockReplace replace = new BlockReplace(this, fluid.getDefaultState());
|
||||
//FAWE start - provide extent for preloading
|
||||
NonRisingVisitor visitor = new NonRisingVisitor(mask, replace, Integer.MAX_VALUE, this);
|
||||
//FAWE start - provide extent for preloading, world min/maxY
|
||||
NonRisingVisitor visitor = new NonRisingVisitor(mask, replace, Integer.MAX_VALUE, minY, maxY, this);
|
||||
//FAWE end
|
||||
|
||||
// Around the origin in a 3x3 block
|
||||
@ -2411,7 +2421,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (y != 0 && (yy = py - y) >= 0) {
|
||||
if (y != 0 && (yy = py - y) >= minY) {
|
||||
this.setBlock(px + x, yy, pz + z, block);
|
||||
if (x != 0) {
|
||||
this.setBlock(px - x, yy, pz + z, block);
|
||||
@ -2506,9 +2516,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
BlockState air = BlockTypes.AIR.getDefaultState();
|
||||
BlockState water = BlockTypes.WATER.getDefaultState();
|
||||
|
||||
int centerY = Math.max(getWorld().getMinY(), Math.min(getWorld().getMaxY(), oy));
|
||||
int minY = Math.max(getWorld().getMinY(), centerY - height);
|
||||
int maxY = Math.min(getWorld().getMaxY(), centerY + height);
|
||||
int centerY = Math.max(minY, Math.min(maxY, oy));
|
||||
int minY = Math.max(this.minY, centerY - height);
|
||||
int maxY = Math.min(this.maxY, centerY + height);
|
||||
|
||||
//FAWE start - mutable
|
||||
MutableBlockVector3 mutable = new MutableBlockVector3();
|
||||
@ -2535,8 +2545,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
++affected;
|
||||
}
|
||||
} else if (id == BlockTypes.SNOW) {
|
||||
//FAWE start
|
||||
if (setBlock(mutable, air)) {
|
||||
if (y > 0) {
|
||||
if (y > getMinY()) {
|
||||
BlockState block = getBlock(mutable2);
|
||||
if (block.getStates().containsKey(snowy)) {
|
||||
if (setBlock(mutable2, block.with(snowy, false))) {
|
||||
@ -2649,9 +2660,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
|
||||
final BlockState grass = BlockTypes.GRASS_BLOCK.getDefaultState();
|
||||
|
||||
final int centerY = Math.max(getWorld().getMinY(), Math.min(getWorld().getMaxY(), oy));
|
||||
final int minY = Math.max(getWorld().getMinY(), centerY - height);
|
||||
final int maxY = Math.min(getWorld().getMaxY(), centerY + height);
|
||||
final int centerY = Math.max(minY, Math.min(maxY, oy));
|
||||
final int minY = Math.max(this.minY, centerY - height);
|
||||
final int maxY = Math.min(this.maxY, centerY + height);
|
||||
|
||||
//FAWE start - mutable
|
||||
MutableBlockVector3 mutable = new MutableBlockVector3();
|
||||
@ -2952,7 +2963,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
int zv = (int) (z.getValue() * unit.getZ() + zero2.getZ());
|
||||
|
||||
BlockState get;
|
||||
if (yv >= 0 && yv < 256) {
|
||||
if (yv >= minY && yv <= maxY) {
|
||||
get = getBlock(xv, yv, zv);
|
||||
} else {
|
||||
get = BlockTypes.AIR.getDefaultState();
|
||||
@ -3538,7 +3549,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
int xx = x + bx;
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int zz = z + bz;
|
||||
for (int y = 0; y < maxY + 1; y++) {
|
||||
for (int y = minY; y < maxY + 1; y++) {
|
||||
BaseBlock block = getFullBlock(mutable.setComponents(xx, y, zz));
|
||||
fcs.add(mutable, block, BlockTypes.AIR.getDefaultState().toBaseBlock());
|
||||
}
|
||||
@ -3561,7 +3572,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int zz = z + bz;
|
||||
mutable.mutZ(zz);
|
||||
for (int y = 0; y < maxY + 1; y++) {
|
||||
for (int y = minY; y < maxY + 1; y++) {
|
||||
mutable.mutY(y);
|
||||
boolean contains = (fe == null || fe.contains(xx, y, zz)) && region.contains(mutable);
|
||||
if (contains) {
|
||||
|
@ -211,6 +211,13 @@ public class LocalSession implements TextureHolder {
|
||||
if (defaultSelector != null) {
|
||||
this.selector = defaultSelector.createSelector();
|
||||
}
|
||||
//FAWE start
|
||||
if (worldOverride != null) {
|
||||
this.selector.setWorld(worldOverride);
|
||||
} else {
|
||||
this.selector.setWorld(currentWorld);
|
||||
}
|
||||
//FAWE end
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
|
@ -457,6 +457,7 @@ public class BrushCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.brush.stencil")
|
||||
public void stencilBrush(
|
||||
Player player,
|
||||
LocalSession session, InjectedValueAccess context,
|
||||
@Arg(desc = "Pattern")
|
||||
Pattern fill,
|
||||
@ -478,13 +479,15 @@ public class BrushCommands {
|
||||
worldEdit.checkMaxBrushRadius(radius);
|
||||
InputStream stream = getHeightmapStream(image);
|
||||
HeightBrush brush;
|
||||
int minY = player.getWorld().getMinY();
|
||||
int maxY = player.getWorld().getMaxY();
|
||||
try {
|
||||
brush = new StencilBrush(stream, rotation, yscale, onlyWhite,
|
||||
"#clipboard".equalsIgnoreCase(image)
|
||||
? session.getClipboard().getClipboard() : null
|
||||
? session.getClipboard().getClipboard() : null, minY, maxY
|
||||
);
|
||||
} catch (EmptyClipboardException ignored) {
|
||||
brush = new StencilBrush(stream, rotation, yscale, onlyWhite, null);
|
||||
brush = new StencilBrush(stream, rotation, yscale, onlyWhite, null, minY, maxY);
|
||||
}
|
||||
if (randomRotate) {
|
||||
brush.setRandomRotate(true);
|
||||
@ -710,6 +713,7 @@ public class BrushCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.brush.height")
|
||||
public void heightBrush(
|
||||
Player player,
|
||||
LocalSession session,
|
||||
@Arg(desc = "Expression", def = "5")
|
||||
Expression radius,
|
||||
@ -728,7 +732,7 @@ public class BrushCommands {
|
||||
boolean dontSmooth, InjectedValueAccess context
|
||||
)
|
||||
throws WorldEditException, FileNotFoundException {
|
||||
terrainBrush(session, radius, image, rotation, yscale, false, randomRotate, layers,
|
||||
terrainBrush(player, session, radius, image, rotation, yscale, false, randomRotate, layers,
|
||||
!dontSmooth, ScalableHeightMap.Shape.CONE, context
|
||||
);
|
||||
}
|
||||
@ -741,6 +745,7 @@ public class BrushCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.brush.height")
|
||||
public void cliffBrush(
|
||||
Player player,
|
||||
LocalSession session,
|
||||
@Arg(desc = "Expression", def = "5")
|
||||
Expression radius,
|
||||
@ -760,7 +765,7 @@ public class BrushCommands {
|
||||
boolean dontSmooth, InjectedValueAccess context
|
||||
)
|
||||
throws WorldEditException, FileNotFoundException {
|
||||
terrainBrush(session, radius, image, rotation, yscale, true, randomRotate, layers,
|
||||
terrainBrush(player, session, radius, image, rotation, yscale, true, randomRotate, layers,
|
||||
!dontSmooth, ScalableHeightMap.Shape.CYLINDER, context
|
||||
);
|
||||
}
|
||||
@ -775,6 +780,7 @@ public class BrushCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.brush.height")
|
||||
public void flattenBrush(
|
||||
Player player,
|
||||
LocalSession session,
|
||||
@Arg(desc = "Expression", def = "5")
|
||||
Expression radius,
|
||||
@ -794,12 +800,13 @@ public class BrushCommands {
|
||||
boolean dontSmooth, InjectedValueAccess context
|
||||
)
|
||||
throws WorldEditException, FileNotFoundException {
|
||||
terrainBrush(session, radius, image, rotation, yscale, true, randomRotate, layers,
|
||||
terrainBrush(player, session, radius, image, rotation, yscale, true, randomRotate, layers,
|
||||
!dontSmooth, ScalableHeightMap.Shape.CONE, context
|
||||
);
|
||||
}
|
||||
|
||||
private void terrainBrush(
|
||||
Player player,
|
||||
LocalSession session,
|
||||
Expression radius,
|
||||
String image,
|
||||
@ -816,23 +823,25 @@ public class BrushCommands {
|
||||
worldEdit.checkMaxBrushRadius(radius);
|
||||
InputStream stream = getHeightmapStream(image);
|
||||
HeightBrush brush;
|
||||
int minY = player.getWorld().getMinY();
|
||||
int maxY = player.getWorld().getMaxY();
|
||||
if (flat) {
|
||||
try {
|
||||
brush = new FlattenBrush(stream, rotation, yscale, layers, smooth,
|
||||
"#clipboard".equalsIgnoreCase(image)
|
||||
? session.getClipboard().getClipboard() : null, shape
|
||||
? session.getClipboard().getClipboard() : null, shape, minY, maxY
|
||||
);
|
||||
} catch (EmptyClipboardException ignored) {
|
||||
brush = new FlattenBrush(stream, rotation, yscale, layers, smooth, null, shape);
|
||||
brush = new FlattenBrush(stream, rotation, yscale, layers, smooth, null, shape, minY, maxY);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
brush = new HeightBrush(stream, rotation, yscale, layers, smooth,
|
||||
"#clipboard".equalsIgnoreCase(image)
|
||||
? session.getClipboard().getClipboard() : null
|
||||
? session.getClipboard().getClipboard() : null, minY, maxY
|
||||
);
|
||||
} catch (EmptyClipboardException ignored) {
|
||||
brush = new HeightBrush(stream, rotation, yscale, layers, smooth, null);
|
||||
brush = new HeightBrush(stream, rotation, yscale, layers, smooth, null, minY, maxY);
|
||||
}
|
||||
}
|
||||
if (randomRotate) {
|
||||
|
@ -635,12 +635,18 @@ public class GenerationCommands {
|
||||
@Arg(desc = "Ore vein size") @Range(from = 0, to = Integer.MAX_VALUE) int size,
|
||||
@Arg(desc = "Ore vein frequency (number of times to attempt to place ore)", def = "10") @Range(from = 0, to = Integer.MAX_VALUE) int freq,
|
||||
@Arg(desc = "Ore vein rarity (% chance each attempt is placed)", def = "100") @Range(from = 0, to = 100) int rarity,
|
||||
@Arg(desc = "Ore vein min y", def = "0") @Range(from = 0, to = 255) int minY,
|
||||
@Arg(desc = "Ore vein max y", def = "63") @Range(from = 0, to = 255) int maxY
|
||||
@Arg(desc = "Ore vein min y", def = "0") int minY,
|
||||
@Arg(desc = "Ore vein max y", def = "63") int maxY
|
||||
) throws WorldEditException {
|
||||
if (mask instanceof AbstractExtentMask) {
|
||||
((AbstractExtentMask) mask).setExtent(editSession);
|
||||
}
|
||||
checkCommandArgument(minY >= editSession.getMinY(), Caption.of("fawe.error.outside-range-lower", "miny",
|
||||
editSession.getMinY()));
|
||||
checkCommandArgument(maxY <= editSession.getMaxY(), Caption.of("fawe.error.outside-range-upper", "maxy",
|
||||
editSession.getMaxY()));
|
||||
checkCommandArgument(minY < maxY, Caption.of("fawe.error.argument-size-mismatch", "miny",
|
||||
"maxy"));
|
||||
editSession.addOre(region, mask, material, size, freq, rarity, minY, maxY);
|
||||
actor.print(Caption.of("fawe.worldedit.visitor.visitor.block", editSession.getBlockChangeCount()));
|
||||
}
|
||||
|
@ -133,8 +133,8 @@ public class HistorySubCommands {
|
||||
Location origin = player.getLocation();
|
||||
BlockVector3 bot = origin.toBlockPoint().subtract(radius, radius, radius);
|
||||
BlockVector3 top = origin.toBlockPoint().add(radius, radius, radius);
|
||||
bot = bot.clampY(0, world.getMaxY());
|
||||
top = top.clampY(0, world.getMaxY());
|
||||
bot = bot.clampY(world.getMinY(), world.getMaxY());
|
||||
top = top.clampY(world.getMinY(), world.getMaxY());
|
||||
// TODO mask the regions bot / top to the bottom and top coord in the allowedRegions
|
||||
// TODO: then mask the edit to the bot / top
|
||||
// if (allowedRegions.length != 1 || !allowedRegions[0].isGlobal()) {
|
||||
@ -196,9 +196,9 @@ public class HistorySubCommands {
|
||||
.summarize(RegionWrapper.GLOBAL(), false);
|
||||
if (summary != null) {
|
||||
rollback.setDimensions(
|
||||
BlockVector3.at(summary.minX, 0, summary.minZ),
|
||||
BlockVector3.at(summary.minX, world.getMinY(), summary.minZ),
|
||||
BlockVector3
|
||||
.at(summary.maxX, 255, summary.maxZ)
|
||||
.at(summary.maxX, world.getMaxY(), summary.maxZ)
|
||||
);
|
||||
rollback.setTime(historyFile.lastModified());
|
||||
RollbackDatabase db = DBHandler.IMP
|
||||
@ -410,8 +410,8 @@ public class HistorySubCommands {
|
||||
|
||||
BlockVector3 bot = origin.toBlockPoint().subtract(radius, radius, radius);
|
||||
BlockVector3 top = origin.toBlockPoint().add(radius, radius, radius);
|
||||
bot = bot.clampY(0, world.getMaxY());
|
||||
top = top.clampY(0, world.getMaxY());
|
||||
bot = bot.clampY(world.getMinY(), world.getMaxY());
|
||||
top = top.clampY(world.getMinY(), world.getMaxY());
|
||||
|
||||
long minTime = System.currentTimeMillis() - timeDiff;
|
||||
Iterable<Supplier<RollbackOptimizedHistory>> edits = database.getEdits(other, minTime, bot, top, false, false);
|
||||
|
@ -363,17 +363,23 @@ public class RegionCommands {
|
||||
@Selection Region region,
|
||||
@Arg(name = "pattern", desc = "The pattern of blocks to lay") Pattern patternArg
|
||||
) throws WorldEditException {
|
||||
BlockVector3 max = region.getMaximumPoint();
|
||||
int maxY = max.getBlockY();
|
||||
//FAWE start - world min/maxY
|
||||
int maxY = region.getMaximumY();
|
||||
int minY = region.getMinimumY();
|
||||
//FAWE end
|
||||
Iterable<BlockVector2> flat = Regions.asFlatRegion(region).asFlatRegion();
|
||||
Iterator<BlockVector2> iter = flat.iterator();
|
||||
int y = 0;
|
||||
//FAWE start - world min/maxY
|
||||
int y = minY;
|
||||
//FAWE end
|
||||
int affected = 0;
|
||||
while (iter.hasNext()) {
|
||||
BlockVector2 pos = iter.next();
|
||||
int x = pos.getBlockX();
|
||||
int z = pos.getBlockZ();
|
||||
y = editSession.getNearestSurfaceTerrainBlock(x, z, y, 0, maxY);
|
||||
//FAWE start - world min/maxY
|
||||
y = editSession.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY);
|
||||
//FAWE end
|
||||
editSession.setBlock(x, y, z, patternArg);
|
||||
affected++;
|
||||
}
|
||||
@ -856,6 +862,7 @@ public class RegionCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.region.flora")
|
||||
@Logging(REGION)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public int flora(
|
||||
Actor actor, EditSession editSession, @Selection Region region,
|
||||
@ -867,7 +874,7 @@ public class RegionCommands {
|
||||
FloraGenerator generator = new FloraGenerator(editSession);
|
||||
GroundFunction ground = new GroundFunction(new ExistingBlockMask(editSession), generator);
|
||||
//FAWE start - provide extent for preloading
|
||||
LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground, editSession);
|
||||
LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground);
|
||||
//FAWE end
|
||||
visitor.setMask(new NoiseFilter2D(new RandomNoise(), density));
|
||||
Operations.completeLegacy(visitor);
|
||||
|
@ -124,9 +124,9 @@ public class SelectionCommands {
|
||||
Location pos;
|
||||
//FAWE start - clamp
|
||||
if (coordinates != null) {
|
||||
pos = new Location(world, coordinates.toVector3().clampY(0, world.getMaxY()));
|
||||
pos = new Location(world, coordinates.toVector3().clampY(world.getMinY(), world.getMaxY()));
|
||||
} else if (actor instanceof Locatable) {
|
||||
pos = ((Locatable) actor).getBlockLocation().clampY(0, world.getMaxY());
|
||||
pos = ((Locatable) actor).getBlockLocation().clampY(world.getMinY(), world.getMaxY());
|
||||
//FAWE end
|
||||
} else {
|
||||
actor.print(Caption.of("worldedit.pos.console-require-coords"));
|
||||
@ -157,9 +157,9 @@ public class SelectionCommands {
|
||||
Location pos;
|
||||
if (coordinates != null) {
|
||||
//FAWE start - clamp
|
||||
pos = new Location(world, coordinates.toVector3().clampY(0, world.getMaxY()));
|
||||
pos = new Location(world, coordinates.toVector3().clampY(world.getMinY(), world.getMaxY()));
|
||||
} else if (actor instanceof Locatable) {
|
||||
pos = ((Locatable) actor).getBlockLocation().clampY(0, world.getMaxY());
|
||||
pos = ((Locatable) actor).getBlockLocation().clampY(world.getMinY(), world.getMaxY());
|
||||
//Fawe end
|
||||
} else {
|
||||
actor.print(Caption.of("worldedit.pos.console-require-coords"));
|
||||
@ -258,7 +258,7 @@ public class SelectionCommands {
|
||||
.clampY(minChunkY, maxChunkY);
|
||||
|
||||
min = minChunk.shl(CHUNK_SHIFTS, CHUNK_SHIFTS_Y, CHUNK_SHIFTS);
|
||||
max = maxChunk.shl(CHUNK_SHIFTS, CHUNK_SHIFTS_Y, CHUNK_SHIFTS).add(15, world.getMaxY(), 15);
|
||||
max = maxChunk.shl(CHUNK_SHIFTS, CHUNK_SHIFTS_Y, CHUNK_SHIFTS).add(15, 255, 15);
|
||||
|
||||
actor.print(Caption.of(
|
||||
"worldedit.chunk.selected-multiple",
|
||||
@ -286,7 +286,7 @@ public class SelectionCommands {
|
||||
}
|
||||
|
||||
min = minChunk.shl(CHUNK_SHIFTS, CHUNK_SHIFTS_Y, CHUNK_SHIFTS);
|
||||
max = min.add(15, world.getMaxY(), 15);
|
||||
max = min.add(15, 255, 15);
|
||||
|
||||
actor.print(Caption.of(
|
||||
"worldedit.chunk.selected",
|
||||
|
@ -413,8 +413,8 @@ public class UtilityCommands {
|
||||
) throws WorldEditException {
|
||||
size = Math.max(1, size);
|
||||
we.checkMaxRadius(size);
|
||||
height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1);
|
||||
|
||||
height = height != null ? Math.min((world.getMaxY() - world.getMinY() + 1), height + 1) : (world.getMaxY() - world.getMinY() + 1);
|
||||
int affected = editSession.removeAbove(session.getPlacementPosition(actor), size, height);
|
||||
actor.print(Caption.of("worldedit.removeabove.removed", TextComponent.of(affected)));
|
||||
return affected;
|
||||
@ -436,8 +436,8 @@ public class UtilityCommands {
|
||||
) throws WorldEditException {
|
||||
size = Math.max(1, size);
|
||||
we.checkMaxRadius(size);
|
||||
height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1);
|
||||
|
||||
height = height != null ? Math.min((world.getMaxY() - world.getMinY() + 1), height + 1) : (world.getMaxY() - world.getMinY() + 1);
|
||||
int affected = editSession.removeBelow(session.getPlacementPosition(actor), size, height);
|
||||
actor.print(Caption.of("worldedit.removebelow.removed", TextComponent.of(affected)));
|
||||
return affected;
|
||||
|
@ -388,7 +388,7 @@ public class BrushTool
|
||||
final int x = loc.getBlockX();
|
||||
final int z = loc.getBlockZ();
|
||||
int y;
|
||||
for (y = height; y > 0; y--) {
|
||||
for (y = height; y > editSession.getMinY(); y--) {
|
||||
BlockType block = editSession.getBlockType(x, y, z);
|
||||
if (block.getMaterial().isMovementBlocker()) {
|
||||
break;
|
||||
|
@ -87,7 +87,8 @@ public class FloodFillTool implements BlockTool {
|
||||
//FAWE start - Respect masks
|
||||
Mask mask = initialType.toMask(editSession);
|
||||
BlockReplace function = new BlockReplace(editSession, pattern);
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(mask, function, range, editSession);
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(mask, function, range, editSession.getMinY(),
|
||||
editSession.getMaxY(), editSession);
|
||||
visitor.visit(origin);
|
||||
Operations.completeLegacy(visitor);
|
||||
//FAWE end
|
||||
|
@ -86,7 +86,14 @@ public class RecursivePickaxe implements BlockTool {
|
||||
final int radius = (int) range;
|
||||
final BlockReplace replace = new BlockReplace(editSession, (BlockTypes.AIR.getDefaultState()));
|
||||
editSession.setMask(null);
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(new IdMask(editSession), replace, radius, editSession);
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(
|
||||
new IdMask(editSession),
|
||||
replace,
|
||||
radius,
|
||||
editSession.getMinY(),
|
||||
editSession.getMaxY(),
|
||||
editSession
|
||||
);
|
||||
//TODO: Fix below
|
||||
//visitor.visit(pos);
|
||||
//Operations.completeBlindly(visitor);
|
||||
|
@ -39,8 +39,8 @@ public class GravityBrush implements Brush {
|
||||
MaxChangedBlocksException {
|
||||
//FAWE start - Ours operates differently to upstream, but does the same
|
||||
double endY = position.getY() + size;
|
||||
double startPerformY = Math.max(0, position.getY() - size);
|
||||
double startCheckY = fullHeight ? 0 : startPerformY;
|
||||
double startPerformY = Math.max(editSession.getMinY(), position.getY() - size);
|
||||
double startCheckY = fullHeight ? editSession.getMinY() : startPerformY;
|
||||
for (double x = position.getX() + size; x > position.getX() - size; --x) {
|
||||
for (double z = position.getZ() + size; z > position.getZ() - size; --z) {
|
||||
double freeSpot = startCheckY;
|
||||
|
@ -69,7 +69,7 @@ public class OffsetMaskParser extends InputParser<Mask> implements AliasedParser
|
||||
submask = new ExistingBlockMask(context.requireExtent());
|
||||
}
|
||||
//FAWE start - OffsetMask > OffsetsMask
|
||||
return new OffsetMask(submask, BlockVector3.at(0, firstChar == '>' ? -1 : 1, 0));
|
||||
return new OffsetMask(submask, BlockVector3.at(0, firstChar == '>' ? -1 : 1, 0), context.getMinY(), context.getMaxY());
|
||||
//FAWE end
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.extension.factory.MaskFactory;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extension.platform.Locatable;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import org.enginehub.piston.inject.InjectedValueAccess;
|
||||
@ -50,6 +51,8 @@ public class ParserContext {
|
||||
private boolean preferringWildcard;
|
||||
//Fawe start
|
||||
private InjectedValueAccess injected;
|
||||
private int minY = Integer.MIN_VALUE;
|
||||
private int maxY = Integer.MAX_VALUE;
|
||||
//FAWE end
|
||||
|
||||
/**
|
||||
@ -270,5 +273,69 @@ public class ParserContext {
|
||||
public InjectedValueAccess getInjected() {
|
||||
return injected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to resolve the minimum Y value associated with this context or returns 0.
|
||||
* Caches both min and max y values.
|
||||
*
|
||||
* @return Minimum y value (inclusive) or 0
|
||||
*/
|
||||
public int getMinY() {
|
||||
if (minY != Integer.MIN_VALUE) {
|
||||
return minY;
|
||||
}
|
||||
|
||||
Extent extent = null;
|
||||
|
||||
if (actor instanceof Locatable) {
|
||||
extent = ((Locatable) actor).getExtent();
|
||||
} else if (world != null) {
|
||||
extent = world;
|
||||
} else if (this.extent != null) {
|
||||
extent = this.extent;
|
||||
}
|
||||
|
||||
if (extent != null) {
|
||||
minY = extent.getMinY();
|
||||
maxY = extent.getMaxY();
|
||||
} else {
|
||||
minY = 0;
|
||||
maxY = 255;
|
||||
}
|
||||
|
||||
return minY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to resolve the maximum Y value associated with this context or returns 255.
|
||||
* Caches both min and max y values.
|
||||
*
|
||||
* @return Maximum y value (inclusive) or 255
|
||||
*/
|
||||
public int getMaxY() {
|
||||
if (maxY != Integer.MAX_VALUE) {
|
||||
return maxY;
|
||||
}
|
||||
|
||||
Extent extent = null;
|
||||
|
||||
if (actor instanceof Locatable) {
|
||||
extent = ((Locatable) actor).getExtent();
|
||||
} else if (world != null) {
|
||||
extent = world;
|
||||
} else if (this.extent != null) {
|
||||
extent = this.extent;
|
||||
}
|
||||
|
||||
if (extent != null) {
|
||||
minY = extent.getMinY();
|
||||
maxY = extent.getMaxY();
|
||||
} else {
|
||||
minY = 0;
|
||||
maxY = 255;
|
||||
}
|
||||
|
||||
return maxY;
|
||||
}
|
||||
//FAWE end
|
||||
}
|
||||
|
@ -202,6 +202,11 @@ public class AbstractDelegateExtent implements Extent {
|
||||
return extent.getMaxY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
return extent.getMinY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean relight(int x, int y, int z) {
|
||||
return extent.relight(x, y, z);
|
||||
@ -317,7 +322,7 @@ public class AbstractDelegateExtent implements Extent {
|
||||
|
||||
@Override
|
||||
public <T extends BlockStateHolder<T>> boolean setBlock(
|
||||
int x, @Range(from = 0, to = 255) int y,
|
||||
int x, int y,
|
||||
int z, T block
|
||||
) throws WorldEditException {
|
||||
return extent.setBlock(x, y, z, block);
|
||||
|
@ -200,9 +200,16 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
- TODO: actually optimize these
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the highest solid 'terrain' block.
|
||||
*
|
||||
* @param x the X coordinate
|
||||
* @param z the Z coordinate
|
||||
* @param minY minimal height
|
||||
* @param maxY maximal height
|
||||
* @return height of highest block found or 'minY'
|
||||
*/
|
||||
default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY) {
|
||||
maxY = Math.min(maxY, Math.max(0, maxY));
|
||||
minY = Math.max(0, minY);
|
||||
for (int y = maxY; y >= minY; --y) {
|
||||
BlockState block = getBlock(x, y, z);
|
||||
if (block.getBlockType().getMaterial().isMovementBlocker()) {
|
||||
@ -212,9 +219,19 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
return minY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the highest solid 'terrain' block.
|
||||
*
|
||||
* @param x the X coordinate
|
||||
* @param z the Z coordinate
|
||||
* @param minY minimal height
|
||||
* @param maxY maximal height
|
||||
* @param filter a mask of blocks to consider, or null to consider any solid (movement-blocking) block
|
||||
* @return height of highest block found or 'minY'
|
||||
*/
|
||||
default int getHighestTerrainBlock(final int x, final int z, int minY, int maxY, Mask filter) {
|
||||
maxY = Math.min(maxY, Math.max(0, maxY));
|
||||
minY = Math.max(0, minY);
|
||||
maxY = Math.min(maxY, getMaxY());
|
||||
minY = Math.max(getMinY(), minY);
|
||||
|
||||
MutableBlockVector3 mutable = new MutableBlockVector3();
|
||||
|
||||
@ -226,6 +243,18 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
return minY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nearest surface layer (up/down from start)
|
||||
* <p>
|
||||
* TODO: Someone understand this..?
|
||||
*
|
||||
* @param x x to search from
|
||||
* @param z y to search from
|
||||
* @param y z to search from
|
||||
* @param minY min y to search (inclusive)
|
||||
* @param maxY max y to search (inclusive)
|
||||
* @return nearest surface layer
|
||||
*/
|
||||
default int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
|
||||
int clearanceAbove = maxY - y;
|
||||
int clearanceBelow = y - minY;
|
||||
@ -255,7 +284,7 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
for (int layer = y - clearance - 1; layer >= minY; layer--) {
|
||||
block = getBlock(x, layer, z);
|
||||
if (block.getBlockType().getMaterial().isMovementBlocker() == state) {
|
||||
return ((layer + offset) << 4) + 0;
|
||||
return (layer + offset) << 4;
|
||||
}
|
||||
data1 = PropertyGroup.LEVEL.get(block);
|
||||
}
|
||||
@ -272,18 +301,20 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
return (state ? minY : maxY) << 4;
|
||||
}
|
||||
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) {
|
||||
return getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, minY, maxY, ignoreAir);
|
||||
}
|
||||
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
|
||||
return getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, minY, maxY);
|
||||
}
|
||||
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) {
|
||||
return getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets y value for the nearest block that is considered the surface of the terrain (cave roof/floor, mountain surface,
|
||||
* etc) where the block conforms to a given mask. Searches in the x,z column given.
|
||||
*
|
||||
* @param x column x
|
||||
* @param z column z
|
||||
* @param y start y
|
||||
* @param minY minimum y height to consider. Inclusive.
|
||||
* @param maxY maximum y height to consider. Inclusive.
|
||||
* @param failedMin if nothing found, the minimum y value to return if returning min
|
||||
* @param failedMax if nothing found, the maximum y value to return if returning max
|
||||
* @param mask mask to test blocks against
|
||||
* @return The y value of the nearest terrain block
|
||||
*/
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) {
|
||||
y = Math.max(minY, Math.min(maxY, y));
|
||||
int clearanceAbove = maxY - y;
|
||||
@ -320,6 +351,68 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
return state ? failedMin : failedMax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets y value for the nearest block that is considered the surface of the terrain (cave roof/floor, mountain surface,
|
||||
* etc). Searches in the x,z column given.
|
||||
*
|
||||
* @param x column x
|
||||
* @param z column z
|
||||
* @param y start y
|
||||
* @param minY minimum y height to consider. Inclusive.
|
||||
* @param maxY maximum y height to consider. Inclusive.
|
||||
* @param ignoreAir if air at the final value if no block found should be considered for return, else return -1
|
||||
* @return The y value of the nearest terrain block
|
||||
*/
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) {
|
||||
return getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, minY, maxY, ignoreAir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets y value for the nearest block that is considered the surface of the terrain (cave roof/floor, mountain surface,
|
||||
* etc). Searches in the x,z column given.
|
||||
*
|
||||
* @param x column x
|
||||
* @param z column z
|
||||
* @param y start y
|
||||
* @param minY minimum y height to consider. Inclusive.
|
||||
* @param maxY maximum y height to consider. Inclusive.
|
||||
* @return The y value of the nearest terrain block
|
||||
*/
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
|
||||
return getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, minY, maxY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets y value for the nearest block that is considered the surface of the terrain (cave roof/floor, mountain surface,
|
||||
* etc). Searches in the x,z column given.
|
||||
*
|
||||
* @param x column x
|
||||
* @param z column z
|
||||
* @param y start y
|
||||
* @param minY minimum y height to consider. Inclusive.
|
||||
* @param maxY maximum y height to consider. Inclusive.
|
||||
* @param failedMin if nothing found, the minimum y value to return if returning min
|
||||
* @param failedMax if nothing found, the maximum y value to return if returning max
|
||||
* @return The y value of the nearest terrain block
|
||||
*/
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) {
|
||||
return getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets y value for the nearest block that is considered the surface of the terrain (cave roof/floor, mountain surface,
|
||||
* etc). Searches in the x,z column given.
|
||||
*
|
||||
* @param x column x
|
||||
* @param z column z
|
||||
* @param y start y
|
||||
* @param minY minimum y height to consider. Inclusive.
|
||||
* @param maxY maximum y height to consider. Inclusive.
|
||||
* @param failedMin if nothing found, the minimum y value to return if returning min
|
||||
* @param failedMax if nothing found, the maximum y value to return if returning max
|
||||
* @param ignoreAir if air at the final value if no block found should be considered for return, else return -1
|
||||
* @return The y value of the nearest terrain block
|
||||
*/
|
||||
default int getNearestSurfaceTerrainBlock(
|
||||
int x,
|
||||
int z,
|
||||
@ -367,7 +460,7 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
}
|
||||
}
|
||||
int result = state ? failedMin : failedMax;
|
||||
if (result > 0 && !ignoreAir) {
|
||||
if (result > minY && !ignoreAir) {
|
||||
block = getBlock(x, result, z);
|
||||
return block.getBlockType().getMaterial().isAir() ? -1 : result;
|
||||
}
|
||||
@ -444,12 +537,13 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
spawnResource(region, new OreGen(this, mask, material, size, minY, maxY), rarity, frequency);
|
||||
}
|
||||
|
||||
//TODO: probably update these for 1.18 etc.
|
||||
default void addOres(Region region, Mask mask) throws WorldEditException {
|
||||
addOre(region, mask, BlockTypes.DIRT.getDefaultState(), 33, 10, 100, 0, 255);
|
||||
addOre(region, mask, BlockTypes.GRAVEL.getDefaultState(), 33, 8, 100, 0, 255);
|
||||
addOre(region, mask, BlockTypes.ANDESITE.getDefaultState(), 33, 10, 100, 0, 79);
|
||||
addOre(region, mask, BlockTypes.DIORITE.getDefaultState(), 33, 10, 100, 0, 79);
|
||||
addOre(region, mask, BlockTypes.GRANITE.getDefaultState(), 33, 10, 100, 0, 79);
|
||||
addOre(region, mask, BlockTypes.DIRT.getDefaultState(), 33, 10, 100, getMinY(), getMaxY());
|
||||
addOre(region, mask, BlockTypes.GRAVEL.getDefaultState(), 33, 8, 100, getMinY(), getMaxY());
|
||||
addOre(region, mask, BlockTypes.ANDESITE.getDefaultState(), 33, 10, 100, getMinY(), 79);
|
||||
addOre(region, mask, BlockTypes.DIORITE.getDefaultState(), 33, 10, 100, getMinY(), 79);
|
||||
addOre(region, mask, BlockTypes.GRANITE.getDefaultState(), 33, 10, 100, getMinY(), 79);
|
||||
addOre(region, mask, BlockTypes.COAL_ORE.getDefaultState(), 17, 20, 100, 0, 127);
|
||||
addOre(region, mask, BlockTypes.IRON_ORE.getDefaultState(), 9, 20, 100, 0, 63);
|
||||
addOre(region, mask, BlockTypes.GOLD_ORE.getDefaultState(), 9, 2, 100, 0, 31);
|
||||
@ -556,11 +650,11 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
}
|
||||
|
||||
default int getMinY() {
|
||||
return 0;
|
||||
return getMinimumPoint().getY();
|
||||
}
|
||||
|
||||
default int getMaxY() {
|
||||
return 255;
|
||||
return getMaximumPoint().getY();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -347,7 +347,7 @@ public interface Clipboard extends Extent, Iterable<BlockVector3>, Closeable {
|
||||
if (!pasteAir && block.getBlockType().getMaterial().isAir()) {
|
||||
continue;
|
||||
}
|
||||
if (pos.getY() < 0) {
|
||||
if (pos.getY() < extent.getMinY()) {
|
||||
throw new RuntimeException("Y-Position cannot be less than 0!");
|
||||
}
|
||||
extent.setBlock(xx, yy, zz, block);
|
||||
|
@ -31,6 +31,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
*/
|
||||
public class OffsetMask extends AbstractMask {
|
||||
|
||||
//FAWE start - ignore resultant position outside world height range
|
||||
private final int minY;
|
||||
private final int maxY;
|
||||
//FAWE end
|
||||
private Mask mask;
|
||||
private BlockVector3 offset;
|
||||
|
||||
@ -39,12 +43,30 @@ public class OffsetMask extends AbstractMask {
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param offset the offset
|
||||
* @deprecated use {@link OffsetMask#OffsetMask(Mask, BlockVector3, int, int)}
|
||||
*/
|
||||
@Deprecated
|
||||
public OffsetMask(Mask mask, BlockVector3 offset) {
|
||||
this(mask, offset, 0, 255);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param offset the offset
|
||||
* @param minY minimum allowable y value to be set. Inclusive.
|
||||
* @param maxY maximum allowable y value to be set. Inclusive.
|
||||
*/
|
||||
//FAWE start - ignore resultant position outside world height range
|
||||
public OffsetMask(Mask mask, BlockVector3 offset, int minY, int maxY) {
|
||||
checkNotNull(mask);
|
||||
checkNotNull(offset);
|
||||
this.mask = mask;
|
||||
this.offset = offset;
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
//FAWE end
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,11 +109,13 @@ public class OffsetMask extends AbstractMask {
|
||||
|
||||
@Override
|
||||
public boolean test(BlockVector3 vector) {
|
||||
//FAWE start - ignore resultant position outside world height range
|
||||
BlockVector3 testPos = vector.add(offset);
|
||||
if (testPos.getBlockY() < 0 || testPos.getBlockY() > 255) {
|
||||
if (testPos.getBlockY() < minY || testPos.getBlockY() > maxY) {
|
||||
return false;
|
||||
}
|
||||
return getMask().test(vector.add(offset));
|
||||
return getMask().test(testPos);
|
||||
//FAWE end
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -108,7 +132,7 @@ public class OffsetMask extends AbstractMask {
|
||||
//FAWE start
|
||||
@Override
|
||||
public Mask copy() {
|
||||
return new OffsetMask(mask.copy(), offset.toImmutable());
|
||||
return new OffsetMask(mask.copy(), offset.toImmutable(), minY, maxY);
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user