diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/lighting/HeightMapType.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/lighting/HeightMapType.java index 0ff367285..71c592b13 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/lighting/HeightMapType.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/lighting/HeightMapType.java @@ -1,5 +1,37 @@ package com.boydti.fawe.beta.implementation.lighting; +import com.sk89q.worldedit.world.block.BlockCategories; +import com.sk89q.worldedit.world.block.BlockState; + public enum HeightMapType { - MOTION_BLOCKING, MOTION_BLOCKING_NO_LEAVES, OCEAN_FLOOR, WORLD_SURFACE + MOTION_BLOCKING { + @Override + public boolean blocks(BlockState state) { + return state.getMaterial().isSolid() || state.getMaterial().isLiquid(); + } + }, + MOTION_BLOCKING_NO_LEAVES { + @Override + public boolean blocks(BlockState state) { + return (state.getMaterial().isSolid() || state.getMaterial().isLiquid()) && !HeightMapType.isLeaf(state); + } + }, + OCEAN_FLOOR { + @Override + public boolean blocks(BlockState state) { + return state.getMaterial().isSolid(); + } + }, + WORLD_SURFACE { + @Override + public boolean blocks(BlockState state) { + return !state.isAir(); + } + }; + + private static boolean isLeaf(BlockState state) { + return BlockCategories.LEAVES.contains(state); + } + + public abstract boolean blocks(BlockState state); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/processors/HeightmapProcessor.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/processors/HeightmapProcessor.java new file mode 100644 index 000000000..e5941511b --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/processors/HeightmapProcessor.java @@ -0,0 +1,91 @@ +package com.boydti.fawe.beta.implementation.processors; + +import com.boydti.fawe.beta.IBatchProcessor; +import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IChunkGet; +import com.boydti.fawe.beta.IChunkSet; +import com.boydti.fawe.beta.implementation.lighting.HeightMapType; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BlockState; +import org.jetbrains.annotations.Nullable; + +import java.util.BitSet; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; + +public class HeightmapProcessor implements IBatchProcessor { + private static final HeightMapType[] types = HeightMapType.values(); + + private final World world; + + public HeightmapProcessor(World world) { + this.world = world; + } + + @Override + public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) { + int max = world.getMaxY(); + int min = world.getMinY(); + int[][] heightmaps = new int[types.length][256]; + BitSet[] bitSets = new BitSet[types.length]; + for (int i = 0; i < bitSets.length; i++) { + bitSets[i] = new BitSet(256); + } + boolean[] skip = new boolean[types.length]; + yLoop: + for (int y = max; y >= min; y--) { + if (!(set.hasSection(y >> 4) || get.hasSection(y >> 4))) { + y -= 16; + continue; + } + for (int z = 0; z < 16; z++) { + for (int x = 0; x < 16; x++) { + BlockState block; + if (set.hasSection(y >> 4)) { + block = set.getBlock(x, y, z); + } else { + block = get.getBlock(x, y, z); + } + for (int i = 0; i < types.length; i++) { + if (skip[i]) continue; + HeightMapType type = types[i]; + int index = (z << 4) | x; + if (heightmaps[i][index] == 0 && type.blocks(block)) { + heightmaps[i][index] = y + 1; + bitSets[i].set(index); + } + } + } + } + for (int i = 0; i < bitSets.length; i++) { + if (bitSets[i].cardinality() == 256) { + skip[i] = true; + } + } + for (boolean skipIt : skip) { + if (!skipIt) continue yLoop; + } + break; + } + for (int i = 0; i < types.length; i++) { + set.setHeightMap(types[i], heightmaps[i]); + } + return set; + } + + @Override + public Future postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) { + return CompletableFuture.completedFuture(set); + } + + @Override + public @Nullable Extent construct(Extent child) { + throw new UnsupportedOperationException("Processing only"); + } + + @Override + public ProcessorScope getScope() { + return ProcessorScope.READING_SET_BLOCKS; + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java b/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java index 670f7d84b..555816522 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/EditSessionBuilder.java @@ -4,10 +4,10 @@ import com.boydti.fawe.Fawe; import com.boydti.fawe.FaweCache; import com.boydti.fawe.beta.IQueueChunk; import com.boydti.fawe.beta.IQueueExtent; -import com.boydti.fawe.beta.implementation.lighting.NMSRelighter; import com.boydti.fawe.beta.implementation.lighting.NullRelighter; import com.boydti.fawe.beta.implementation.lighting.RelightProcessor; import com.boydti.fawe.beta.implementation.lighting.Relighter; +import com.boydti.fawe.beta.implementation.processors.HeightmapProcessor; import com.boydti.fawe.beta.implementation.processors.LimitExtent; import com.boydti.fawe.beta.implementation.queue.ParallelQueueExtent; import com.boydti.fawe.config.Caption; @@ -35,7 +35,6 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.extent.EditSessionEvent; import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.internal.util.LogManagerCompat; @@ -43,14 +42,13 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Identifiable; import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.world.World; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; +import javax.annotation.Nullable; import java.util.Locale; import java.util.UUID; -import javax.annotation.Nullable; import static com.google.common.base.Preconditions.checkNotNull; @@ -413,6 +411,10 @@ public class EditSessionBuilder { } else { relighter = NullRelighter.INSTANCE; } + // TODO dirty workaround, NMSRelighter and HeightmapProcessor don't work well together + if (Settings.IMP.LIGHTING.MODE == 0 || relighter.getClass().getSimpleName().startsWith("Tuinity")) { + extent.addProcessor(new HeightmapProcessor(world)); + } if (limit != null && !limit.isUnlimited() && regionExtent != null) { this.extent = new LimitExtent(regionExtent, limit); } else if (limit != null && !limit.isUnlimited()) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java index 1789a4789..29980fd82 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java @@ -123,7 +123,9 @@ public final class BlockCategories { public static BlockCategory get(String id) { BlockCategory entry = BlockCategory.REGISTRY.get(id); if (entry == null) { - return new BlockCategory(id); + BlockCategory blockCategory = new BlockCategory(id); + blockCategory.load(); + return blockCategory; } return entry; }