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