merge 1.16

This commit is contained in:
Aurora 2020-07-01 14:46:25 +02:00
commit b96d45e4e6
No known key found for this signature in database
GPG Key ID: 89839F67B53656AD
86 changed files with 2816 additions and 741 deletions

View File

@ -17,7 +17,7 @@ FAWE is a fork of WorldEdit that has huge speed and memory improvements and cons
## Downloads ## Downloads
### 1.13+ ### 1.13+
* [Download](https://intellectualsites.github.io/download/fawe.html) * [Download](https://intellectualsites.github.io/download/fawe.html)
* [Jenkins](https://ci.athion.net/job/FastAsyncWorldEdit-1.15/) * [Jenkins](https://ci.athion.net/job/FastAsyncWorldEdit-1.16/)
### < 1.12.2 ### < 1.12.2
* [Download](https://intellectualsites.github.io/download/fawe.html) * [Download](https://intellectualsites.github.io/download/fawe.html)
@ -35,7 +35,7 @@ $ gradlew setupDecompWorkspace
$ gradlew build $ gradlew build
``` ```
The jar is located in `worldedit-bukkit/build/libs/FastAsyncWorldEdit-1.15-###.jar` The jar is located in `worldedit-bukkit/build/libs/FastAsyncWorldEdit-1.16-###.jar`
## Contributing ## Contributing
Have an idea for an optimization, or a cool feature? Have an idea for an optimization, or a cool feature?

View File

@ -15,7 +15,7 @@ logger.lifecycle("""
******************************************* *******************************************
""") """)
//TODO FIX THIS WHEN I FEEL LIKE IT //TODO FIX THIS WHEN I FEEL LIKE IT
var rootVersion = "1.15" var rootVersion = "1.16"
var revision: String = "" var revision: String = ""
var buildNumber = "" var buildNumber = ""
var date: String = "" var date: String = ""

View File

@ -68,6 +68,6 @@
</module> </module>
<!-- Validate that command annotations are formatted correctly --> <!-- Validate that command annotations are formatted correctly -->
<module name="RegexpMultiline"> <module name="RegexpMultiline">
<property name="format" value="^( +)@(Arg|Switch|Command)\(.*?\n\1 {5,}"/> <property name="format" value="^( +)@(Arg|Switch|Command)\(.*?\r?\n\1 {5,}"/>
</module> </module>
</module> </module>

View File

@ -41,12 +41,13 @@ dependencies {
"compile"("org.spigotmcv1_14_r1:spigotmcv1_14_r1:1_14_r1") "compile"("org.spigotmcv1_14_r1:spigotmcv1_14_r1:1_14_r1")
"compile"("org.spigotmcv1_15_r1:spigotmcv1_15_r1:1_15_r1") "compile"("org.spigotmcv1_15_r1:spigotmcv1_15_r1:1_15_r1")
"compile"("it.unimi.dsi:fastutil:8.2.1") "compile"("it.unimi.dsi:fastutil:8.2.1")
"api"("com.destroystokyo.paper:paper-api:1.15.2-R0.1-SNAPSHOT") { "api"("com.destroystokyo.paper:paper-api:1.16.1-R0.1-SNAPSHOT") {
exclude("junit", "junit") exclude("junit", "junit")
isTransitive = false isTransitive = false
} }
"compileOnly"("org.spigotmc:spigot:1.14.4-R0.1-SNAPSHOT") "compileOnly"("org.spigotmc:spigot:1.14.4-R0.1-SNAPSHOT")
"compileOnly"("org.spigotmc:spigot:1.15.2-R0.1-SNAPSHOT") "compileOnly"("org.spigotmc:spigot:1.15.2-R0.1-SNAPSHOT")
"compileOnly"("org.spigotmc:spigot:1.16.1-R0.1-SNAPSHOT")
"implementation"("io.papermc:paperlib:1.0.2") "implementation"("io.papermc:paperlib:1.0.2")
"compileOnly"("com.sk89q:dummypermscompat:1.10") "compileOnly"("com.sk89q:dummypermscompat:1.10")
"implementation"("org.apache.logging.log4j:log4j-slf4j-impl:2.8.1") "implementation"("org.apache.logging.log4j:log4j-slf4j-impl:2.8.1")

View File

@ -58,6 +58,7 @@ public class FaweBukkit implements IFawe, Listener {
private boolean listeningImages; private boolean listeningImages;
private BukkitImageListener imageListener; private BukkitImageListener imageListener;
private CFIPacketListener packetListener; private CFIPacketListener packetListener;
private final boolean chunksStretched;
public VaultUtil getVault() { public VaultUtil getVault() {
return this.vault; return this.vault;
@ -99,6 +100,8 @@ public class FaweBukkit implements IFawe, Listener {
// The tick limiter // The tick limiter
new ChunkListener_9(); new ChunkListener_9();
}); });
chunksStretched = Integer.parseInt(Bukkit.getMinecraftVersion().split("\\.")[1]) >= 16;
} }
@Override // Please don't delete this again, it's WIP @Override // Please don't delete this again, it's WIP
@ -302,6 +305,11 @@ public class FaweBukkit implements IFawe, Listener {
return null; return null;
} }
@Override
public boolean isChunksStretched() {
return chunksStretched;
}
private void setupPlotSquared() { private void setupPlotSquared() {
Plugin plotSquared = this.plugin.getServer().getPluginManager().getPlugin("PlotSquared"); Plugin plotSquared = this.plugin.getServer().getPluginManager().getPlugin("PlotSquared");
if (plotSquared == null) if (plotSquared == null)

View File

@ -56,7 +56,7 @@ import net.minecraft.server.v1_14_R1.Entity;
import net.minecraft.server.v1_14_R1.EntityTypes; import net.minecraft.server.v1_14_R1.EntityTypes;
import net.minecraft.server.v1_14_R1.EnumSkyBlock; import net.minecraft.server.v1_14_R1.EnumSkyBlock;
import net.minecraft.server.v1_14_R1.IBlockData; import net.minecraft.server.v1_14_R1.IBlockData;
import net.minecraft.server.v1_14_R1.LightEngineThreaded; import net.minecraft.server.v1_14_R1.LightEngine;
import net.minecraft.server.v1_14_R1.NBTTagCompound; import net.minecraft.server.v1_14_R1.NBTTagCompound;
import net.minecraft.server.v1_14_R1.NBTTagInt; import net.minecraft.server.v1_14_R1.NBTTagInt;
import net.minecraft.server.v1_14_R1.NibbleArray; import net.minecraft.server.v1_14_R1.NibbleArray;
@ -69,8 +69,13 @@ import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BukkitGetBlocks_1_14 extends CharGetBlocks { public class BukkitGetBlocks_1_14 extends CharGetBlocks {
private static final Logger log = LoggerFactory.getLogger(BukkitGetBlocks_1_14.class);
public ChunkSection[] sections; public ChunkSection[] sections;
public Chunk nmsChunk; public Chunk nmsChunk;
public WorldServer world; public WorldServer world;
@ -129,7 +134,17 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
int layer = y >> 4; int layer = y >> 4;
if (skyLight[layer] == null) { if (skyLight[layer] == null) {
//getDataLayerData //getDataLayerData
skyLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(SectionPosition.a(nmsChunk.getPos(), layer)); SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), layer);
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPosition);
// If the server hasn't generated the section's NibbleArray yet, it will be null
if (nibbleArray == null) {
byte[] a = new byte[2048];
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
Arrays.fill(a, (byte) 15);
nibbleArray = new NibbleArray(a);
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibbleArray);
}
skyLight[layer] = nibbleArray;
} }
long l = BlockPosition.a(x, y, z); long l = BlockPosition.a(x, y, z);
return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l))); return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
@ -140,7 +155,17 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
int layer = y >> 4; int layer = y >> 4;
if (blockLight[layer] == null) { if (blockLight[layer] == null) {
//getDataLayerData //getDataLayerData
blockLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(SectionPosition.a(nmsChunk.getPos(), layer)); SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), layer);
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
// If the server hasn't generated the section's NibbleArray yet, it will be null
if (nibbleArray == null) {
byte[] a = new byte[2048];
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
Arrays.fill(a, (byte) 15);
nibbleArray = new NibbleArray(a);
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.BLOCK, sectionPosition, nibbleArray);
}
blockLight[layer] = nibbleArray;
} }
long l = BlockPosition.a(x, y, z); long l = BlockPosition.a(x, y, z);
return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l))); return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
@ -299,7 +324,7 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
} else { } else {
existingSection = sections[layer]; existingSection = sections[layer];
if (existingSection == null) { if (existingSection == null) {
System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); log.error("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer);
continue; continue;
} }
} }
@ -326,7 +351,7 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
} }
newSection = BukkitAdapter_1_14.newChunkSection(layer, this::load, setArr, fastmode); newSection = BukkitAdapter_1_14.newChunkSection(layer, this::load, setArr, fastmode);
if (!BukkitAdapter_1_14.setSectionAtomic(sections, existingSection, newSection, layer)) { if (!BukkitAdapter_1_14.setSectionAtomic(sections, existingSection, newSection, layer)) {
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); log.error("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
continue; continue;
} else { } else {
updateGet(this, nmsChunk, sections, newSection, setArr, layer); updateGet(this, nmsChunk, sections, newSection, setArr, layer);
@ -667,9 +692,13 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
if (light[Y] == null) { if (light[Y] == null) {
continue; continue;
} }
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(SectionPosition.a(nmsChunk.getPos(), Y)); SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), Y);
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(sectionPosition);
if (nibble == null) { if (nibble == null) {
continue; byte[] a = new byte[2048];
Arrays.fill(a, skyBlock == EnumSkyBlock.SKY ? (byte) 15 : (byte) 0);
nibble = new NibbleArray(a);
((LightEngine) world.getChunkProvider().getLightEngine()).a(skyBlock, sectionPosition, nibble);
} }
synchronized (nibble) { synchronized (nibble) {
for (int i = 0; i < 4096; i++) { for (int i = 0; i < 4096; i++) {

View File

@ -0,0 +1,176 @@
package com.boydti.fawe.bukkit.adapter.mc1_14;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_14_R4;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import net.minecraft.server.v1_14_R1.Block;
import net.minecraft.server.v1_14_R1.BlockPosition;
import net.minecraft.server.v1_14_R1.Chunk;
import net.minecraft.server.v1_14_R1.ChunkProviderServer;
import net.minecraft.server.v1_14_R1.EnumDirection;
import net.minecraft.server.v1_14_R1.IBlockData;
import net.minecraft.server.v1_14_R1.NBTBase;
import net.minecraft.server.v1_14_R1.NBTTagCompound;
import net.minecraft.server.v1_14_R1.PlayerChunk;
import net.minecraft.server.v1_14_R1.TileEntity;
import net.minecraft.server.v1_14_R1.World;
import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Objects;
public class FAWEWorldNativeAccess_1_14 implements WorldNativeAccess<Chunk, IBlockData, BlockPosition> {
private static final int UPDATE = 1, NOTIFY = 2;
private final FAWE_Spigot_v1_14_R4 adapter;
private final WeakReference<World> world;
private SideEffectSet sideEffectSet;
public FAWEWorldNativeAccess_1_14(FAWE_Spigot_v1_14_R4 adapter, WeakReference<World> world) {
this.adapter = adapter;
this.world = world;
}
private World getWorld() {
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
}
@Override
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
this.sideEffectSet = sideEffectSet;
}
@Override
public Chunk getChunk(int x, int z) {
return getWorld().getChunkAt(x, z);
}
@Override
public IBlockData toNative(com.sk89q.worldedit.world.block.BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.getByCombinedId(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
}
@Override
public IBlockData getBlockState(Chunk chunk, BlockPosition position) {
return chunk.getType(position);
}
@Nullable
@Override
public IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
return chunk.setType(position, state, false);
}
@Override
public IBlockData getValidBlockForPosition(IBlockData block, BlockPosition position) {
return Block.b(block, getWorld(), position);
}
@Override
public BlockPosition getPosition(int x, int y, int z) {
return new BlockPosition(x, y, z);
}
@Override
public void updateLightingForBlock(BlockPosition position) {
getWorld().getChunkProvider().getLightEngine().a(position);
}
@Override
public boolean updateTileEntity(BlockPosition position, CompoundTag tag) {
// We will assume that the tile entity was created for us,
// though we do not do this on the other versions
TileEntity tileEntity = getWorld().getTileEntity(position);
if (tileEntity == null) {
return false;
}
NBTBase nativeTag = adapter.fromNative(tag);
tileEntity.load((NBTTagCompound) nativeTag);
return true;
}
@Override
public void notifyBlockUpdate(BlockPosition position, IBlockData oldState, IBlockData newState) {
getWorld().notify(position, oldState, newState, UPDATE | NOTIFY);
}
@Override
public boolean isChunkTicking(Chunk chunk) {
return chunk.getState().isAtLeast(PlayerChunk.State.TICKING);
}
@Override
public void markBlockChanged(BlockPosition position) {
((ChunkProviderServer) getWorld().getChunkProvider()).flagDirty(position);
}
private static final EnumDirection[] NEIGHBOUR_ORDER = {
EnumDirection.WEST, EnumDirection.EAST,
EnumDirection.DOWN, EnumDirection.UP,
EnumDirection.NORTH, EnumDirection.SOUTH
};
@Override
public void notifyNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState) {
World world = getWorld();
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
world.update(pos, oldState.getBlock());
} else {
// When we don't want events, manually run the physics without them.
// Un-nest neighbour updating
for (EnumDirection direction : NEIGHBOUR_ORDER) {
BlockPosition shifted = pos.shift(direction);
world.getType(shifted).doPhysics(world, shifted, oldState.getBlock(), pos, false);
}
}
if (newState.isComplexRedstone()) {
world.updateAdjacentComparators(pos, newState.getBlock());
}
}
@Override
public void updateNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState, int recursionLimit) {
World world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.b(world, pos, NOTIFY);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld();
if (craftWorld != null) {
BlockPhysicsEvent event = new BlockPhysicsEvent(
craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()),
CraftBlockData.fromData(newState));
world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
}
}
newState.a(world, pos, NOTIFY);
newState.b(world, pos, NOTIFY);
}
@Override
public void onBlockStateChange(BlockPosition pos, IBlockData oldState, IBlockData newState) {
getWorld().a(pos, oldState, newState);
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException {
return this.adapter.setBlock(this.getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4).bukkitChunk, position.getBlockX(), position.getBlockY(), position.getBlockZ(), block, sideEffectSet.shouldApply(SideEffect.LIGHTING));
}
}

View File

@ -40,6 +40,7 @@ import net.minecraft.server.v1_15_R1.Entity;
import net.minecraft.server.v1_15_R1.EntityTypes; import net.minecraft.server.v1_15_R1.EntityTypes;
import net.minecraft.server.v1_15_R1.EnumSkyBlock; import net.minecraft.server.v1_15_R1.EnumSkyBlock;
import net.minecraft.server.v1_15_R1.IBlockData; import net.minecraft.server.v1_15_R1.IBlockData;
import net.minecraft.server.v1_15_R1.LightEngine;
import net.minecraft.server.v1_15_R1.NBTTagCompound; import net.minecraft.server.v1_15_R1.NBTTagCompound;
import net.minecraft.server.v1_15_R1.NBTTagInt; import net.minecraft.server.v1_15_R1.NBTTagInt;
import net.minecraft.server.v1_15_R1.NibbleArray; import net.minecraft.server.v1_15_R1.NibbleArray;
@ -140,7 +141,17 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
public int getSkyLight(int x, int y, int z) { public int getSkyLight(int x, int y, int z) {
int layer = y >> 4; int layer = y >> 4;
if (skyLight[layer] == null) { if (skyLight[layer] == null) {
skyLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(SectionPosition.a(nmsChunk.getPos(), layer)); SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), layer);
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPosition);
// If the server hasn't generated the section's NibbleArray yet, it will be null
if (nibbleArray == null) {
byte[] a = new byte[2048];
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
Arrays.fill(a, (byte) 15);
nibbleArray = new NibbleArray(a);
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibbleArray);
}
skyLight[layer] = nibbleArray;
} }
long l = BlockPosition.a(x, y, z); long l = BlockPosition.a(x, y, z);
return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l))); return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
@ -150,7 +161,17 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
public int getEmmittedLight(int x, int y, int z) { public int getEmmittedLight(int x, int y, int z) {
int layer = y >> 4; int layer = y >> 4;
if (blockLight[layer] == null) { if (blockLight[layer] == null) {
blockLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(SectionPosition.a(nmsChunk.getPos(), layer)); SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), layer);
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
// If the server hasn't generated the section's NibbleArray yet, it will be null
if (nibbleArray == null) {
byte[] a = new byte[2048];
// Safe enough to assume if it's not created, it's not got any emitted light. Unlikely to be created before lighting is fixed anyway.
Arrays.fill(a, (byte) 0);
nibbleArray = new NibbleArray(a);
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.BLOCK, sectionPosition, nibbleArray);
}
blockLight[layer] = nibbleArray;
} }
long l = BlockPosition.a(x, y, z); long l = BlockPosition.a(x, y, z);
return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l))); return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
@ -316,7 +337,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
} else { } else {
existingSection = sections[layer]; existingSection = sections[layer];
if (existingSection == null) { if (existingSection == null) {
System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); log.error("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer);
continue; continue;
} }
} }
@ -343,7 +364,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
} }
newSection = BukkitAdapter_1_15_2.newChunkSection(layer, this::load, setArr, fastmode); newSection = BukkitAdapter_1_15_2.newChunkSection(layer, this::load, setArr, fastmode);
if (!BukkitAdapter_1_15_2.setSectionAtomic(sections, existingSection, newSection, layer)) { if (!BukkitAdapter_1_15_2.setSectionAtomic(sections, existingSection, newSection, layer)) {
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); log.error("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
continue; continue;
} else { } else {
updateGet(this, nmsChunk, sections, newSection, setArr, layer); updateGet(this, nmsChunk, sections, newSection, setArr, layer);
@ -689,9 +710,13 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
if (light[Y] == null) { if (light[Y] == null) {
continue; continue;
} }
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(SectionPosition.a(nmsChunk.getPos(), Y)); SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), Y);
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(sectionPosition);
if (nibble == null) { if (nibble == null) {
continue; byte[] a = new byte[2048];
Arrays.fill(a, skyBlock == EnumSkyBlock.SKY ? (byte) 15 : (byte) 0);
nibble = new NibbleArray(a);
((LightEngine) world.getChunkProvider().getLightEngine()).a(skyBlock, sectionPosition, nibble);
} }
synchronized (nibble) { synchronized (nibble) {
for (int i = 0; i < 4096; i++) { for (int i = 0; i < 4096; i++) {

View File

@ -0,0 +1,173 @@
package com.boydti.fawe.bukkit.adapter.mc1_15_2;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_15_R2;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import net.minecraft.server.v1_15_R1.Block;
import net.minecraft.server.v1_15_R1.BlockPosition;
import net.minecraft.server.v1_15_R1.Chunk;
import net.minecraft.server.v1_15_R1.ChunkProviderServer;
import net.minecraft.server.v1_15_R1.EnumDirection;
import net.minecraft.server.v1_15_R1.IBlockData;
import net.minecraft.server.v1_15_R1.NBTBase;
import net.minecraft.server.v1_15_R1.NBTTagCompound;
import net.minecraft.server.v1_15_R1.PlayerChunk;
import net.minecraft.server.v1_15_R1.TileEntity;
import net.minecraft.server.v1_15_R1.World;
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Objects;
public class FAWEWorldNativeAccess_1_15_2 implements WorldNativeAccess<Chunk, IBlockData, BlockPosition> {
private static final int UPDATE = 1, NOTIFY = 2;
private final FAWE_Spigot_v1_15_R2 adapter;
private final WeakReference<World> world;
private SideEffectSet sideEffectSet;
public FAWEWorldNativeAccess_1_15_2(FAWE_Spigot_v1_15_R2 adapter, WeakReference<World> world) {
this.adapter = adapter;
this.world = world;
}
private World getWorld() {
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
}
@Override
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
this.sideEffectSet = sideEffectSet;
}
@Override
public Chunk getChunk(int x, int z) {
return getWorld().getChunkAt(x, z);
}
@Override
public IBlockData toNative(com.sk89q.worldedit.world.block.BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.getByCombinedId(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
}
@Override
public IBlockData getBlockState(Chunk chunk, BlockPosition position) {
return chunk.getType(position);
}
@Nullable
@Override
public IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
return chunk.setType(position, state, false);
}
@Override
public IBlockData getValidBlockForPosition(IBlockData block, BlockPosition position) {
return Block.b(block, getWorld(), position);
}
@Override
public BlockPosition getPosition(int x, int y, int z) {
return new BlockPosition(x, y, z);
}
@Override
public void updateLightingForBlock(BlockPosition position) {
getWorld().getChunkProvider().getLightEngine().a(position);
}
@Override
public boolean updateTileEntity(BlockPosition position, CompoundTag tag) {
// We will assume that the tile entity was created for us,
// though we do not do this on the other versions
TileEntity tileEntity = getWorld().getTileEntity(position);
if (tileEntity == null) {
return false;
}
NBTBase nativeTag = adapter.fromNative(tag);
tileEntity.load((NBTTagCompound) nativeTag);
return true;
}
@Override
public void notifyBlockUpdate(BlockPosition position, IBlockData oldState, IBlockData newState) {
getWorld().notify(position, oldState, newState, UPDATE | NOTIFY);
}
@Override
public boolean isChunkTicking(Chunk chunk) {
return chunk.getState().isAtLeast(PlayerChunk.State.TICKING);
}
@Override
public void markBlockChanged(BlockPosition position) {
((ChunkProviderServer) getWorld().getChunkProvider()).flagDirty(position);
}
private static final EnumDirection[] NEIGHBOUR_ORDER = {
EnumDirection.WEST, EnumDirection.EAST,
EnumDirection.DOWN, EnumDirection.UP,
EnumDirection.NORTH, EnumDirection.SOUTH
};
@Override
public void notifyNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState) {
World world = getWorld();
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
world.update(pos, oldState.getBlock());
} else {
// When we don't want events, manually run the physics without them.
// Un-nest neighbour updating
for (EnumDirection direction : NEIGHBOUR_ORDER) {
BlockPosition shifted = pos.shift(direction);
world.getType(shifted).doPhysics(world, shifted, oldState.getBlock(), pos, false);
}
}
if (newState.isComplexRedstone()) {
world.updateAdjacentComparators(pos, newState.getBlock());
}
}
@Override
public void updateNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState, int recursionLimit) {
World world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.b(world, pos, NOTIFY);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld();
if (craftWorld != null) {
BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
}
}
newState.a(world, pos, NOTIFY);
newState.b(world, pos, NOTIFY);
}
@Override
public void onBlockStateChange(BlockPosition pos, IBlockData oldState, IBlockData newState) {
getWorld().a(pos, oldState, newState);
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException {
return this.adapter.setBlock(this.getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4).bukkitChunk, position.getBlockX(), position.getBlockY(), position.getBlockZ(), block, sideEffectSet.shouldApply(SideEffect.LIGHTING));
}
}

View File

@ -1,15 +1,11 @@
package com.boydti.fawe.bukkit.adapter.mc1_15; package com.boydti.fawe.bukkit.adapter.mc1_16_1;
import com.sk89q.util.ReflectionUtil; import com.sk89q.util.ReflectionUtil;
import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockMaterial;
import net.minecraft.server.v1_15_R1.Block; import net.minecraft.server.v1_16_R1.*;
import net.minecraft.server.v1_15_R1.EnumPistonReaction; import org.bukkit.craftbukkit.v1_16_R1.block.data.CraftBlockData;
import net.minecraft.server.v1_15_R1.IBlockData;
import net.minecraft.server.v1_15_R1.ITileEntity;
import net.minecraft.server.v1_15_R1.Material;
import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData;
public class BlockMaterial_1_15 implements BlockMaterial { public class BlockMaterial_1_16_1 implements BlockMaterial {
private final Block block; private final Block block;
private final IBlockData defaultState; private final IBlockData defaultState;
private final Material material; private final Material material;
@ -17,17 +13,17 @@ public class BlockMaterial_1_15 implements BlockMaterial {
private final CraftBlockData craftBlockData; private final CraftBlockData craftBlockData;
private final org.bukkit.Material craftMaterial; private final org.bukkit.Material craftMaterial;
public BlockMaterial_1_15(Block block) { public BlockMaterial_1_16_1(Block block) {
this(block, block.getBlockData()); this(block, block.getBlockData());
} }
public BlockMaterial_1_15(Block block, IBlockData defaultState) { public BlockMaterial_1_16_1(Block block, IBlockData defaultState) {
this.block = block; this.block = block;
this.defaultState = defaultState; this.defaultState = defaultState;
this.material = defaultState.getMaterial(); this.material = defaultState.getMaterial();
this.craftBlockData = CraftBlockData.fromData(defaultState); this.craftBlockData = CraftBlockData.fromData(defaultState);
this.craftMaterial = craftBlockData.getMaterial(); this.craftMaterial = craftBlockData.getMaterial();
this.isTranslucent = !(boolean) ReflectionUtil.getField(Block.class, block, "v"); this.isTranslucent = !(boolean) ReflectionUtil.getField(Block.class, block, "at"); //TODO Update Mapping for 1.16.1
} }
public Block getBlock() { public Block getBlock() {
@ -78,7 +74,7 @@ public class BlockMaterial_1_15 implements BlockMaterial {
@Override @Override
public float getHardness() { public float getHardness() {
return block.strength; return craftBlockData.getState().strength;
} }
@Override @Override
@ -88,12 +84,12 @@ public class BlockMaterial_1_15 implements BlockMaterial {
@Override @Override
public float getSlipperiness() { public float getSlipperiness() {
return block.m(); return block.getFrictionFactor();
} }
@Override @Override
public int getLightValue() { public int getLightValue() {
return defaultState.h(); return defaultState.f();
} }
@Override @Override
@ -128,7 +124,8 @@ public class BlockMaterial_1_15 implements BlockMaterial {
@Override @Override
public boolean isToolRequired() { public boolean isToolRequired() {
return !material.isAlwaysDestroyable(); //TODO Removed in 1.16.1 Replacement not found.
return true;
} }
@Override @Override
@ -148,6 +145,6 @@ public class BlockMaterial_1_15 implements BlockMaterial {
@Override @Override
public int getMapColor() { public int getMapColor() {
return material.i().rgb; return material.h().rgb;
} }
} }

View File

@ -1,11 +1,11 @@
package com.boydti.fawe.bukkit.adapter.mc1_15; package com.boydti.fawe.bukkit.adapter.mc1_16_1;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache; import com.boydti.fawe.FaweCache;
import com.boydti.fawe.bukkit.adapter.DelegateLock; import com.boydti.fawe.bukkit.adapter.DelegateLock;
import com.boydti.fawe.bukkit.adapter.NMSAdapter; import com.boydti.fawe.bukkit.adapter.NMSAdapter;
import com.boydti.fawe.config.Settings; import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.collection.BitArray; import com.boydti.fawe.object.collection.BitArrayUnstretched;
import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.ReflectionUtils; import com.boydti.fawe.util.ReflectionUtils;
import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.TaskManager;
@ -14,22 +14,9 @@ import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import net.jpountz.util.UnsafeUtils; import net.jpountz.util.UnsafeUtils;
import net.minecraft.server.v1_15_R1.Block; import net.minecraft.server.v1_16_R1.*;
import net.minecraft.server.v1_15_R1.Chunk; import org.bukkit.craftbukkit.v1_16_R1.CraftChunk;
import net.minecraft.server.v1_15_R1.ChunkCoordIntPair; import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
import net.minecraft.server.v1_15_R1.ChunkSection;
import net.minecraft.server.v1_15_R1.DataBits;
import net.minecraft.server.v1_15_R1.DataPalette;
import net.minecraft.server.v1_15_R1.DataPaletteBlock;
import net.minecraft.server.v1_15_R1.DataPaletteLinear;
import net.minecraft.server.v1_15_R1.GameProfileSerializer;
import net.minecraft.server.v1_15_R1.IBlockData;
import net.minecraft.server.v1_15_R1.PacketPlayOutLightUpdate;
import net.minecraft.server.v1_15_R1.PlayerChunk;
import net.minecraft.server.v1_15_R1.PlayerChunkMap;
import net.minecraft.server.v1_15_R1.World;
import org.bukkit.craftbukkit.v1_15_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
import sun.misc.Unsafe; import sun.misc.Unsafe;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
@ -43,7 +30,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function; import java.util.function.Function;
public final class BukkitAdapter_1_15 extends NMSAdapter { public final class BukkitAdapter_1_16_1 extends NMSAdapter {
/* /*
NMS fields NMS fields
*/ */
@ -51,6 +38,8 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
public final static Field fieldPalette; public final static Field fieldPalette;
public final static Field fieldSize; public final static Field fieldSize;
public final static Field fieldBitsPerEntry;
public final static Field fieldFluidCount; public final static Field fieldFluidCount;
public final static Field fieldTickingBlockCount; public final static Field fieldTickingBlockCount;
public final static Field fieldNonEmptyBlockCount; public final static Field fieldNonEmptyBlockCount;
@ -74,6 +63,9 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
fieldPalette = DataPaletteBlock.class.getDeclaredField("h"); fieldPalette = DataPaletteBlock.class.getDeclaredField("h");
fieldPalette.setAccessible(true); fieldPalette.setAccessible(true);
fieldBitsPerEntry = DataBits.class.getDeclaredField("c");
fieldBitsPerEntry.setAccessible(true);
fieldFluidCount = ChunkSection.class.getDeclaredField("e"); fieldFluidCount = ChunkSection.class.getDeclaredField("e");
fieldFluidCount.setAccessible(true); fieldFluidCount.setAccessible(true);
fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount"); fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount");
@ -86,8 +78,6 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
fieldDirtyBits = PlayerChunk.class.getDeclaredField("r"); fieldDirtyBits = PlayerChunk.class.getDeclaredField("r");
fieldDirtyBits.setAccessible(true); fieldDirtyBits.setAccessible(true);
fieldTickingBlockCount.setAccessible(true);
Method declaredGetVisibleChunk = PlayerChunkMap.class.getDeclaredMethod("getVisibleChunk", long.class); Method declaredGetVisibleChunk = PlayerChunkMap.class.getDeclaredMethod("getVisibleChunk", long.class);
declaredGetVisibleChunk.setAccessible(true); declaredGetVisibleChunk.setAccessible(true);
methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk); methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk);
@ -120,6 +110,7 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
} }
protected static DelegateLock applyLock(ChunkSection section) { protected static DelegateLock applyLock(ChunkSection section) {
//todo there has to be a better way to do this. Maybe using a() in DataPaletteBlock which acquires the lock in NMS?
try { try {
synchronized (section) { synchronized (section) {
DataPaletteBlock<IBlockData> blocks = section.getBlocks(); DataPaletteBlock<IBlockData> blocks = section.getBlocks();
@ -138,7 +129,7 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
} }
public static Chunk ensureLoaded(World nmsWorld, int X, int Z) { public static Chunk ensureLoaded(World nmsWorld, int X, int Z) {
Chunk nmsChunk = nmsWorld.getChunkIfLoaded(X, Z); Chunk nmsChunk = nmsWorld.getChunkProvider().getChunkAt(X, Z, false);
if (nmsChunk != null) { if (nmsChunk != null) {
return nmsChunk; return nmsChunk;
} }
@ -159,7 +150,7 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(X, Z)); return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(X, Z));
} }
public static PlayerChunk getPlayerChunk(net.minecraft.server.v1_15_R1.WorldServer nmsWorld, final int cx, final int cz) { public static PlayerChunk getPlayerChunk(WorldServer nmsWorld, final int cx, final int cz) {
PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap; PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap;
try { try {
return (PlayerChunk)methodGetVisibleChunk.invoke(chunkMap, ChunkCoordIntPair.pair(cx, cz)); return (PlayerChunk)methodGetVisibleChunk.invoke(chunkMap, ChunkCoordIntPair.pair(cx, cz));
@ -168,7 +159,7 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
} }
} }
public static void sendChunk(net.minecraft.server.v1_15_R1.WorldServer nmsWorld, int X, int Z, int mask, boolean lighting) { public static void sendChunk(WorldServer nmsWorld, int X, int Z, int mask, boolean lighting) {
PlayerChunk playerChunk = getPlayerChunk(nmsWorld, X, Z); PlayerChunk playerChunk = getPlayerChunk(nmsWorld, X, Z);
if (playerChunk == null) { if (playerChunk == null) {
return; return;
@ -191,7 +182,8 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
if (lighting) { if (lighting) {
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(X, Z); ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(X, Z);
PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine()); boolean trustEdges = false; //Added in 1.16.1 Not sure what it does.
PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges);
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> { playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
p.playerConnection.sendPacket(packet); p.playerConnection.sendPacket(packet);
}); });
@ -202,9 +194,7 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
} }
return null; return null;
}); });
return;
} }
return;
} }
/* /*
@ -227,9 +217,11 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>(); Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
int air; int air;
if (get == null) { if (get == null) {
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer, set, ticking_blocks, fastmode); air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
set, ticking_blocks, fastmode);
} else { } else {
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer, get, set, ticking_blocks, fastmode); air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
num_palette_buffer, get, set, ticking_blocks, fastmode);
} }
int num_palette = num_palette_buffer[0]; int num_palette = num_palette_buffer[0];
// BlockStates // BlockStates
@ -240,11 +232,13 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries
} }
final int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6; final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntry);
final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong);
if (num_palette == 1) { if (num_palette == 1) {
for (int i = 0; i < blockBitArrayEnd; i++) blockStates[i] = 0; for (int i = 0; i < blockBitArrayEnd; i++) blockStates[i] = 0;
} else { } else {
final BitArray bitArray = new BitArray(bitsPerEntry, 4096, blockStates); final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntry, blockStates);
bitArray.fromRaw(blocksCopy); bitArray.fromRaw(blocksCopy);
} }
@ -257,14 +251,14 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
final DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits); final DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits);
final DataPalette<IBlockData> palette; final DataPalette<IBlockData> palette;
// palette = new DataPaletteHash<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d, GameProfileSerializer::a); // palette = new DataPaletteHash<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d, GameProfileSerializer::a);
palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d); palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::c);
// set palette // set palette
for (int i = 0; i < num_palette; i++) { for (int i = 0; i < num_palette; i++) {
final int ordinal = paletteToBlock[i]; final int ordinal = paletteToBlock[i];
blockToPalette[ordinal] = Integer.MAX_VALUE; blockToPalette[ordinal] = Integer.MAX_VALUE;
final BlockState state = BlockTypesCache.states[ordinal]; final BlockState state = BlockTypesCache.states[ordinal];
final IBlockData ibd = ((BlockMaterial_1_15) state.getMaterial()).getState(); final IBlockData ibd = ((BlockMaterial_1_16_1) state.getMaterial()).getState();
palette.a(ibd); palette.a(ibd);
} }
try { try {
@ -272,10 +266,11 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
fieldPalette.set(dataPaletteBlocks, palette); fieldPalette.set(dataPaletteBlocks, palette);
fieldSize.set(dataPaletteBlocks, bitsPerEntry); fieldSize.set(dataPaletteBlocks, bitsPerEntry);
setCount(ticking_blocks.size(), 4096 - air, section); setCount(ticking_blocks.size(), 4096 - air, section);
ticking_blocks.forEach((pos, ordinal) -> { if (!fastmode) {
section.setType(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(), ticking_blocks.forEach((pos, ordinal) -> section
Block.getByCombinedId(ordinal)); .setType(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(),
}); Block.getByCombinedId(ordinal)));
}
} catch (final IllegalAccessException | NoSuchFieldException e) { } catch (final IllegalAccessException | NoSuchFieldException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@ -1,6 +1,4 @@
package com.boydti.fawe.bukkit.adapter.mc1_15; package com.boydti.fawe.bukkit.adapter.mc1_16_1;
import static org.slf4j.LoggerFactory.getLogger;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache; import com.boydti.fawe.FaweCache;
@ -9,71 +7,46 @@ import com.boydti.fawe.beta.implementation.blocks.CharBlocks;
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks; import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.boydti.fawe.beta.implementation.queue.QueueHandler; import com.boydti.fawe.beta.implementation.queue.QueueHandler;
import com.boydti.fawe.bukkit.adapter.DelegateLock; import com.boydti.fawe.bukkit.adapter.DelegateLock;
import com.boydti.fawe.bukkit.adapter.mc1_15.nbt.LazyCompoundTag_1_15; import com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt.LazyCompoundTag_1_16_1;
import com.boydti.fawe.config.Settings; import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.collection.AdaptedMap; import com.boydti.fawe.object.collection.AdaptedMap;
import com.boydti.fawe.object.collection.BitArray; import com.boydti.fawe.object.collection.BitArrayUnstretched;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.LongTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.jnbt.*;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_15_R1; import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R1;
import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.internal.Constants;
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.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.AbstractSet; import net.minecraft.server.v1_16_R1.*;
import java.util.Arrays; import org.bukkit.World;
import java.util.Collection; import org.bukkit.block.Biome;
import java.util.Collections; import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
import java.util.Iterator; import org.bukkit.craftbukkit.v1_16_R1.block.CraftBlock;
import java.util.List; import org.bukkit.event.entity.CreatureSpawnEvent;
import java.util.Map; import org.jetbrains.annotations.NotNull;
import java.util.HashMap; import org.slf4j.Logger;
import java.util.Set; import org.slf4j.LoggerFactory;
import java.util.UUID;
import javax.annotation.Nullable;
import java.util.*;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import net.minecraft.server.v1_15_R1.BiomeBase;
import net.minecraft.server.v1_15_R1.BiomeStorage;
import net.minecraft.server.v1_15_R1.BlockPosition;
import net.minecraft.server.v1_15_R1.Chunk;
import net.minecraft.server.v1_15_R1.ChunkSection;
import net.minecraft.server.v1_15_R1.DataBits;
import net.minecraft.server.v1_15_R1.DataPalette;
import net.minecraft.server.v1_15_R1.DataPaletteBlock;
import net.minecraft.server.v1_15_R1.DataPaletteHash;
import net.minecraft.server.v1_15_R1.DataPaletteLinear;
import net.minecraft.server.v1_15_R1.Entity;
import net.minecraft.server.v1_15_R1.EntityTypes;
import net.minecraft.server.v1_15_R1.EnumSkyBlock;
import net.minecraft.server.v1_15_R1.IBlockData;
import net.minecraft.server.v1_15_R1.LightEngineThreaded;
import net.minecraft.server.v1_15_R1.NBTTagCompound;
import net.minecraft.server.v1_15_R1.NBTTagInt;
import net.minecraft.server.v1_15_R1.NibbleArray;
import net.minecraft.server.v1_15_R1.SectionPosition;
import net.minecraft.server.v1_15_R1.TileEntity;
import net.minecraft.server.v1_15_R1.WorldServer;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_15_R1.block.CraftBlock;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.jetbrains.annotations.NotNull;
public class BukkitGetBlocks_1_15 extends CharGetBlocks { import static org.slf4j.LoggerFactory.getLogger;
public class BukkitGetBlocks_1_16_1 extends CharGetBlocks {
private static final Logger log = LoggerFactory.getLogger(BukkitGetBlocks_1_16_1.class);
private static final Function<BlockPosition, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ()); private static final Function<BlockPosition, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
private final static Function<TileEntity, CompoundTag> nmsTile2We = tileEntity -> new LazyCompoundTag_1_15(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound()))); private final static Function<TileEntity, CompoundTag> nmsTile2We = tileEntity -> new LazyCompoundTag_1_16_1(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
public ChunkSection[] sections; public ChunkSection[] sections;
public Chunk nmsChunk; public Chunk nmsChunk;
public WorldServer world; public WorldServer world;
@ -81,11 +54,11 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
public NibbleArray[] blockLight = new NibbleArray[16]; public NibbleArray[] blockLight = new NibbleArray[16];
public NibbleArray[] skyLight = new NibbleArray[16]; public NibbleArray[] skyLight = new NibbleArray[16];
public BukkitGetBlocks_1_15(World world, int X, int Z) { public BukkitGetBlocks_1_16_1(World world, int X, int Z) {
this(((CraftWorld) world).getHandle(), X, Z); this(((CraftWorld) world).getHandle(), X, Z);
} }
public BukkitGetBlocks_1_15(WorldServer world, int X, int Z) { public BukkitGetBlocks_1_16_1(WorldServer world, int X, int Z) {
this.world = world; this.world = world;
this.X = X; this.X = X;
this.Z = Z; this.Z = Z;
@ -120,7 +93,7 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
if (tileEntity == null) { if (tileEntity == null) {
return null; return null;
} }
return new LazyCompoundTag_1_15(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound()))); return new LazyCompoundTag_1_16_1(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
} }
@Override @Override
@ -136,7 +109,17 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
public int getSkyLight(int x, int y, int z) { public int getSkyLight(int x, int y, int z) {
int layer = y >> 4; int layer = y >> 4;
if (skyLight[layer] == null) { if (skyLight[layer] == null) {
skyLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(SectionPosition.a(nmsChunk.getPos(), layer)); SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), layer);
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPosition);
// If the server hasn't generated the section's NibbleArray yet, it will be null
if (nibbleArray == null) {
byte[] a = new byte[2048];
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
Arrays.fill(a, (byte) 15);
nibbleArray = new NibbleArray(a);
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibbleArray, true);
}
skyLight[layer] = nibbleArray;
} }
long l = BlockPosition.a(x, y, z); long l = BlockPosition.a(x, y, z);
return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l))); return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
@ -145,8 +128,18 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
@Override @Override
public int getEmmittedLight(int x, int y, int z) { public int getEmmittedLight(int x, int y, int z) {
int layer = y >> 4; int layer = y >> 4;
if (blockLight[layer] == null) { if (skyLight[layer] == null) {
blockLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(SectionPosition.a(nmsChunk.getPos(), layer)); SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), layer);
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
// If the server hasn't generated the section's NibbleArray yet, it will be null
if (nibbleArray == null) {
byte[] a = new byte[2048];
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
Arrays.fill(a, (byte) 15);
nibbleArray = new NibbleArray(a);
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.BLOCK, sectionPosition, nibbleArray, true);
}
skyLight[layer] = nibbleArray;
} }
long l = BlockPosition.a(x, y, z); long l = BlockPosition.a(x, y, z);
return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l))); return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
@ -219,19 +212,21 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
@NotNull @NotNull
@Override @Override
public Iterator<CompoundTag> iterator() { public Iterator<CompoundTag> iterator() {
Iterable<CompoundTag> result = StreamSupport Iterable<CompoundTag> result = Iterables.transform(Iterables.concat(slices), new com.google.common.base.Function<Entity, CompoundTag>() {
.stream(Iterables.concat(slices).spliterator(), false).map(input -> { @Nullable
BukkitImplAdapter adapter = WorldEditPlugin.getInstance() @Override
.getBukkitImplAdapter(); public CompoundTag apply(@Nullable Entity input) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
NBTTagCompound tag = new NBTTagCompound(); NBTTagCompound tag = new NBTTagCompound();
return (CompoundTag) adapter.toNative(input.save(tag)); return (CompoundTag) adapter.toNative(input.save(tag));
}).collect(Collectors.toList()); }
});
return result.iterator(); return result.iterator();
} }
}; };
} }
private void updateGet(BukkitGetBlocks_1_15 get, Chunk nmsChunk, ChunkSection[] sections, ChunkSection section, char[] arr, int layer) { private void updateGet(BukkitGetBlocks_1_16_1 get, Chunk nmsChunk, ChunkSection[] sections, ChunkSection section, char[] arr, int layer) {
synchronized (get) { synchronized (get) {
if (this.nmsChunk != nmsChunk) { if (this.nmsChunk != nmsChunk) {
this.nmsChunk = nmsChunk; this.nmsChunk = nmsChunk;
@ -242,7 +237,7 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
this.sections = sections.clone(); this.sections = sections.clone();
} }
if (this.sections[layer] != section) { if (this.sections[layer] != section) {
this.sections[layer] = section; this.sections[layer] = new ChunkSection[]{section}.clone()[0];
} }
this.blocks[layer] = arr; this.blocks[layer] = arr;
} }
@ -253,8 +248,8 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
entity.valid = false; entity.valid = false;
} }
public Chunk ensureLoaded(net.minecraft.server.v1_15_R1.World nmsWorld, int X, int Z) { public Chunk ensureLoaded(net.minecraft.server.v1_16_R1.World nmsWorld, int X, int Z) {
return BukkitAdapter_1_15.ensureLoaded(nmsWorld, X, Z); return BukkitAdapter_1_16_1.ensureLoaded(nmsWorld, X, Z);
} }
@Override @Override
@ -266,6 +261,7 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
// Remove existing tiles // Remove existing tiles
{ {
// Create a copy so that we can remove blocks
Map<BlockPosition, TileEntity> tiles = new HashMap<>(nmsChunk.getTileEntities()); Map<BlockPosition, TileEntity> tiles = new HashMap<>(nmsChunk.getTileEntities());
if (!tiles.isEmpty()) { if (!tiles.isEmpty()) {
for (Map.Entry<BlockPosition, TileEntity> entry : tiles.entrySet()) { for (Map.Entry<BlockPosition, TileEntity> entry : tiles.entrySet()) {
@ -277,7 +273,9 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
if (!set.hasSection(layer)) { if (!set.hasSection(layer)) {
continue; continue;
} }
if (set.getBlock(lx, ly, lz).getOrdinal() != 0) {
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
if (ordinal != 0) {
TileEntity tile = entry.getValue(); TileEntity tile = entry.getValue();
nmsChunk.removeTileEntity(tile.getPosition()); nmsChunk.removeTileEntity(tile.getPosition());
} }
@ -290,7 +288,9 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
ChunkSection[] sections = nmsChunk.getSections(); ChunkSection[] sections = nmsChunk.getSections();
for (int layer = 0; layer < 16; layer++) { for (int layer = 0; layer < 16; layer++) {
if (!set.hasSection(layer)) continue; if (!set.hasSection(layer)){
continue;
}
bitMask |= 1 << layer; bitMask |= 1 << layer;
@ -298,23 +298,23 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
ChunkSection newSection; ChunkSection newSection;
ChunkSection existingSection = sections[layer]; ChunkSection existingSection = sections[layer];
if (existingSection == null) { if (existingSection == null) {
newSection = BukkitAdapter_1_15.newChunkSection(layer, setArr, fastmode); newSection = BukkitAdapter_1_16_1.newChunkSection(layer, setArr, fastmode);
if (BukkitAdapter_1_15.setSectionAtomic(sections, null, newSection, layer)) { if (BukkitAdapter_1_16_1.setSectionAtomic(sections, null, newSection, layer)) {
updateGet(this, nmsChunk, sections, newSection, setArr, layer); updateGet(this, nmsChunk, sections, newSection, setArr, layer);
continue; continue;
} else { } else {
existingSection = sections[layer]; existingSection = sections[layer];
if (existingSection == null) { if (existingSection == null) {
System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer); log.error("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer);
continue; continue;
} }
} }
} }
BukkitAdapter_1_16_1.fieldTickingBlockCount.set(existingSection, (short) 0);
//ensure that the server doesn't try to tick the chunksection while we're editing it. //ensure that the server doesn't try to tick the chunksection while we're editing it.
BukkitAdapter_1_15.fieldTickingBlockCount.set(existingSection, (short) 0); DelegateLock lock = BukkitAdapter_1_16_1.applyLock(existingSection);
DelegateLock lock = BukkitAdapter_1_15.applyLock(existingSection);
synchronized (this) { synchronized (this) {
synchronized (lock) { synchronized (lock) {
lock.untilFree(); lock.untilFree();
@ -330,9 +330,11 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
} else if (lock.isModified()) { } else if (lock.isModified()) {
this.reset(layer); this.reset(layer);
} }
newSection = BukkitAdapter_1_15.newChunkSection(layer, this::load, setArr, fastmode); newSection = BukkitAdapter_1_16_1
if (!BukkitAdapter_1_15.setSectionAtomic(sections, existingSection, newSection, layer)) { .newChunkSection(layer, this::load, setArr, fastmode);
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); if (!BukkitAdapter_1_16_1
.setSectionAtomic(sections, existingSection, newSection, layer)) {
log.error("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
continue; continue;
} else { } else {
updateGet(this, nmsChunk, sections, newSection, setArr, layer); updateGet(this, nmsChunk, sections, newSection, setArr, layer);
@ -421,7 +423,8 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
final ListTag posTag = (ListTag) entityTagMap.get("Pos"); final ListTag posTag = (ListTag) entityTagMap.get("Pos");
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation"); final ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
if (idTag == null || posTag == null || rotTag == null) { if (idTag == null || posTag == null || rotTag == null) {
getLogger(BukkitGetBlocks_1_15.class).debug("Unknown entity tag: " + nativeTag); getLogger(
BukkitGetBlocks_1_16_1.class).debug("Unknown entity tag: " + nativeTag);
continue; continue;
} }
final double x = posTag.getDouble(0); final double x = posTag.getDouble(0);
@ -444,7 +447,7 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
tag.remove(name); tag.remove(name);
} }
entity.f(tag); entity.save(tag);
} }
entity.setLocation(x, y, z, yaw, pitch); entity.setLocation(x, y, z, yaw, pitch);
nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM); nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
@ -481,7 +484,7 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
tag.set("x", NBTTagInt.a(x)); tag.set("x", NBTTagInt.a(x));
tag.set("y", NBTTagInt.a(y)); tag.set("y", NBTTagInt.a(y));
tag.set("z", NBTTagInt.a(z)); tag.set("z", NBTTagInt.a(z));
tileEntity.load(tag); tileEntity.load(tileEntity.getBlock(), tag);
} }
} }
} }
@ -500,7 +503,7 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
nmsChunk.mustNotSave = false; nmsChunk.mustNotSave = false;
nmsChunk.markDirty(); nmsChunk.markDirty();
// send to player // send to player
BukkitAdapter_1_15.sendChunk(nmsWorld, X, Z, finalMask, finalLightUpdate); BukkitAdapter_1_16_1.sendChunk(nmsWorld, X, Z, finalMask, finalLightUpdate);
if (finalizer != null) finalizer.run(); if (finalizer != null) finalizer.run();
}; };
} }
@ -554,31 +557,27 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
if (data == null || data == FaweCache.IMP.EMPTY_CHAR_4096) { if (data == null || data == FaweCache.IMP.EMPTY_CHAR_4096) {
data = new char[4096]; data = new char[4096];
} }
DelegateLock lock = BukkitAdapter_1_15.applyLock(section); DelegateLock lock = BukkitAdapter_1_16_1.applyLock(section);
synchronized (lock) { synchronized (lock) {
lock.untilFree(); lock.untilFree();
lock.setModified(false); lock.setModified(false);
// Efficiently convert ChunkSection to raw data // Efficiently convert ChunkSection to raw data
try { try {
FAWE_Spigot_v1_15_R1 adapter = ((FAWE_Spigot_v1_15_R1) WorldEditPlugin.getInstance().getBukkitImplAdapter()); FAWE_Spigot_v1_16_R1 adapter = ((FAWE_Spigot_v1_16_R1) WorldEditPlugin.getInstance().getBukkitImplAdapter());
final DataPaletteBlock<IBlockData> blocks = section.getBlocks(); final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
final DataBits bits = (DataBits) BukkitAdapter_1_15.fieldBits.get(blocks); final DataBits bits = (DataBits) BukkitAdapter_1_16_1.fieldBits.get(blocks);
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_15.fieldPalette.get(blocks); final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_16_1.fieldPalette.get(blocks);
//getBits() final int bitsPerEntry = (int) BukkitAdapter_1_16_1.fieldBitsPerEntry.get(bits);
final int bitsPerEntry = bits.c();
//getRaw()
final long[] blockStates = bits.a(); final long[] blockStates = bits.a();
new BitArray(bitsPerEntry, 4096, blockStates).toRaw(data); new BitArrayUnstretched(bitsPerEntry, blockStates).toRaw(data);
int num_palette; int num_palette;
if (palette instanceof DataPaletteLinear) { if (palette instanceof DataPaletteLinear) {
//Get the size of the palette
num_palette = ((DataPaletteLinear<IBlockData>) palette).b(); num_palette = ((DataPaletteLinear<IBlockData>) palette).b();
} else if (palette instanceof DataPaletteHash) { } else if (palette instanceof DataPaletteHash) {
//Get the size of the palette
num_palette = ((DataPaletteHash<IBlockData>) palette).b(); num_palette = ((DataPaletteHash<IBlockData>) palette).b();
} else { } else {
num_palette = 0; num_palette = 0;
@ -590,7 +589,6 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
char ordinal = paletteToBlockChars[paletteVal]; char ordinal = paletteToBlockChars[paletteVal];
if (ordinal == Character.MAX_VALUE) { if (ordinal == Character.MAX_VALUE) {
paletteToBlockInts[num_palette++] = paletteVal; paletteToBlockInts[num_palette++] = paletteVal;
//palette.a(Object) is palette.idFor(Object)
IBlockData ibd = palette.a(data[i]); IBlockData ibd = palette.a(data[i]);
if (ibd == null) { if (ibd == null) {
ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar(); ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar();
@ -614,7 +612,6 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
try { try {
if (num_palette != 1) { if (num_palette != 1) {
for (int i = 0; i < num_palette; i++) { for (int i = 0; i < num_palette; i++) {
//palette.a(Object) is palette.idFor(Object)
char ordinal = ordinal(palette.a(i), adapter); char ordinal = ordinal(palette.a(i), adapter);
paletteToOrdinal[i] = ordinal; paletteToOrdinal[i] = ordinal;
} }
@ -644,7 +641,7 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
} }
} }
private final char ordinal(IBlockData ibd, FAWE_Spigot_v1_15_R1 adapter) { private final char ordinal(IBlockData ibd, FAWE_Spigot_v1_16_R1 adapter) {
if (ibd == null) { if (ibd == null) {
return BlockTypes.AIR.getDefaultState().getOrdinalChar(); return BlockTypes.AIR.getDefaultState().getOrdinalChar();
} else { } else {
@ -684,9 +681,13 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
if (light[Y] == null) { if (light[Y] == null) {
continue; continue;
} }
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(SectionPosition.a(nmsChunk.getPos(), Y)); SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), Y);
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(sectionPosition);
if (nibble == null) { if (nibble == null) {
continue; byte[] a = new byte[2048];
Arrays.fill(a, skyBlock == EnumSkyBlock.SKY ? (byte) 15 : (byte) 0);
nibble = new NibbleArray(a);
((LightEngine) world.getChunkProvider().getLightEngine()).a(skyBlock, sectionPosition, nibble, true);
} }
synchronized (nibble) { synchronized (nibble) {
for (int i = 0; i < 4096; i++) { for (int i = 0; i < 4096; i++) {
@ -705,6 +706,8 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
@Override @Override
public boolean trim(boolean aggressive) { public boolean trim(boolean aggressive) {
skyLight = new NibbleArray[16];
blockLight = new NibbleArray[16];
if (aggressive) { if (aggressive) {
sections = null; sections = null;
nmsChunk = null; nmsChunk = null;
@ -718,7 +721,7 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
try { try {
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks(); final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_15.fieldPalette.get(blocksExisting); final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_16_1.fieldPalette.get(blocksExisting);
int paletteSize; int paletteSize;
if (palette instanceof DataPaletteLinear) { if (palette instanceof DataPaletteLinear) {

View File

@ -0,0 +1,174 @@
package com.boydti.fawe.bukkit.adapter.mc1_16_1;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R1;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import net.minecraft.server.v1_16_R1.Block;
import net.minecraft.server.v1_16_R1.BlockPosition;
import net.minecraft.server.v1_16_R1.Chunk;
import net.minecraft.server.v1_16_R1.ChunkProviderServer;
import net.minecraft.server.v1_16_R1.EnumDirection;
import net.minecraft.server.v1_16_R1.IBlockData;
import net.minecraft.server.v1_16_R1.NBTBase;
import net.minecraft.server.v1_16_R1.NBTTagCompound;
import net.minecraft.server.v1_16_R1.PlayerChunk;
import net.minecraft.server.v1_16_R1.TileEntity;
import net.minecraft.server.v1_16_R1.World;
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_16_R1.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Objects;
public class FAWEWorldNativeAccess_1_16 implements WorldNativeAccess<Chunk, IBlockData, BlockPosition> {
private static final int UPDATE = 1, NOTIFY = 2;
private final FAWE_Spigot_v1_16_R1 adapter;
private final WeakReference<World> world;
private SideEffectSet sideEffectSet;
public FAWEWorldNativeAccess_1_16(FAWE_Spigot_v1_16_R1 adapter, WeakReference<World> world) {
this.adapter = adapter;
this.world = world;
}
private World getWorld() {
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
}
@Override
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
this.sideEffectSet = sideEffectSet;
}
@Override
public Chunk getChunk(int x, int z) {
return getWorld().getChunkAt(x, z);
}
@Override
public IBlockData toNative(BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.getByCombinedId(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
}
@Override
public IBlockData getBlockState(Chunk chunk, BlockPosition position) {
return chunk.getType(position);
}
@Nullable
@Override
public IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
return chunk.setType(position, state, false);
}
@Override
public IBlockData getValidBlockForPosition(IBlockData block, BlockPosition position) {
return Block.b(block, getWorld(), position);
}
@Override
public BlockPosition getPosition(int x, int y, int z) {
return new BlockPosition(x, y, z);
}
@Override
public void updateLightingForBlock(BlockPosition position) {
getWorld().getChunkProvider().getLightEngine().a(position);
}
@Override
public boolean updateTileEntity(BlockPosition position, CompoundTag tag) {
// We will assume that the tile entity was created for us,
// though we do not do this on the other versions
TileEntity tileEntity = getWorld().getTileEntity(position);
if (tileEntity == null) {
return false;
}
NBTBase nativeTag = adapter.fromNative(tag);
tileEntity.load(tileEntity.getBlock(), (NBTTagCompound) nativeTag);
return true;
}
@Override
public void notifyBlockUpdate(BlockPosition position, IBlockData oldState, IBlockData newState) {
getWorld().notify(position, oldState, newState, UPDATE | NOTIFY);
}
@Override
public boolean isChunkTicking(Chunk chunk) {
return chunk.getState().isAtLeast(PlayerChunk.State.TICKING);
}
@Override
public void markBlockChanged(BlockPosition position) {
((ChunkProviderServer) getWorld().getChunkProvider()).flagDirty(position);
}
private static final EnumDirection[] NEIGHBOUR_ORDER = {
EnumDirection.WEST, EnumDirection.EAST,
EnumDirection.DOWN, EnumDirection.UP,
EnumDirection.NORTH, EnumDirection.SOUTH
};
@Override
public void notifyNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState) {
World world = getWorld();
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
world.update(pos, oldState.getBlock());
} else {
// When we don't want events, manually run the physics without them.
// Un-nest neighbour updating
for (EnumDirection direction : NEIGHBOUR_ORDER) {
BlockPosition shifted = pos.shift(direction);
world.getType(shifted).doPhysics(world, shifted, oldState.getBlock(), pos, false);
}
}
if (newState.isComplexRedstone()) {
world.updateAdjacentComparators(pos, newState.getBlock());
}
}
@Override
public void updateNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState, int recursionLimit) {
World world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.b(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld();
if (craftWorld != null) {
BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
world.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
}
}
newState.a(world, pos, NOTIFY, recursionLimit);
newState.b(world, pos, NOTIFY, recursionLimit);
}
@Override
public void onBlockStateChange(BlockPosition pos, IBlockData oldState, IBlockData newState) {
getWorld().a(pos, oldState, newState);
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException {
return this.adapter.setBlock(this.getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4).bukkitChunk, position.getBlockX(), position.getBlockY(), position.getBlockZ(), block, sideEffectSet.shouldApply(SideEffect.LIGHTING));
}
}

View File

@ -1,17 +1,17 @@
package com.boydti.fawe.bukkit.adapter.mc1_15; package com.boydti.fawe.bukkit.adapter.mc1_16_1;
import com.boydti.fawe.bukkit.adapter.MapChunkUtil; import com.boydti.fawe.bukkit.adapter.MapChunkUtil;
import net.minecraft.server.v1_15_R1.PacketPlayOutMapChunk; import net.minecraft.server.v1_16_R1.PacketPlayOutMapChunk;
public class MapChunkUtil_1_15 extends MapChunkUtil<PacketPlayOutMapChunk> { public class MapChunkUtil_1_16_1 extends MapChunkUtil<PacketPlayOutMapChunk> {
public MapChunkUtil_1_15() throws NoSuchFieldException { public MapChunkUtil_1_16_1() throws NoSuchFieldException {
fieldX = PacketPlayOutMapChunk.class.getDeclaredField("a"); fieldX = PacketPlayOutMapChunk.class.getDeclaredField("a");
fieldZ = PacketPlayOutMapChunk.class.getDeclaredField("b"); fieldZ = PacketPlayOutMapChunk.class.getDeclaredField("b");
fieldBitMask = PacketPlayOutMapChunk.class.getDeclaredField("c"); fieldBitMask = PacketPlayOutMapChunk.class.getDeclaredField("c");
fieldHeightMap = PacketPlayOutMapChunk.class.getDeclaredField("d"); fieldHeightMap = PacketPlayOutMapChunk.class.getDeclaredField("d");
fieldChunkData = PacketPlayOutMapChunk.class.getDeclaredField("e"); fieldChunkData = PacketPlayOutMapChunk.class.getDeclaredField("f");
fieldBlockEntities = PacketPlayOutMapChunk.class.getDeclaredField("f"); fieldBlockEntities = PacketPlayOutMapChunk.class.getDeclaredField("g");
fieldFull = PacketPlayOutMapChunk.class.getDeclaredField("g"); fieldFull = PacketPlayOutMapChunk.class.getDeclaredField("h");
fieldX.setAccessible(true); fieldX.setAccessible(true);
fieldZ.setAccessible(true); fieldZ.setAccessible(true);
fieldBitMask.setAccessible(true); fieldBitMask.setAccessible(true);

View File

@ -1,14 +1,14 @@
package com.boydti.fawe.bukkit.adapter.mc1_15.nbt; package com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import net.minecraft.server.v1_15_R1.NBTBase; import net.minecraft.server.v1_16_R1.NBTBase;
import net.minecraft.server.v1_15_R1.NBTNumber; import net.minecraft.server.v1_16_R1.NBTNumber;
import net.minecraft.server.v1_15_R1.NBTTagCompound; import net.minecraft.server.v1_16_R1.NBTTagCompound;
import net.minecraft.server.v1_15_R1.NBTTagList; import net.minecraft.server.v1_16_R1.NBTTagList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -16,15 +16,15 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
public class LazyCompoundTag_1_15 extends CompoundTag { public class LazyCompoundTag_1_16_1 extends CompoundTag {
private final Supplier<NBTTagCompound> nmsTag; private final Supplier<NBTTagCompound> nmsTag;
public LazyCompoundTag_1_15(Supplier<NBTTagCompound> tag) { public LazyCompoundTag_1_16_1(Supplier<NBTTagCompound> tag) {
super(null); super(null);
this.nmsTag = tag; this.nmsTag = tag;
} }
public LazyCompoundTag_1_15(NBTTagCompound tag) { public LazyCompoundTag_1_16_1(NBTTagCompound tag) {
this(() -> tag); this(() -> tag);
} }
@ -93,7 +93,7 @@ public class LazyCompoundTag_1_15 extends CompoundTag {
NBTTagList nbtList = (NBTTagList) tag; NBTTagList nbtList = (NBTTagList) tag;
for (NBTBase elem : nbtList) { for (NBTBase elem : nbtList) {
if (elem instanceof NBTTagCompound) { if (elem instanceof NBTTagCompound) {
list.add(new LazyCompoundTag_1_15((NBTTagCompound) elem)); list.add(new LazyCompoundTag_1_16_1((NBTTagCompound) elem));
} else { } else {
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem)); list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
} }
@ -149,4 +149,4 @@ public class LazyCompoundTag_1_15 extends CompoundTag {
public String toString() { public String toString() {
return nmsTag.get().toString(); return nmsTag.get().toString();
} }
} }

View File

@ -84,7 +84,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
private BukkitImplAdapter adapter; private BukkitImplAdapter adapter;
@Override @Override
public <T> void spawnParticle(Particle particle, double v, double v1, double v2, int i, double v3, double v4, double v5, double v6, T t) { public <T> void spawnParticle(@NotNull Particle particle, double v, double v1, double v2, int i, double v3, double v4, double v5, double v6, T t) {
parent.spawnParticle(particle, v, v1, v2, i, v3, v4, v5, v6, t); parent.spawnParticle(particle, v, v1, v2, i, v3, v4, v5, v6, t);
} }
@ -158,77 +158,77 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public WorldBorder getWorldBorder() { public @NotNull WorldBorder getWorldBorder() {
return TaskManager.IMP.sync(() -> parent.getWorldBorder()); return TaskManager.IMP.sync(() -> parent.getWorldBorder());
} }
@Override @Override
public void spawnParticle(Particle particle, Location location, int i) { public void spawnParticle(@NotNull Particle particle, @NotNull Location location, int i) {
parent.spawnParticle(particle, location, i); parent.spawnParticle(particle, location, i);
} }
@Override @Override
public void spawnParticle(Particle particle, double v, double v1, double v2, int i) { public void spawnParticle(@NotNull Particle particle, double v, double v1, double v2, int i) {
parent.spawnParticle(particle, v, v1, v2, i); parent.spawnParticle(particle, v, v1, v2, i);
} }
@Override @Override
public <T> void spawnParticle(Particle particle, Location location, int i, T t) { public <T> void spawnParticle(@NotNull Particle particle, @NotNull Location location, int i, T t) {
parent.spawnParticle(particle, location, i, t); parent.spawnParticle(particle, location, i, t);
} }
@Override @Override
public <T> void spawnParticle(Particle particle, double x, double y, double z, int count, T data) { public <T> void spawnParticle(@NotNull Particle particle, double x, double y, double z, int count, T data) {
parent.spawnParticle(particle, x, y, z, count, data); parent.spawnParticle(particle, x, y, z, count, data);
} }
@Override @Override
public void spawnParticle(Particle particle, Location location, int count, double offsetX, double offsetY, double offsetZ) { public void spawnParticle(@NotNull Particle particle, @NotNull Location location, int count, double offsetX, double offsetY, double offsetZ) {
parent.spawnParticle(particle, location, count, offsetX, offsetY, offsetZ); parent.spawnParticle(particle, location, count, offsetX, offsetY, offsetZ);
} }
@Override @Override
public void spawnParticle(Particle particle, double v, double v1, double v2, int i, double v3, double v4, double v5) { public void spawnParticle(@NotNull Particle particle, double v, double v1, double v2, int i, double v3, double v4, double v5) {
parent.spawnParticle(particle, v, v1, v2, i, v3, v4, v5); parent.spawnParticle(particle, v, v1, v2, i, v3, v4, v5);
} }
@Override @Override
public <T> void spawnParticle(Particle particle, Location location, int i, double v, double v1, double v2, T t) { public <T> void spawnParticle(@NotNull Particle particle, @NotNull Location location, int i, double v, double v1, double v2, T t) {
parent.spawnParticle(particle, location, i, v, v1, v2, t); parent.spawnParticle(particle, location, i, v, v1, v2, t);
} }
@Override @Override
public <T> void spawnParticle(Particle particle, double v, double v1, double v2, int i, double v3, double v4, double v5, T t) { public <T> void spawnParticle(@NotNull Particle particle, double v, double v1, double v2, int i, double v3, double v4, double v5, T t) {
parent.spawnParticle(particle, v, v1, v2, i, v3, v4, v5, t); parent.spawnParticle(particle, v, v1, v2, i, v3, v4, v5, t);
} }
@Override @Override
public void spawnParticle(Particle particle, Location location, int i, double v, double v1, double v2, double v3) { public void spawnParticle(@NotNull Particle particle, @NotNull Location location, int i, double v, double v1, double v2, double v3) {
parent.spawnParticle(particle, location, i, v, v1, v2, v3); parent.spawnParticle(particle, location, i, v, v1, v2, v3);
} }
@Override @Override
public void spawnParticle(Particle particle, double v, double v1, double v2, int i, double v3, double v4, double v5, double v6) { public void spawnParticle(@NotNull Particle particle, double v, double v1, double v2, int i, double v3, double v4, double v5, double v6) {
parent.spawnParticle(particle, v, v1, v2, i, v3, v4, v5, v6); parent.spawnParticle(particle, v, v1, v2, i, v3, v4, v5, v6);
} }
@Override @Override
public <T> void spawnParticle(Particle particle, Location location, int i, double v, double v1, double v2, double v3, T t) { public <T> void spawnParticle(@NotNull Particle particle, @NotNull Location location, int i, double v, double v1, double v2, double v3, T t) {
parent.spawnParticle(particle, location, i, v, v1, v2, v3, t); parent.spawnParticle(particle, location, i, v, v1, v2, v3, t);
} }
@Override @Override
public boolean setSpawnLocation(Location location) { public boolean setSpawnLocation(@NotNull Location location) {
return parent.setSpawnLocation(location); return parent.setSpawnLocation(location);
} }
@Override @Override
public AsyncBlock getBlockAt(final int x, final int y, final int z) { public @NotNull AsyncBlock getBlockAt(final int x, final int y, final int z) {
return new AsyncBlock(this, x, y, z); return new AsyncBlock(this, x, y, z);
} }
@Override @Override
public AsyncBlock getBlockAt(Location loc) { public @NotNull AsyncBlock getBlockAt(Location loc) {
return getBlockAt(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); return getBlockAt(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
} }
@ -247,13 +247,13 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public AsyncBlock getHighestBlockAt(int x, int z) { public @NotNull AsyncBlock getHighestBlockAt(int x, int z) {
int y = getHighestBlockYAt(x, z); int y = getHighestBlockYAt(x, z);
return getBlockAt(x, y, z); return getBlockAt(x, y, z);
} }
@Override @Override
public AsyncBlock getHighestBlockAt(Location loc) { public @NotNull AsyncBlock getHighestBlockAt(Location loc) {
return getHighestBlockAt(loc.getBlockX(), loc.getBlockZ()); return getHighestBlockAt(loc.getBlockX(), loc.getBlockZ());
} }
@ -279,17 +279,17 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public AsyncChunk getChunkAt(int x, int z) { public @NotNull AsyncChunk getChunkAt(int x, int z) {
return new AsyncChunk(this, x, z); return new AsyncChunk(this, x, z);
} }
@Override @Override
public AsyncChunk getChunkAt(Location location) { public @NotNull AsyncChunk getChunkAt(Location location) {
return getChunkAt(location.getBlockX(), location.getBlockZ()); return getChunkAt(location.getBlockX(), location.getBlockZ());
} }
@Override @Override
public AsyncChunk getChunkAt(Block block) { public @NotNull AsyncChunk getChunkAt(Block block) {
return getChunkAt(block.getX(), block.getZ()); return getChunkAt(block.getX(), block.getZ());
} }
@ -405,17 +405,17 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public Item dropItem(final Location location, final ItemStack item) { public @NotNull Item dropItem(final @NotNull Location location, final @NotNull ItemStack item) {
return TaskManager.IMP.sync(() -> parent.dropItem(location, item)); return TaskManager.IMP.sync(() -> parent.dropItem(location, item));
} }
@Override @Override
public Item dropItemNaturally(final Location location, final ItemStack item) { public @NotNull Item dropItemNaturally(final @NotNull Location location, final @NotNull ItemStack item) {
return TaskManager.IMP.sync(() -> parent.dropItemNaturally(location, item)); return TaskManager.IMP.sync(() -> parent.dropItemNaturally(location, item));
} }
@Override @Override
public Arrow spawnArrow(final Location location, final Vector direction, final float speed, final float spread) { public @NotNull Arrow spawnArrow(final @NotNull Location location, final @NotNull Vector direction, final float speed, final float spread) {
return TaskManager.IMP.sync(() -> parent.spawnArrow(location, direction, speed, spread)); return TaskManager.IMP.sync(() -> parent.spawnArrow(location, direction, speed, spread));
} }
@ -425,78 +425,78 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public boolean generateTree(final Location location, final TreeType type) { public boolean generateTree(final @NotNull Location location, final @NotNull TreeType type) {
return TaskManager.IMP.sync(() -> parent.generateTree(location, type)); return TaskManager.IMP.sync(() -> parent.generateTree(location, type));
} }
@Override @Override
public boolean generateTree(final Location loc, final TreeType type, final BlockChangeDelegate delegate) { public boolean generateTree(final @NotNull Location loc, final @NotNull TreeType type, final @NotNull BlockChangeDelegate delegate) {
return TaskManager.IMP.sync(() -> parent.generateTree(loc, type, delegate)); return TaskManager.IMP.sync(() -> parent.generateTree(loc, type, delegate));
} }
@Override @Override
public Entity spawnEntity(Location loc, EntityType type) { public @NotNull Entity spawnEntity(@NotNull Location loc, EntityType type) {
return spawn(loc, type.getEntityClass()); return spawn(loc, type.getEntityClass());
} }
@Override @Override
public LightningStrike strikeLightning(final Location loc) { public @NotNull LightningStrike strikeLightning(final @NotNull Location loc) {
return TaskManager.IMP.sync(() -> parent.strikeLightning(loc)); return TaskManager.IMP.sync(() -> parent.strikeLightning(loc));
} }
@Override @Override
public LightningStrike strikeLightningEffect(final Location loc) { public @NotNull LightningStrike strikeLightningEffect(final @NotNull Location loc) {
return TaskManager.IMP.sync(() -> parent.strikeLightningEffect(loc)); return TaskManager.IMP.sync(() -> parent.strikeLightningEffect(loc));
} }
@Override @Override
public List getEntities() { public @NotNull List getEntities() {
return TaskManager.IMP.sync(() -> parent.getEntities()); return TaskManager.IMP.sync(() -> parent.getEntities());
} }
@Override @Override
public List<LivingEntity> getLivingEntities() { public @NotNull List<LivingEntity> getLivingEntities() {
return TaskManager.IMP.sync(() -> parent.getLivingEntities()); return TaskManager.IMP.sync(() -> parent.getLivingEntities());
} }
@Override @Override
@Deprecated @Deprecated
public <T extends Entity> Collection<T> getEntitiesByClass(final Class<T>... classes) { public <T extends Entity> @NotNull Collection<T> getEntitiesByClass(final Class<T>... classes) {
return TaskManager.IMP.sync(() -> parent.getEntitiesByClass(classes)); return TaskManager.IMP.sync(() -> parent.getEntitiesByClass(classes));
} }
@Override @Override
public <T extends Entity> Collection<T> getEntitiesByClass(final Class<T> cls) { public <T extends Entity> @NotNull Collection<T> getEntitiesByClass(final @NotNull Class<T> cls) {
return TaskManager.IMP.sync(() -> parent.getEntitiesByClass(cls)); return TaskManager.IMP.sync(() -> parent.getEntitiesByClass(cls));
} }
@Override @Override
public Collection<Entity> getEntitiesByClasses(final Class<?>... classes) { public @NotNull Collection<Entity> getEntitiesByClasses(final Class<?>... classes) {
return TaskManager.IMP.sync(() -> parent.getEntitiesByClasses(classes)); return TaskManager.IMP.sync(() -> parent.getEntitiesByClasses(classes));
} }
@Override @Override
public List<Player> getPlayers() { public @NotNull List<Player> getPlayers() {
return TaskManager.IMP.sync(() -> parent.getPlayers()); return TaskManager.IMP.sync(() -> parent.getPlayers());
} }
@Override @Override
public Collection<Entity> getNearbyEntities(final Location location, final double x, final double y, final double z) { public @NotNull Collection<Entity> getNearbyEntities(final @NotNull Location location, final double x, final double y, final double z) {
return TaskManager.IMP.sync(() -> parent.getNearbyEntities(location, x, y, z)); return TaskManager.IMP.sync(() -> parent.getNearbyEntities(location, x, y, z));
} }
@Override @Override
public String getName() { public @NotNull String getName() {
return parent.getName(); return parent.getName();
} }
@Override @Override
public UUID getUID() { public @NotNull UUID getUID() {
return parent.getUID(); return parent.getUID();
} }
@Override @Override
public Location getSpawnLocation() { public @NotNull Location getSpawnLocation() {
return parent.getSpawnLocation(); return parent.getSpawnLocation();
} }
@ -590,7 +590,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public boolean createExplosion(Location loc, float power) { public boolean createExplosion(@NotNull Location loc, float power) {
return this.createExplosion(loc, power, false); return this.createExplosion(loc, power, false);
} }
@ -636,17 +636,17 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public List<BlockPopulator> getPopulators() { public @NotNull List<BlockPopulator> getPopulators() {
return parent.getPopulators(); return parent.getPopulators();
} }
@Override @Override
public <T extends Entity> T spawn(final Location location, final Class<T> clazz) throws IllegalArgumentException { public <T extends Entity> @NotNull T spawn(final @NotNull Location location, final @NotNull Class<T> clazz) throws IllegalArgumentException {
return TaskManager.IMP.sync(() -> parent.spawn(location, clazz)); return TaskManager.IMP.sync(() -> parent.spawn(location, clazz));
} }
@Override @Override
public <T extends Entity> T spawn(Location location, Class<T> clazz, Consumer<T> function) throws IllegalArgumentException { public <T extends Entity> @NotNull T spawn(@NotNull Location location, @NotNull Class<T> clazz, Consumer<T> function) throws IllegalArgumentException {
return TaskManager.IMP.sync(() -> parent.spawn(location, clazz, function)); return TaskManager.IMP.sync(() -> parent.spawn(location, clazz, function));
} }
@ -656,28 +656,28 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public FallingBlock spawnFallingBlock(Location location, MaterialData data) throws IllegalArgumentException { public @NotNull FallingBlock spawnFallingBlock(@NotNull Location location, @NotNull MaterialData data) throws IllegalArgumentException {
return TaskManager.IMP.sync(() -> parent.spawnFallingBlock(location, data)); return TaskManager.IMP.sync(() -> parent.spawnFallingBlock(location, data));
} }
@Override @Override
@Deprecated @Deprecated
public FallingBlock spawnFallingBlock(Location location, Material material, byte data) throws IllegalArgumentException { public @NotNull FallingBlock spawnFallingBlock(@NotNull Location location, @NotNull Material material, byte data) throws IllegalArgumentException {
return TaskManager.IMP.sync(() -> parent.spawnFallingBlock(location, material, data)); return TaskManager.IMP.sync(() -> parent.spawnFallingBlock(location, material, data));
} }
@Override @Override
public FallingBlock spawnFallingBlock(Location location, BlockData blockData) throws IllegalArgumentException { public @NotNull FallingBlock spawnFallingBlock(@NotNull Location location, @NotNull BlockData blockData) throws IllegalArgumentException {
return TaskManager.IMP.sync(() -> parent.spawnFallingBlock(location, blockData)); return TaskManager.IMP.sync(() -> parent.spawnFallingBlock(location, blockData));
} }
@Override @Override
public void playEffect(Location location, Effect effect, int data) { public void playEffect(@NotNull Location location, @NotNull Effect effect, int data) {
this.playEffect(location, effect, data, 64); this.playEffect(location, effect, data, 64);
} }
@Override @Override
public void playEffect(final Location location, final Effect effect, final int data, final int radius) { public void playEffect(final @NotNull Location location, final @NotNull Effect effect, final int data, final int radius) {
TaskManager.IMP.sync(new RunnableVal<Object>() { TaskManager.IMP.sync(new RunnableVal<Object>() {
@Override @Override
public void run(Object value) { public void run(Object value) {
@ -687,12 +687,12 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public <T> void playEffect(Location loc, Effect effect, T data) { public <T> void playEffect(@NotNull Location loc, @NotNull Effect effect, T data) {
this.playEffect(loc, effect, data, 64); this.playEffect(loc, effect, data, 64);
} }
@Override @Override
public <T> void playEffect(final Location location, final Effect effect, final T data, final int radius) { public <T> void playEffect(final @NotNull Location location, final @NotNull Effect effect, final T data, final int radius) {
TaskManager.IMP.sync(new RunnableVal<Object>() { TaskManager.IMP.sync(new RunnableVal<Object>() {
@Override @Override
public void run(Object value) { public void run(Object value) {
@ -702,7 +702,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public ChunkSnapshot getEmptyChunkSnapshot(final int x, final int z, final boolean includeBiome, final boolean includeBiomeTempRain) { public @NotNull ChunkSnapshot getEmptyChunkSnapshot(final int x, final int z, final boolean includeBiome, final boolean includeBiomeTempRain) {
return TaskManager.IMP.sync( return TaskManager.IMP.sync(
() -> parent.getEmptyChunkSnapshot(x, z, includeBiome, includeBiomeTempRain)); () -> parent.getEmptyChunkSnapshot(x, z, includeBiome, includeBiomeTempRain));
} }
@ -723,7 +723,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public Biome getBiome(int x, int z) { public @NotNull Biome getBiome(int x, int z) {
return adapter.adapt(getExtent().getBiomeType(x, 0, z)); return adapter.adapt(getExtent().getBiomeType(x, 0, z));
} }
@ -733,7 +733,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public void setBiome(int x, int z, Biome bio) { public void setBiome(int x, int z, @NotNull Biome bio) {
BiomeType biome = adapter.adapt(bio); BiomeType biome = adapter.adapt(bio);
getExtent().setBiome(x, 0, z, biome); getExtent().setBiome(x, 0, z, biome);
} }
@ -800,17 +800,17 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public void setDifficulty(Difficulty difficulty) { public void setDifficulty(@NotNull Difficulty difficulty) {
parent.setDifficulty(difficulty); parent.setDifficulty(difficulty);
} }
@Override @Override
public Difficulty getDifficulty() { public @NotNull Difficulty getDifficulty() {
return parent.getDifficulty(); return parent.getDifficulty();
} }
@Override @Override
public File getWorldFolder() { public @NotNull File getWorldFolder() {
return parent.getWorldFolder(); return parent.getWorldFolder();
} }
@ -884,6 +884,14 @@ public class AsyncWorld extends PassthroughExtent implements World {
parent.setWaterAnimalSpawnLimit(limit); parent.setWaterAnimalSpawnLimit(limit);
} }
@Override public int getWaterAmbientSpawnLimit() {
return parent.getWaterAmbientSpawnLimit();
}
@Override public void setWaterAmbientSpawnLimit(int limit) {
parent.setWaterAmbientSpawnLimit(limit);
}
@Override @Override
public int getAmbientSpawnLimit() { public int getAmbientSpawnLimit() {
return parent.getAmbientSpawnLimit(); return parent.getAmbientSpawnLimit();
@ -895,7 +903,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public void playSound(final Location location, final Sound sound, final float volume, final float pitch) { public void playSound(final @NotNull Location location, final @NotNull Sound sound, final float volume, final float pitch) {
TaskManager.IMP.sync(new RunnableVal<Object>() { TaskManager.IMP.sync(new RunnableVal<Object>() {
@Override @Override
public void run(Object value) { public void run(Object value) {
@ -905,7 +913,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public void playSound(final Location location, final String sound, final float volume, final float pitch) { public void playSound(final @NotNull Location location, final @NotNull String sound, final float volume, final float pitch) {
TaskManager.IMP.sync(new RunnableVal<Object>() { TaskManager.IMP.sync(new RunnableVal<Object>() {
@Override @Override
public void run(Object value) { public void run(Object value) {
@ -915,7 +923,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public void playSound(Location location, Sound sound, SoundCategory category, float volume, float pitch) { public void playSound(@NotNull Location location, @NotNull Sound sound, @NotNull SoundCategory category, float volume, float pitch) {
TaskManager.IMP.sync(new RunnableVal<Object>() { TaskManager.IMP.sync(new RunnableVal<Object>() {
@Override @Override
public void run(Object value) { public void run(Object value) {
@ -925,7 +933,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public void playSound(Location location, String sound, SoundCategory category, float volume, float pitch) { public void playSound(@NotNull Location location, @NotNull String sound, @NotNull SoundCategory category, float volume, float pitch) {
TaskManager.IMP.sync(new RunnableVal<Object>() { TaskManager.IMP.sync(new RunnableVal<Object>() {
@Override @Override
public void run(Object value) { public void run(Object value) {
@ -945,32 +953,32 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public boolean setGameRuleValue(String rule, String value) { public boolean setGameRuleValue(@NotNull String rule, @NotNull String value) {
return parent.setGameRuleValue(rule, value); return parent.setGameRuleValue(rule, value);
} }
@Override @Override
public boolean isGameRule(String rule) { public boolean isGameRule(@NotNull String rule) {
return parent.isGameRule(rule); return parent.isGameRule(rule);
} }
@Override @Override
public <T> T getGameRuleValue(GameRule<T> gameRule) { public <T> T getGameRuleValue(@NotNull GameRule<T> gameRule) {
return parent.getGameRuleValue(gameRule); return parent.getGameRuleValue(gameRule);
} }
@Override @Override
public <T> T getGameRuleDefault(GameRule<T> gameRule) { public <T> T getGameRuleDefault(@NotNull GameRule<T> gameRule) {
return parent.getGameRuleDefault(gameRule); return parent.getGameRuleDefault(gameRule);
} }
@Override @Override
public <T> boolean setGameRule(GameRule<T> gameRule, T t) { public <T> boolean setGameRule(@NotNull GameRule<T> gameRule, @NotNull T t) {
return parent.setGameRule(gameRule, t); return parent.setGameRule(gameRule, t);
} }
@Override @Override
public Spigot spigot() { public @NotNull Spigot spigot() {
return parent.spigot(); return parent.spigot();
} }
@ -985,7 +993,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public void setMetadata(final String key, final MetadataValue meta) { public void setMetadata(final @NotNull String key, final @NotNull MetadataValue meta) {
TaskManager.IMP.sync(new RunnableVal<Object>() { TaskManager.IMP.sync(new RunnableVal<Object>() {
@Override @Override
public void run(Object value) { public void run(Object value) {
@ -995,17 +1003,17 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public List<MetadataValue> getMetadata(String key) { public @NotNull List<MetadataValue> getMetadata(@NotNull String key) {
return parent.getMetadata(key); return parent.getMetadata(key);
} }
@Override @Override
public boolean hasMetadata(String key) { public boolean hasMetadata(@NotNull String key) {
return parent.hasMetadata(key); return parent.hasMetadata(key);
} }
@Override @Override
public void removeMetadata(final String key, final Plugin plugin) { public void removeMetadata(final @NotNull String key, final @NotNull Plugin plugin) {
TaskManager.IMP.sync(new RunnableVal<Object>() { TaskManager.IMP.sync(new RunnableVal<Object>() {
@Override @Override
public void run(Object value) { public void run(Object value) {
@ -1015,12 +1023,12 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public void sendPluginMessage(Plugin source, String channel, byte[] message) { public void sendPluginMessage(@NotNull Plugin source, @NotNull String channel, byte[] message) {
parent.sendPluginMessage(source, channel, message); parent.sendPluginMessage(source, channel, message);
} }
@Override @Override
public Set<String> getListeningPluginChannels() { public @NotNull Set<String> getListeningPluginChannels() {
return parent.getListeningPluginChannels(); return parent.getListeningPluginChannels();
} }
@ -1029,17 +1037,17 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public Collection<Entity> getNearbyEntities(BoundingBox arg0) { public @NotNull Collection<Entity> getNearbyEntities(@NotNull BoundingBox arg0) {
return parent.getNearbyEntities(arg0); return parent.getNearbyEntities(arg0);
} }
@Override @Override
public Collection<Entity> getNearbyEntities(BoundingBox arg0, Predicate<Entity> arg1) { public @NotNull Collection<Entity> getNearbyEntities(@NotNull BoundingBox arg0, Predicate<Entity> arg1) {
return parent.getNearbyEntities(arg0, arg1); return parent.getNearbyEntities(arg0, arg1);
} }
@Override @Override
public Collection<Entity> getNearbyEntities(Location arg0, double arg1, double arg2, double arg3, public @NotNull Collection<Entity> getNearbyEntities(@NotNull Location arg0, double arg1, double arg2, double arg3,
Predicate<Entity> arg4) { Predicate<Entity> arg4) {
return parent.getNearbyEntities(arg0, arg1, arg2, arg3, arg4); return parent.getNearbyEntities(arg0, arg1, arg2, arg3, arg4);
} }
@ -1050,7 +1058,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public Location locateNearestStructure(Location arg0, StructureType arg1, int arg2, boolean arg3) { public Location locateNearestStructure(@NotNull Location arg0, @NotNull StructureType arg1, int arg2, boolean arg3) {
return parent.locateNearestStructure(arg0, arg1, arg2, arg3); return parent.locateNearestStructure(arg0, arg1, arg2, arg3);
} }
@ -1075,44 +1083,45 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public RayTraceResult rayTrace(Location arg0, Vector arg1, double arg2, FluidCollisionMode arg3, boolean arg4, public RayTraceResult rayTrace(
@NotNull Location arg0, @NotNull Vector arg1, double arg2, @NotNull FluidCollisionMode arg3, boolean arg4,
double arg5, Predicate<Entity> arg6) { double arg5, Predicate<Entity> arg6) {
return parent.rayTrace(arg0, arg1, arg2, arg3, arg4, arg5, arg6); return parent.rayTrace(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
} }
@Override @Override
public RayTraceResult rayTraceBlocks(Location arg0, Vector arg1, double arg2) { public RayTraceResult rayTraceBlocks(@NotNull Location arg0, @NotNull Vector arg1, double arg2) {
return parent.rayTraceBlocks(arg0, arg1, arg2); return parent.rayTraceBlocks(arg0, arg1, arg2);
} }
@Override @Override
public RayTraceResult rayTraceBlocks(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode) { public RayTraceResult rayTraceBlocks(@NotNull Location start, @NotNull Vector direction, double maxDistance, @NotNull FluidCollisionMode fluidCollisionMode) {
return parent.rayTraceBlocks(start, direction, maxDistance, fluidCollisionMode); return parent.rayTraceBlocks(start, direction, maxDistance, fluidCollisionMode);
} }
@Override @Override
public RayTraceResult rayTraceBlocks(Location start, Vector direction, double arg2, FluidCollisionMode fluidCollisionMode, public RayTraceResult rayTraceBlocks(@NotNull Location start, @NotNull Vector direction, double arg2, @NotNull FluidCollisionMode fluidCollisionMode,
boolean ignorePassableBlocks) { boolean ignorePassableBlocks) {
return parent.rayTraceBlocks(start, direction, arg2, fluidCollisionMode, ignorePassableBlocks); return parent.rayTraceBlocks(start, direction, arg2, fluidCollisionMode, ignorePassableBlocks);
} }
@Override @Override
public RayTraceResult rayTraceEntities(Location start, Vector direction, double maxDistance) { public RayTraceResult rayTraceEntities(@NotNull Location start, @NotNull Vector direction, double maxDistance) {
return parent.rayTraceEntities(start, direction, maxDistance); return parent.rayTraceEntities(start, direction, maxDistance);
} }
@Override @Override
public RayTraceResult rayTraceEntities(Location arg0, Vector arg1, double arg2, double arg3) { public RayTraceResult rayTraceEntities(@NotNull Location arg0, @NotNull Vector arg1, double arg2, double arg3) {
return parent.rayTraceEntities(arg0, arg1, arg2, arg3); return parent.rayTraceEntities(arg0, arg1, arg2, arg3);
} }
@Override @Override
public RayTraceResult rayTraceEntities(Location arg0, Vector arg1, double arg2, Predicate<Entity> arg3) { public RayTraceResult rayTraceEntities(@NotNull Location arg0, @NotNull Vector arg1, double arg2, Predicate<Entity> arg3) {
return parent.rayTraceEntities(arg0, arg1, arg2, arg3); return parent.rayTraceEntities(arg0, arg1, arg2, arg3);
} }
@Override @Override
public RayTraceResult rayTraceEntities(Location arg0, Vector arg1, double arg2, double arg3, public RayTraceResult rayTraceEntities(@NotNull Location arg0, @NotNull Vector arg1, double arg2, double arg3,
Predicate<Entity> arg4) { Predicate<Entity> arg4) {
return parent.rayTraceEntities(arg0, arg1, arg2, arg3, arg4); return parent.rayTraceEntities(arg0, arg1, arg2, arg3, arg4);
} }
@ -1131,7 +1140,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public Collection<Chunk> getForceLoadedChunks() { public @NotNull Collection<Chunk> getForceLoadedChunks() {
return parent.getForceLoadedChunks(); return parent.getForceLoadedChunks();
} }
@ -1161,7 +1170,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public int getHighestBlockYAt(int x, int z, com.destroystokyo.paper.HeightmapType heightmap) throws UnsupportedOperationException { public int getHighestBlockYAt(int x, int z, com.destroystokyo.paper.@NotNull HeightmapType heightmap) throws UnsupportedOperationException {
return TaskManager.IMP.sync(() -> parent.getHighestBlockYAt(x, z, heightmap)); return TaskManager.IMP.sync(() -> parent.getHighestBlockYAt(x, z, heightmap));
} }
@ -1191,7 +1200,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public CompletableFuture<Chunk> getChunkAtAsync(int arg0, int arg1, boolean arg2) { public @NotNull CompletableFuture<Chunk> getChunkAtAsync(int arg0, int arg1, boolean arg2) {
return parent.getChunkAtAsync(arg0, arg1, arg2); return parent.getChunkAtAsync(arg0, arg1, arg2);
} }
@ -1206,22 +1215,22 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public void getChunkAtAsync(int x, int z, ChunkLoadCallback cb) { public void getChunkAtAsync(int x, int z, @NotNull ChunkLoadCallback cb) {
parent.getChunkAtAsync(x, z, cb); parent.getChunkAtAsync(x, z, cb);
} }
@Override @Override
public void getChunkAtAsync(Location location, ChunkLoadCallback cb) { public void getChunkAtAsync(@NotNull Location location, @NotNull ChunkLoadCallback cb) {
parent.getChunkAtAsync(location, cb); parent.getChunkAtAsync(location, cb);
} }
@Override @Override
public void getChunkAtAsync(Block block, ChunkLoadCallback cb) { public void getChunkAtAsync(@NotNull Block block, @NotNull ChunkLoadCallback cb) {
parent.getChunkAtAsync(block, cb); parent.getChunkAtAsync(block, cb);
} }
@Override @Override
public Entity getEntity(UUID uuid) { public Entity getEntity(@NotNull UUID uuid) {
return TaskManager.IMP.sync(() -> parent.getEntity(uuid)); return TaskManager.IMP.sync(() -> parent.getEntity(uuid));
} }
@ -1232,7 +1241,7 @@ public class AsyncWorld extends PassthroughExtent implements World {
} }
@Override @Override
public boolean createExplosion(Entity source, Location loc, float power, boolean setFire, boolean breakBlocks) { public boolean createExplosion(Entity source, @NotNull Location loc, float power, boolean setFire, boolean breakBlocks) {
return TaskManager.IMP.sync(() -> parent.createExplosion(source, loc, power, setFire, breakBlocks)); return TaskManager.IMP.sync(() -> parent.createExplosion(source, loc, power, setFire, breakBlocks));
} }
@ -1250,12 +1259,13 @@ public class AsyncWorld extends PassthroughExtent implements World {
@Override @Override
public <T> void spawnParticle(Particle particle, List<Player> receivers, Player source, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data) { public <T> void spawnParticle(
@NotNull Particle particle, List<Player> receivers, @NotNull Player source, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data) {
parent.spawnParticle(particle, receivers, source, x, y, z, count, offsetX, offsetY, offsetZ, extra, data); parent.spawnParticle(particle, receivers, source, x, y, z, count, offsetX, offsetY, offsetZ, extra, data);
} }
@Override @Override
public <T> void spawnParticle(Particle particle, List<Player> list, Player player, double v, double v1, double v2, int i, double v3, double v4, double v5, double v6, T t, boolean b) { public <T> void spawnParticle(@NotNull Particle particle, List<Player> list, Player player, double v, double v1, double v2, int i, double v3, double v4, double v5, double v6, T t, boolean b) {
parent.spawnParticle(particle, list, player, v, v1, v2, i, v3, v4, v5, v6, t, b); parent.spawnParticle(particle, list, player, v, v1, v2, i, v3, v4, v5, v6, t, b);
} }
@ -1284,19 +1294,34 @@ public class AsyncWorld extends PassthroughExtent implements World {
return parent.getHighestBlockAt(location, heightmap); return parent.getHighestBlockAt(location, heightmap);
} }
@Override
public long getTicksPerWaterSpawns() { public long getTicksPerWaterSpawns() {
throw new UnsupportedOperationException(); return parent.getTicksPerWaterSpawns();
} }
@Override
public void setTicksPerWaterSpawns(int ticksPerWaterSpawns) { public void setTicksPerWaterSpawns(int ticksPerWaterSpawns) {
throw new UnsupportedOperationException(); parent.setTicksPerWaterSpawns(ticksPerWaterSpawns);
} }
@Override
public long getTicksPerWaterAmbientSpawns() {
return parent.getTicksPerWaterAmbientSpawns();
}
@Override
public void setTicksPerWaterAmbientSpawns(int ticksPerAmbientSpawns) {
parent.setTicksPerWaterAmbientSpawns(ticksPerAmbientSpawns);
}
@Override
public long getTicksPerAmbientSpawns() { public long getTicksPerAmbientSpawns() {
throw new UnsupportedOperationException(); return parent.getTicksPerAmbientSpawns();
} }
@Override
public void setTicksPerAmbientSpawns(int ticksPerAmbientSpawns) { public void setTicksPerAmbientSpawns(int ticksPerAmbientSpawns) {
throw new UnsupportedOperationException(); parent.setTicksPerAmbientSpawns(ticksPerAmbientSpawns);
} }
} }

View File

@ -3,15 +3,20 @@ package com.boydti.fawe.bukkit.wrapper.state;
import com.boydti.fawe.FaweCache; import com.boydti.fawe.FaweCache;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.persistence.PersistentDataAdapterContext; import org.bukkit.persistence.PersistentDataAdapterContext;
import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
public final class AsyncDataContainer implements PersistentDataContainer { public final class AsyncDataContainer implements PersistentDataContainer {
private final CompoundTag root; private final CompoundTag root;
@ -69,6 +74,20 @@ public final class AsyncDataContainer implements PersistentDataContainer {
return z != null ? z : defaultValue; return z != null ? z : defaultValue;
} }
@NotNull
@Override
public Set<NamespacedKey> getKeys() {
Set<NamespacedKey> keys = new HashSet<>();
this.get(false).keySet().forEach(key -> {
String[] keyData = key.split(":", 2);
if (keyData.length == 2) {
keys.add(new NamespacedKey(keyData[0], keyData[1]));
}
});
return keys;
}
public void remove(NamespacedKey key) { public void remove(NamespacedKey key) {
Validate.notNull(key, "The provided key for the custom value was null"); Validate.notNull(key, "The provided key for the custom value was null");
get(false).remove(key.toString()); get(false).remove(key.toString());

View File

@ -19,6 +19,7 @@
package com.sk89q.worldedit.bukkit; package com.sk89q.worldedit.bukkit;
import com.google.common.collect.Sets;
import com.sk89q.bukkit.util.CommandInfo; import com.sk89q.bukkit.util.CommandInfo;
import com.sk89q.bukkit.util.CommandRegistration; import com.sk89q.bukkit.util.CommandRegistration;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
@ -30,6 +31,7 @@ import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.MultiUserPlatform;
import com.sk89q.worldedit.extension.platform.Preference; import com.sk89q.worldedit.extension.platform.Preference;
import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extension.platform.Watchdog;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.registry.Registries; import com.sk89q.worldedit.world.registry.Registries;
@ -44,8 +46,8 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -218,6 +220,18 @@ public class BukkitServerInterface implements MultiUserPlatform {
return capabilities; return capabilities;
} }
private static final Set<SideEffect> SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet(
SideEffect.NEIGHBORS
);
@Override
public Set<SideEffect> getSupportedSideEffects() {
if (plugin.getBukkitImplAdapter() != null) {
return plugin.getBukkitImplAdapter().getSupportedSideEffects();
}
return SUPPORTED_SIDE_EFFECTS;
}
public void unregisterCommands() { public void unregisterCommands() {
dynamicCommands.unregisterCommands(); dynamicCommands.unregisterCommands();
} }

View File

@ -24,6 +24,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.implementation.packet.ChunkPacket; import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
@ -33,11 +35,14 @@ import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
@ -48,15 +53,7 @@ import com.sk89q.worldedit.world.weather.WeatherTypes;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.*;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.function.Supplier;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.bukkit.Effect; import org.bukkit.Effect;
import org.bukkit.TreeType; import org.bukkit.TreeType;
@ -83,6 +80,7 @@ public class BukkitWorld extends AbstractWorld {
} }
private final WeakReference<World> worldRef; private final WeakReference<World> worldRef;
private final WorldNativeAccess<?, ?, ?> worldNativeAccess;
/** /**
* Construct the object. * Construct the object.
@ -91,6 +89,12 @@ public class BukkitWorld extends AbstractWorld {
*/ */
public BukkitWorld(World world) { public BukkitWorld(World world) {
this.worldRef = new WeakReference<>(world); this.worldRef = new WeakReference<>(world);
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
if (adapter != null) {
this.worldNativeAccess = adapter.createWorldNativeAccess(world);
} else {
this.worldNativeAccess = null;
}
} }
@Override @Override
@ -479,26 +483,22 @@ public class BukkitWorld extends AbstractWorld {
} }
@Override @Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException { public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); if (worldNativeAccess != null) {
if (adapter != null) {
try { try {
return adapter.setBlock(BukkitAdapter.adapt(getWorld(), position), block, notifyAndLight); return worldNativeAccess.setBlock(position, block, sideEffects);
} catch (Exception e) { } catch (Exception e) {
if (block instanceof BaseBlock && ((BaseBlock) block).getNbtData() != null) { if (block instanceof BaseBlock && ((BaseBlock) block).getNbtData() != null) {
logger.warn("Tried to set a corrupt tile entity at " + position.toString()); logger.warn("Tried to set a corrupt tile entity at " + position.toString() +
logger.warn(((BaseBlock) block).getNbtData().toString()); ": " + ((BaseBlock) block).getNbtData(), e);
} else {
logger.warn("Failed to set block via adapter, falling back to generic", e);
} }
e.printStackTrace();
Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ());
bukkitBlock.setBlockData(BukkitAdapter.adapt(block), notifyAndLight);
return true;
} }
} else {
Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ());
bukkitBlock.setBlockData(BukkitAdapter.adapt(block), false);
return true;
} }
Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ());
bukkitBlock.setBlockData(BukkitAdapter.adapt(block), sideEffects.doesApplyAny());
return true;
} }
@Override @Override
@ -512,14 +512,17 @@ public class BukkitWorld extends AbstractWorld {
} }
@Override @Override
public boolean notifyAndLightBlock(BlockVector3 position, com.sk89q.worldedit.world.block.BlockState previousType) throws WorldEditException { public Set<SideEffect> applySideEffects(BlockVector3 position, com.sk89q.worldedit.world.block.BlockState previousType,
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); SideEffectSet sideEffectSet) {
if (adapter != null) { if (worldNativeAccess != null) {
adapter.notifyAndLightBlock(BukkitAdapter.adapt(getWorld(), position), previousType); worldNativeAccess.applySideEffects(position, previousType, sideEffectSet);
return true; return Sets.intersection(
WorldEditPlugin.getInstance().getInternalPlatform().getSupportedSideEffects(),
sideEffectSet.getSideEffectsToApply()
);
} }
return false; return ImmutableSet.of();
} }
@Override @Override

View File

@ -33,8 +33,8 @@ import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.bukkit.adapter.AdapterLoadException; import com.sk89q.worldedit.bukkit.adapter.AdapterLoadException;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplLoader; import com.sk89q.worldedit.bukkit.adapter.BukkitImplLoader;
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_15_R1;
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_15_R2; import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_15_R2;
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R1;
import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
import com.sk89q.worldedit.event.platform.PlatformReadyEvent; import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
@ -371,8 +371,8 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
BukkitImplLoader adapterLoader = new BukkitImplLoader(); BukkitImplLoader adapterLoader = new BukkitImplLoader();
try { try {
adapterLoader.addClass(FAWE_Spigot_v1_14_R4.class); adapterLoader.addClass(FAWE_Spigot_v1_14_R4.class);
adapterLoader.addClass(FAWE_Spigot_v1_15_R1.class);
adapterLoader.addClass(FAWE_Spigot_v1_15_R2.class); adapterLoader.addClass(FAWE_Spigot_v1_15_R2.class);
adapterLoader.addClass(FAWE_Spigot_v1_16_R1.class);
} catch (Throwable throwable) { } catch (Throwable throwable) {
throwable.printStackTrace(); throwable.printStackTrace();
} }

View File

@ -30,19 +30,21 @@ import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.biome.BiomeType; 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.BlockType; import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockMaterial;
import java.util.Map; import java.util.Map;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
@ -95,23 +97,12 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
BaseBlock getBlock(Location location); BaseBlock getBlock(Location location);
/** /**
* Set the block at the given location. * Create a {@link WorldNativeAccess} for the given world reference.
* *
* @param location the location * @param world the world reference
* @param state the block * @return the native access object
* @param notifyAndLight notify and light if set
* @return true if a block was likely changed
*/ */
<B extends BlockStateHolder<B>> boolean setBlock(Location location, B state, boolean notifyAndLight); WorldNativeAccess<?, ?, ?> createWorldNativeAccess(World world);
/**
* Notifies the simulation that the block at the given location has
* been changed and it must be re-lighted (and issue other events).
*
* @param position position of the block
* @param previousType the type of the previous block that was there
*/
void notifyAndLightBlock(Location position, BlockState previousType);
/** /**
* Get the state for the given entity. * Get the state for the given entity.
@ -186,6 +177,13 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
*/ */
BaseItemStack adapt(ItemStack itemStack); BaseItemStack adapt(ItemStack itemStack);
/**
* Get the {@link SideEffect}s that this adapter supports.
*
* @return The side effects that are supported
*/
Set<SideEffect> getSupportedSideEffects();
default OptionalInt getInternalBlockStateId(BlockData data) { default OptionalInt getInternalBlockStateId(BlockData data) {
// return OptionalInt.empty(); // return OptionalInt.empty();
return getInternalBlockStateId(BukkitAdapter.adapt(data)); return getInternalBlockStateId(BukkitAdapter.adapt(data));

View File

@ -155,11 +155,20 @@ public class BukkitImplLoader {
*/ */
public BukkitImplAdapter loadAdapter() throws AdapterLoadException { public BukkitImplAdapter loadAdapter() throws AdapterLoadException {
for (String className : adapterCandidates) { for (String className : adapterCandidates) {
System.out.println("Candidate: " + className);
try { try {
Class<?> cls = Class.forName(className); Class<?> cls = Class.forName(className);
if (cls.isSynthetic()) continue; if (cls.isSynthetic()){
System.out.println(className + " is synthetic, continuing");
continue;
}else{
System.out.println(className + " is not synthetic");
}
if (BukkitImplAdapter.class.isAssignableFrom(cls)) { if (BukkitImplAdapter.class.isAssignableFrom(cls)) {
System.out.println(className + " is assignable from BukkitImplAdapter, returning");
return (BukkitImplAdapter) cls.newInstance(); return (BukkitImplAdapter) cls.newInstance();
}else{
System.out.println(className + " is NOT assignable from BukkitImplAdapter, returning");
} }
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
log.warn("Failed to load the Bukkit adapter class '" + className + log.warn("Failed to load the Bukkit adapter class '" + className +
@ -170,6 +179,8 @@ public class BukkitImplLoader {
} catch (Throwable e) { } catch (Throwable e) {
if (className.equals(customCandidate)) { if (className.equals(customCandidate)) {
log.warn("Failed to load the Bukkit adapter class '" + className + "'", e); log.warn("Failed to load the Bukkit adapter class '" + className + "'", e);
}else{
log.warn(className + " is not custom candidate.", e);
} }
} }
} }

View File

@ -12,6 +12,7 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
@ -65,15 +66,6 @@ public interface IDelegateBukkitImplAdapter<T> extends BukkitImplAdapter<T> {
return getParent().getBlock(location); return getParent().getBlock(location);
} }
default <B extends BlockStateHolder<B>> boolean setBlock(Location location, B state, boolean notifyAndLight) {
return getParent().setBlock(location, state, notifyAndLight);
}
@Override
default void notifyAndLightBlock(Location position, BlockState previousType) {
getParent().notifyAndLightBlock(position, previousType);
}
@Override @Override
@Nullable @Nullable
default BaseEntity getEntity(Entity entity) { default BaseEntity getEntity(Entity entity) {

View File

@ -24,10 +24,7 @@ import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.implementation.packet.ChunkPacket; import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
import com.boydti.fawe.beta.implementation.queue.SingleThreadQueueExtent; import com.boydti.fawe.beta.implementation.queue.SingleThreadQueueExtent;
import com.boydti.fawe.bukkit.adapter.mc1_14.BlockMaterial_1_14; import com.boydti.fawe.bukkit.adapter.mc1_14.*;
import com.boydti.fawe.bukkit.adapter.mc1_14.BukkitAdapter_1_14;
import com.boydti.fawe.bukkit.adapter.mc1_14.BukkitGetBlocks_1_14;
import com.boydti.fawe.bukkit.adapter.mc1_14.MapChunkUtil_1_14;
import com.boydti.fawe.bukkit.adapter.mc1_14.nbt.LazyCompoundTag_1_14; import com.boydti.fawe.bukkit.adapter.mc1_14.nbt.LazyCompoundTag_1_14;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
@ -42,11 +39,13 @@ import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.LazyBaseEntity; import com.sk89q.worldedit.entity.LazyBaseEntity;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
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.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.*; import com.sk89q.worldedit.world.block.*;
import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityType;
@ -69,8 +68,10 @@ import org.bukkit.generator.ChunkGenerator;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Map; import java.util.Map;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -149,8 +150,8 @@ public final class FAWE_Spigot_v1_14_R4 extends CachedBukkitAdapter implements I
} }
@Override @Override
public <B extends BlockStateHolder<B>> boolean setBlock(Location location, B state, boolean notifyAndLight) { public Set<SideEffect> getSupportedSideEffects() {
return this.setBlock(location.getChunk(), location.getBlockX(), location.getBlockY(), location.getBlockZ(), state, notifyAndLight); return SideEffectSet.defaults().getSideEffectsToApply();
} }
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) { public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
@ -204,6 +205,12 @@ public final class FAWE_Spigot_v1_14_R4 extends CachedBukkitAdapter implements I
return true; return true;
} }
@Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
return new FAWEWorldNativeAccess_1_14(this,
new WeakReference<>(((CraftWorld) world).getHandle()));
}
@Nullable @Nullable
private static String getEntityId(Entity entity) { private static String getEntityId(Entity entity) {
MinecraftKey minecraftkey = EntityTypes.getName(entity.getEntityType()); MinecraftKey minecraftkey = EntityTypes.getName(entity.getEntityType());
@ -292,11 +299,6 @@ public final class FAWE_Spigot_v1_14_R4 extends CachedBukkitAdapter implements I
return material.getCraftBlockData(); return material.getCraftBlockData();
} }
@Override
public void notifyAndLightBlock(Location position, BlockState previousType) {
this.setBlock(position.getChunk(), position.getBlockX(), position.getBlockY(), position.getBlockZ(), previousType, true);
}
private MapChunkUtil_1_14 mapUtil = new MapChunkUtil_1_14(); private MapChunkUtil_1_14 mapUtil = new MapChunkUtil_1_14();
@Override @Override

View File

@ -26,10 +26,7 @@ import com.boydti.fawe.beta.IQueueChunk;
import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.implementation.packet.ChunkPacket; import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
import com.boydti.fawe.beta.implementation.queue.SingleThreadQueueExtent; import com.boydti.fawe.beta.implementation.queue.SingleThreadQueueExtent;
import com.boydti.fawe.bukkit.adapter.mc1_15_2.BlockMaterial_1_15_2; import com.boydti.fawe.bukkit.adapter.mc1_15_2.*;
import com.boydti.fawe.bukkit.adapter.mc1_15_2.BukkitAdapter_1_15_2;
import com.boydti.fawe.bukkit.adapter.mc1_15_2.BukkitGetBlocks_1_15_2;
import com.boydti.fawe.bukkit.adapter.mc1_15_2.MapChunkUtil_1_15_2;
import com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt.LazyCompoundTag_1_15_2; import com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt.LazyCompoundTag_1_15_2;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
@ -44,9 +41,12 @@ import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.LazyBaseEntity; import com.sk89q.worldedit.entity.LazyBaseEntity;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
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.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
@ -71,8 +71,10 @@ import org.bukkit.generator.ChunkGenerator;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Map; import java.util.Map;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@ -158,11 +160,11 @@ public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements I
} }
@Override @Override
public <B extends BlockStateHolder<B>> boolean setBlock(Location location, B state, boolean notifyAndLight) { public Set<SideEffect> getSupportedSideEffects() {
return this.setBlock(location.getChunk(), location.getBlockX(), location.getBlockY(), location.getBlockZ(), state, notifyAndLight); return SideEffectSet.defaults().getSideEffectsToApply();
} }
public <B extends BlockStateHolder<B>> boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, B state, boolean update) { public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
CraftChunk craftChunk = (CraftChunk) chunk; CraftChunk craftChunk = (CraftChunk) chunk;
Chunk nmsChunk = craftChunk.getHandle(); Chunk nmsChunk = craftChunk.getHandle();
World nmsWorld = nmsChunk.getWorld(); World nmsWorld = nmsChunk.getWorld();
@ -213,6 +215,12 @@ public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements I
return true; return true;
} }
@Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
return new FAWEWorldNativeAccess_1_15_2(this,
new WeakReference<>(((CraftWorld) world).getHandle()));
}
@Nullable @Nullable
private static String getEntityId(Entity entity) { private static String getEntityId(Entity entity) {
MinecraftKey minecraftkey = EntityTypes.getName(entity.getEntityType()); MinecraftKey minecraftkey = EntityTypes.getName(entity.getEntityType());
@ -301,11 +309,6 @@ public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements I
return material.getCraftBlockData(); return material.getCraftBlockData();
} }
@Override
public void notifyAndLightBlock(Location position, BlockState previousType) {
this.setBlock(position.getChunk(), position.getBlockX(), position.getBlockY(), position.getBlockZ(), previousType, true);
}
private MapChunkUtil_1_15_2 mapUtil = new MapChunkUtil_1_15_2(); private MapChunkUtil_1_15_2 mapUtil = new MapChunkUtil_1_15_2();
@Override @Override

View File

@ -26,11 +26,8 @@ import com.boydti.fawe.beta.IQueueChunk;
import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.implementation.packet.ChunkPacket; import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
import com.boydti.fawe.beta.implementation.queue.SingleThreadQueueExtent; import com.boydti.fawe.beta.implementation.queue.SingleThreadQueueExtent;
import com.boydti.fawe.bukkit.adapter.mc1_15.BlockMaterial_1_15; import com.boydti.fawe.bukkit.adapter.mc1_16_1.*;
import com.boydti.fawe.bukkit.adapter.mc1_15.BukkitAdapter_1_15; import com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt.LazyCompoundTag_1_16_1;
import com.boydti.fawe.bukkit.adapter.mc1_15.BukkitGetBlocks_1_15;
import com.boydti.fawe.bukkit.adapter.mc1_15.MapChunkUtil_1_15;
import com.boydti.fawe.bukkit.adapter.mc1_15.nbt.LazyCompoundTag_1_15;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
@ -44,35 +41,39 @@ import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.LazyBaseEntity; import com.sk89q.worldedit.entity.LazyBaseEntity;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
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.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.*; import com.sk89q.worldedit.world.block.*;
import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockMaterial;
import net.minecraft.server.v1_15_R1.*; import net.minecraft.server.v1_16_R1.*;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World.Environment; import org.bukkit.World.Environment;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_15_R1.CraftChunk; import org.bukkit.craftbukkit.v1_16_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_15_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_16_R1.block.CraftBlock;
import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_16_R1.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_16_R1.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_16_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_16_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Map; import java.util.Map;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@ -81,16 +82,16 @@ import java.util.stream.Stream;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
public final class FAWE_Spigot_v1_15_R1 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<NBTBase> { public final class FAWE_Spigot_v1_16_R1 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<NBTBase> {
private final Spigot_v1_15_R1 parent; private final Spigot_v1_16_R1 parent;
private char[] ibdToStateOrdinal; private char[] ibdToStateOrdinal;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Code that may break between versions of Minecraft // Code that may break between versions of Minecraft
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
public FAWE_Spigot_v1_15_R1() throws NoSuchFieldException, NoSuchMethodException { public FAWE_Spigot_v1_16_R1() throws NoSuchFieldException, NoSuchMethodException {
this.parent = new Spigot_v1_15_R1(); this.parent = new Spigot_v1_16_R1();
} }
@Override @Override
@ -99,11 +100,11 @@ public final class FAWE_Spigot_v1_15_R1 extends CachedBukkitAdapter implements I
} }
private synchronized boolean init() { private synchronized boolean init() {
if (ibdToStateOrdinal != null) return false; if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) return false;
ibdToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size ibdToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size
for (int i = 0; i < ibdToStateOrdinal.length; i++) { for (int i = 0; i < ibdToStateOrdinal.length; i++) {
BlockState state = BlockTypesCache.states[i]; BlockState state = BlockTypesCache.states[i];
BlockMaterial_1_15 material = (BlockMaterial_1_15) state.getMaterial(); BlockMaterial_1_16_1 material = (BlockMaterial_1_16_1) state.getMaterial();
int id = Block.REGISTRY_ID.getId(material.getState()); int id = Block.REGISTRY_ID.getId(material.getState());
ibdToStateOrdinal[id] = state.getOrdinalChar(); ibdToStateOrdinal[id] = state.getOrdinalChar();
} }
@ -113,13 +114,15 @@ public final class FAWE_Spigot_v1_15_R1 extends CachedBukkitAdapter implements I
@Override @Override
public BlockMaterial getMaterial(BlockType blockType) { public BlockMaterial getMaterial(BlockType blockType) {
Block block = getBlock(blockType); Block block = getBlock(blockType);
return new BlockMaterial_1_15(block); return new BlockMaterial_1_16_1(block);
} }
@Override @Override
public BlockMaterial getMaterial(BlockState state) { public BlockMaterial getMaterial(BlockState state) {
IBlockData bs = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState(); IBlockData bs = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState();
return new BlockMaterial_1_15(bs.getBlock(), bs); return new BlockMaterial_1_16_1(bs.getBlock(), bs);
} }
public Block getBlock(BlockType blockType) { public Block getBlock(BlockType blockType) {
@ -156,24 +159,24 @@ public final class FAWE_Spigot_v1_15_R1 extends CachedBukkitAdapter implements I
} }
@Override @Override
public <B extends BlockStateHolder<B>> boolean setBlock(Location location, B state, boolean notifyAndLight) { public Set<SideEffect> getSupportedSideEffects() {
return this.setBlock(location.getChunk(), location.getBlockX(), location.getBlockY(), location.getBlockZ(), state, notifyAndLight); return SideEffectSet.defaults().getSideEffectsToApply();
} }
public <B extends BlockStateHolder<B>> boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, B state, boolean update) { public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
CraftChunk craftChunk = (CraftChunk) chunk; CraftChunk craftChunk = (CraftChunk) chunk;
Chunk nmsChunk = craftChunk.getHandle(); Chunk nmsChunk = craftChunk.getHandle();
World nmsWorld = nmsChunk.getWorld(); World nmsWorld = nmsChunk.getWorld();
BlockPosition blockPos = new BlockPosition(x, y, z); BlockPosition blockPos = new BlockPosition(x, y, z);
IBlockData blockData = ((BlockMaterial_1_15) state.getMaterial()).getState(); IBlockData blockData = ((BlockMaterial_1_16_1) state.getMaterial()).getState();
ChunkSection[] sections = nmsChunk.getSections(); ChunkSection[] sections = nmsChunk.getSections();
int y4 = y >> 4; int y4 = y >> 4;
ChunkSection section = sections[y4]; ChunkSection section = sections[y4];
IBlockData existing; IBlockData existing;
if (section == null) { if (section == null) {
existing = ((BlockMaterial_1_15) BlockTypes.AIR.getDefaultState().getMaterial()).getState(); existing = ((BlockMaterial_1_16_1) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
} else { } else {
existing = section.getType(x & 15, y & 15, z & 15); existing = section.getType(x & 15, y & 15, z & 15);
} }
@ -194,7 +197,7 @@ public final class FAWE_Spigot_v1_15_R1 extends CachedBukkitAdapter implements I
tag.set("x", NBTTagInt.a(x)); tag.set("x", NBTTagInt.a(x));
tag.set("y", NBTTagInt.a(y)); tag.set("y", NBTTagInt.a(y));
tag.set("z", NBTTagInt.a(z)); tag.set("z", NBTTagInt.a(z));
tileEntity.load(tag); // readTagIntoTileEntity - load data tileEntity.load(tileEntity.getBlock(), tag); // readTagIntoTileEntity - load data
} }
} }
} else { } else {
@ -211,6 +214,12 @@ public final class FAWE_Spigot_v1_15_R1 extends CachedBukkitAdapter implements I
return true; return true;
} }
@Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
return new FAWEWorldNativeAccess_1_16(this,
new WeakReference<>(((CraftWorld)world).getHandle()));
}
@Nullable @Nullable
private static String getEntityId(Entity entity) { private static String getEntityId(Entity entity) {
MinecraftKey minecraftkey = EntityTypes.getName(entity.getEntityType()); MinecraftKey minecraftkey = EntityTypes.getName(entity.getEntityType());
@ -245,7 +254,7 @@ public final class FAWE_Spigot_v1_15_R1 extends CachedBukkitAdapter implements I
@Override @Override
public OptionalInt getInternalBlockStateId(BlockState state) { public OptionalInt getInternalBlockStateId(BlockState state) {
BlockMaterial_1_15 material = (BlockMaterial_1_15) state.getMaterial(); BlockMaterial_1_16_1 material = (BlockMaterial_1_16_1) state.getMaterial();
IBlockData mcState = material.getCraftBlockData().getState(); IBlockData mcState = material.getCraftBlockData().getState();
return OptionalInt.of(Block.REGISTRY_ID.getId(mcState)); return OptionalInt.of(Block.REGISTRY_ID.getId(mcState));
} }
@ -286,7 +295,7 @@ public final class FAWE_Spigot_v1_15_R1 extends CachedBukkitAdapter implements I
} catch (NullPointerException e) { } catch (NullPointerException e) {
init(); init();
return adaptToChar(ibd); return adaptToChar(ibd);
} catch (ArrayIndexOutOfBoundsException e1) { } catch(ArrayIndexOutOfBoundsException e1){
Fawe.debug("Attempted to convert " + ibd.getBlock() + " with ID " + Block.REGISTRY_ID.getId(ibd) + " to char. ibdToStateOrdinal length: " + ibdToStateOrdinal.length + ". Defaulting to air!"); Fawe.debug("Attempted to convert " + ibd.getBlock() + " with ID " + Block.REGISTRY_ID.getId(ibd) + " to char. ibdToStateOrdinal length: " + ibdToStateOrdinal.length + ". Defaulting to air!");
return 0; return 0;
} }
@ -295,21 +304,16 @@ public final class FAWE_Spigot_v1_15_R1 extends CachedBukkitAdapter implements I
@Override @Override
public <B extends BlockStateHolder<B>> BlockData adapt(B state) { public <B extends BlockStateHolder<B>> BlockData adapt(B state) {
BlockMaterial_1_15 material = (BlockMaterial_1_15) state.getMaterial(); BlockMaterial_1_16_1 material = (BlockMaterial_1_16_1) state.getMaterial();
return material.getCraftBlockData(); return material.getCraftBlockData();
} }
@Override private MapChunkUtil_1_16_1 mapUtil = new MapChunkUtil_1_16_1();
public void notifyAndLightBlock(Location position, BlockState previousType) {
this.setBlock(position.getChunk(), position.getBlockX(), position.getBlockY(), position.getBlockZ(), previousType, true);
}
private MapChunkUtil_1_15 mapUtil = new MapChunkUtil_1_15();
@Override @Override
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet) { public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet) {
WorldServer nmsWorld = ((CraftWorld) world).getHandle(); WorldServer nmsWorld = ((CraftWorld) world).getHandle();
PlayerChunk map = BukkitAdapter_1_15.getPlayerChunk(nmsWorld, packet.getChunkX(), packet.getChunkZ()); PlayerChunk map = BukkitAdapter_1_16_1.getPlayerChunk(nmsWorld, packet.getChunkX(), packet.getChunkZ());
if (map != null && map.hasBeenLoaded()) { if (map != null && map.hasBeenLoaded()) {
boolean flag = false; boolean flag = false;
PlayerChunk.d players = map.players; PlayerChunk.d players = map.players;
@ -362,91 +366,93 @@ public final class FAWE_Spigot_v1_15_R1 extends CachedBukkitAdapter implements I
@Override @Override
public NBTBase fromNative(Tag foreign) { public NBTBase fromNative(Tag foreign) {
if (foreign instanceof LazyCompoundTag_1_15) { if (foreign instanceof LazyCompoundTag_1_16_1) {
return ((LazyCompoundTag_1_15) foreign).get(); return ((LazyCompoundTag_1_16_1) foreign).get();
} }
return parent.fromNative(foreign); return parent.fromNative(foreign);
} }
@Override @Override
public boolean regenerate(org.bukkit.World world, Region region, EditSession editSession) { public boolean regenerate(org.bukkit.World world, Region region, EditSession editSession) {
WorldServer originalWorld = ((CraftWorld) world).getHandle(); // WorldServer originalWorld = ((CraftWorld) world).getHandle();
ChunkProviderServer provider = originalWorld.getChunkProvider(); // ChunkProviderServer provider = originalWorld.getChunkProvider();
if (!(provider instanceof ChunkProviderServer)) { // if (!(provider instanceof ChunkProviderServer)) {
return false; // return false;
} // }
//
// File saveFolder = Files.createTempDir();
// // register this just in case something goes wrong
// // normally it should be deleted at the end of this method
// saveFolder.deleteOnExit();
// try {
// MinecraftServer server = originalWorld.getServer().getServer();
// Convertable.ConversionSession originalDataManager = server.convertable;
//// Convertable.ConversionSession saveHandler = new Convertable.ConversionSession(world.getName(), world.);
// WorldData newWorldData = new WorldData(originalWorld.worldData.a((NBTTagCompound) null),
// server.dataConverterManager, getDataVersion(), null);
// newWorldData.setName(UUID.randomUUID().toString());
//
// ChunkGenerator gen = world.getGenerator();
// Environment env = world.getEnvironment();
// try (WorldServer freshWorld = new WorldServer(server,
// server.executorService, originalDataManager,
// newWorldData,
// originalWorld.worldProvider.getDimensionManager(),
// originalWorld.getMethodProfiler(),
// server.worldLoadListenerFactory.create(11),
// env,
// gen){
// @Override
// public boolean addEntityChunk(Entity entity) {
// //Fixes #320; Prevent adding entities so we aren't attempting to spawn them asynchronously
// return false;
// }
// }) {
//
// // Pre-gen all the chunks
// // We need to also pull one more chunk in every direction
// Fawe.get().getQueueHandler().startSet(true);
// try {
// IQueueExtent<IQueueChunk> extent = new SingleThreadQueueExtent();
// extent.init(null, (x, z) -> new BukkitGetBlocks_1_16_1(freshWorld, x, z) {
// @Override
// public Chunk ensureLoaded(World nmsWorld, int X, int Z) {
// Chunk cached = nmsWorld.getChunkIfLoaded(X, Z);
// if (cached != null) return cached;
// Future<Chunk> future = Fawe.get().getQueueHandler().sync((Supplier<Chunk>) () -> freshWorld.getChunkAt(X, Z));
// while (!future.isDone()) {
// // this feels so dirty
// freshWorld.getChunkProvider().runTasks();
// }
// try {
// return future.get();
// } catch (InterruptedException | ExecutionException e) {
// throw new RuntimeException(e);
// }
// }
// }, null);
// for (BlockVector3 vec : region) {
// editSession.setBlock(vec, extent.getFullBlock(vec));
// }
// } finally {
// Fawe.get().getQueueHandler().endSet(true);
// }
// } catch (IOException e) {
// throw new RuntimeException(e);
// }
// } catch (MaxChangedBlocksException e) {
// throw new RuntimeException(e);
// } finally {
// saveFolder.delete();
// }
// return true;
File saveFolder = Files.createTempDir(); return false; //TODO: rework or remove for 1.16
// register this just in case something goes wrong
// normally it should be deleted at the end of this method
saveFolder.deleteOnExit();
try {
MinecraftServer server = originalWorld.getServer().getServer();
WorldNBTStorage originalDataManager = originalWorld.getDataManager();
WorldNBTStorage saveHandler = new WorldNBTStorage(saveFolder, originalDataManager.getDirectory().getName(), server, originalDataManager.getDataFixer());
WorldData newWorldData = new WorldData(originalWorld.worldData.a((NBTTagCompound) null),
server.dataConverterManager, getDataVersion(), null);
newWorldData.setName(UUID.randomUUID().toString());
ChunkGenerator gen = world.getGenerator();
Environment env = world.getEnvironment();
try (WorldServer freshWorld = new WorldServer(server,
server.executorService, saveHandler,
newWorldData,
originalWorld.worldProvider.getDimensionManager(),
originalWorld.getMethodProfiler(),
server.worldLoadListenerFactory.create(11),
env,
gen){
@Override
public boolean addEntityChunk(net.minecraft.server.v1_15_R1.Entity entity) {
//Fixes #320; Prevent adding entities so we aren't attempting to spawn them asynchronously
return false;
}
}) {
// Pre-gen all the chunks
// We need to also pull one more chunk in every direction
Fawe.get().getQueueHandler().startSet(true);
try {
IQueueExtent<IQueueChunk> extent = new SingleThreadQueueExtent();
extent.init(null, (x, z) -> new BukkitGetBlocks_1_15(freshWorld, x, z) {
@Override
public Chunk ensureLoaded(World nmsWorld, int X, int Z) {
Chunk cached = nmsWorld.getChunkIfLoaded(X, Z);
if (cached != null) return cached;
Future<Chunk> future = Fawe.get().getQueueHandler().sync((Supplier<Chunk>) () -> freshWorld.getChunkAt(X, Z));
while (!future.isDone()) {
// this feels so dirty
freshWorld.getChunkProvider().runTasks();
}
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
}, null);
for (BlockVector3 vec : region) {
editSession.setBlock(vec, extent.getFullBlock(vec));
}
} finally {
Fawe.get().getQueueHandler().endSet(true);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
} catch (MaxChangedBlocksException e) {
throw new RuntimeException(e);
} finally {
saveFolder.delete();
}
return true;
} }
@Override @Override
public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) {
return new BukkitGetBlocks_1_15(world, chunkX, chunkZ); return new BukkitGetBlocks_1_16_1(world, chunkX, chunkZ);
} }
@Override @Override

View File

@ -19,10 +19,12 @@
package com.sk89q.worldedit.cli; package com.sk89q.worldedit.cli;
import com.google.common.collect.ImmutableSet;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.AbstractPlatform; import com.sk89q.worldedit.extension.platform.AbstractPlatform;
import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Preference; import com.sk89q.worldedit.extension.platform.Preference;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.entity.EntityTypes;
@ -33,6 +35,7 @@ import java.util.ArrayList;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@ -153,6 +156,11 @@ class CLIPlatform extends AbstractPlatform {
return capabilities; return capabilities;
} }
@Override
public Set<SideEffect> getSupportedSideEffects() {
return ImmutableSet.of();
}
public void addWorld(World world) { public void addWorld(World world) {
worlds.add(world); worlds.add(world);
} }

View File

@ -19,6 +19,7 @@
package com.sk89q.worldedit.cli.schematic; package com.sk89q.worldedit.cli.schematic;
import com.google.common.collect.ImmutableSet;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
@ -34,6 +35,8 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
@ -46,6 +49,7 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -74,15 +78,14 @@ public class ClipboardWorld extends AbstractWorld implements Clipboard, CLIWorld
} }
@Override @Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException {
throws WorldEditException {
dirty = true; dirty = true;
return clipboard.setBlock(position, block); return clipboard.setBlock(position, block);
} }
@Override @Override
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException { public Set<SideEffect> applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet) throws WorldEditException {
return false; return ImmutableSet.of();
} }
@Override @Override

View File

@ -305,7 +305,7 @@ public class Fawe {
br.close(); br.close();
this.version = FaweVersion.tryParse(versionString, commitString, dateString); this.version = FaweVersion.tryParse(versionString, commitString, dateString);
Settings.IMP.DATE = new Date(100 + version.year, version.month, version.day).toGMTString(); Settings.IMP.DATE = new Date(100 + version.year, version.month, version.day).toGMTString();
Settings.IMP.BUILD = "https://ci.athion.net/job/FastAsyncWorldEdit-1.15/" + version.build; Settings.IMP.BUILD = "https://ci.athion.net/job/FastAsyncWorldEdit-1.16/" + version.build;
Settings.IMP.COMMIT = "https://github.com/IntellectualSites/FastAsyncWorldEdit/commit/" + Integer.toHexString(version.hash); Settings.IMP.COMMIT = "https://github.com/IntellectualSites/FastAsyncWorldEdit/commit/" + Integer.toHexString(version.hash);
} catch (Throwable ignore) {} } catch (Throwable ignore) {}
try { try {

View File

@ -1,7 +1,6 @@
package com.boydti.fawe; package com.boydti.fawe;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
import com.boydti.fawe.beta.IChunkSet; import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.Trimable; import com.boydti.fawe.beta.Trimable;
@ -9,6 +8,7 @@ import com.boydti.fawe.beta.implementation.queue.Pool;
import com.boydti.fawe.beta.implementation.queue.QueuePool; import com.boydti.fawe.beta.implementation.queue.QueuePool;
import com.boydti.fawe.config.Settings; import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.collection.BitArray; import com.boydti.fawe.object.collection.BitArray;
import com.boydti.fawe.object.collection.BitArrayUnstretched;
import com.boydti.fawe.object.collection.CleanableThreadLocal; import com.boydti.fawe.object.collection.CleanableThreadLocal;
import com.boydti.fawe.object.collection.VariableThreadLocal; import com.boydti.fawe.object.collection.VariableThreadLocal;
import com.boydti.fawe.object.exception.FaweBlockBagException; import com.boydti.fawe.object.exception.FaweBlockBagException;
@ -299,6 +299,102 @@ public enum FaweCache implements Trimable {
} }
} }
/**
* Convert raw int array to unstretched palette (1.16)
* @param layerOffset
* @param blocks
* @return palette
*/
public Palette toPaletteUnstretched(int layerOffset, char[] blocks) {
return toPaletteUnstretched(layerOffset, null, blocks);
}
/**
* Convert raw int array to unstretched palette (1.16)
* @param layerOffset
* @param blocks
* @return palette
*/
public Palette toPaletteUnstretched(int layerOffset, int[] blocks) {
return toPaletteUnstretched(layerOffset, blocks, null);
}
private Palette toPaletteUnstretched(int layerOffset, int[] blocksInts, char[] blocksChars) {
int[] blockToPalette = BLOCK_TO_PALETTE.get();
int[] paletteToBlock = PALETTE_TO_BLOCK.get();
long[] blockStates = BLOCK_STATES.get();
int[] blocksCopy = SECTION_BLOCKS.get();
try {
int num_palette = 0;
int blockIndexStart = layerOffset << 12;
int blockIndexEnd = blockIndexStart + 4096;
if (blocksChars != null) {
for (int i = blockIndexStart, j = 0; i < blockIndexEnd; i++, j++) {
int ordinal = blocksChars[i];
int palette = blockToPalette[ordinal];
if (palette == Integer.MAX_VALUE) {
blockToPalette[ordinal] = palette = num_palette;
paletteToBlock[num_palette] = ordinal;
num_palette++;
}
blocksCopy[j] = palette;
}
} else if (blocksInts != null) {
for (int i = blockIndexStart, j = 0; i < blockIndexEnd; i++, j++) {
int ordinal = blocksInts[i];
int palette = blockToPalette[ordinal];
if (palette == Integer.MAX_VALUE) {
// BlockState state = BlockTypesCache.states[ordinal];
blockToPalette[ordinal] = palette = num_palette;
paletteToBlock[num_palette] = ordinal;
num_palette++;
}
blocksCopy[j] = palette;
}
} else {
throw new IllegalArgumentException();
}
for (int i = 0; i < num_palette; i++) {
blockToPalette[paletteToBlock[i]] = Integer.MAX_VALUE;
}
// BlockStates
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) {
bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry
} else {
bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries
}
int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntry);
int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong);
if (num_palette == 1) {
// Set a value, because minecraft needs it for some reason
blockStates[0] = 0;
blockBitArrayEnd = 1;
} else {
BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntry, blockStates);
bitArray.fromRaw(blocksCopy);
}
// Construct palette
Palette palette = PALETTE_CACHE.get();
palette.bitsPerEntry = bitsPerEntry;
palette.paletteToBlockLength = num_palette;
palette.paletteToBlock = paletteToBlock;
palette.blockStatesLength = blockBitArrayEnd;
palette.blockStates = blockStates;
return palette;
} catch (Throwable e) {
e.printStackTrace();
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
throw e;
}
}
/* /*
* Vector cache * Vector cache
*/ */

View File

@ -32,9 +32,9 @@ public class FaweVersion {
@Override public String toString() { @Override public String toString() {
if (hash == 0 && build == 0) { if (hash == 0 && build == 0) {
return "FastAsyncWorldEdit-1.15-NoVer-SNAPSHOT"; return "FastAsyncWorldEdit-1.16-NoVer-SNAPSHOT";
} else { } else {
return "FastAsyncWorldEdit-1.15" + build; return "FastAsyncWorldEdit-1.16" + build;
} }
} }

View File

@ -41,4 +41,8 @@ public interface IFawe {
Preloader getPreloader(); Preloader getPreloader();
default boolean isChunksStretched() {
return true;
}
} }

View File

@ -45,11 +45,11 @@ public interface IBlocks extends Trimable {
IBlocks reset(); IBlocks reset();
default byte[] toByteArray(boolean full) { default byte[] toByteArray(boolean full, boolean stretched) {
return toByteArray(null, getBitMask(), full); return toByteArray(null, getBitMask(), full, stretched);
} }
default byte[] toByteArray(byte[] buffer, int bitMask, boolean full) { default byte[] toByteArray(byte[] buffer, int bitMask, boolean full, boolean stretched) {
if (buffer == null) { if (buffer == null) {
buffer = new byte[1024]; buffer = new byte[1024];
} }
@ -81,7 +81,12 @@ public interface IBlocks extends Trimable {
} }
sectionWriter.writeShort(nonEmpty); // non empty sectionWriter.writeShort(nonEmpty); // non empty
FaweCache.Palette palette = FaweCache.IMP.toPalette(0, ids); FaweCache.Palette palette;
if (stretched) {
palette = FaweCache.IMP.toPalette(0, ids);
} else {
palette = FaweCache.IMP.toPaletteUnstretched(0, ids);
}
sectionWriter.writeByte(palette.bitsPerEntry); // bits per block sectionWriter.writeByte(palette.bitsPerEntry); // bits per block
sectionWriter.writeVarInt(palette.paletteToBlockLength); sectionWriter.writeVarInt(palette.paletteToBlockLength);

View File

@ -181,6 +181,18 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
} }
@Override public void setFullBright(int layer) { @Override public void setFullBright(int layer) {
if (light == null) {
light = new char[16][];
}
if (light[layer] == null) {
light[layer] = new char[4096];
}
if (skyLight == null) {
skyLight = new char[16][];
}
if (skyLight[layer] == null) {
skyLight[layer] = new char[4096];
}
Arrays.fill(light[layer], (char) 15); Arrays.fill(light[layer], (char) 15);
Arrays.fill(skyLight[layer], (char) 15); Arrays.fill(skyLight[layer], (char) 15);
} }

View File

@ -1,10 +1,12 @@
package com.boydti.fawe.beta.implementation.packet; package com.boydti.fawe.beta.implementation.packet;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache; import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBlocks; import com.boydti.fawe.beta.IBlocks;
import com.boydti.fawe.object.FaweOutputStream; import com.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.object.io.FastByteArrayOutputStream; import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEdit;
import java.util.HashMap; import java.util.HashMap;
import java.util.function.Function; import java.util.function.Function;
@ -64,7 +66,7 @@ public class ChunkPacket implements Function<byte[], byte[]>, Supplier<byte[]> {
if (sectionBytes == null) { if (sectionBytes == null) {
IBlocks tmpChunk = getChunk(); IBlocks tmpChunk = getChunk();
byte[] buf = FaweCache.IMP.BYTE_BUFFER_8192.get(); byte[] buf = FaweCache.IMP.BYTE_BUFFER_8192.get();
sectionBytes = tmpChunk.toByteArray(buf, tmpChunk.getBitMask(), this.full); sectionBytes = tmpChunk.toByteArray(buf, tmpChunk.getBitMask(), this.full, Fawe.imp().isChunksStretched());
} }
tmp = sectionBytes; tmp = sectionBytes;
} }
@ -72,6 +74,7 @@ public class ChunkPacket implements Function<byte[], byte[]>, Supplier<byte[]> {
return tmp; return tmp;
} }
public Object getNativePacket() { public Object getNativePacket() {
return nativePacket; return nativePacket;
} }

View File

@ -13,12 +13,16 @@ import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.File; import java.io.File;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
@ -35,6 +39,11 @@ public class MCAWorld extends AbstractWorld {
return path.getName(); return path.getName();
} }
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException {
return false;
}
@Override @Override
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
@ -46,6 +55,11 @@ public class MCAWorld extends AbstractWorld {
return false; return false;
} }
@Override
public Set<SideEffect> applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet) throws WorldEditException {
return SideEffectSet.none().getSideEffectsToApply();
}
@Override @Override
public boolean clearContainerBlockContents(BlockVector3 position) { public boolean clearContainerBlockContents(BlockVector3 position) {
return false; return false;

View File

@ -31,7 +31,8 @@ public class CopyPastaBrush implements Brush, ResettableTool {
private final LocalSession session; private final LocalSession session;
private final Player player; private final Player player;
public boolean autoRotate, randomRotate; public boolean autoRotate;
public boolean randomRotate;
public CopyPastaBrush(Player player, LocalSession session, boolean randomRotate, boolean autoRotate) { public CopyPastaBrush(Player player, LocalSession session, boolean randomRotate, boolean autoRotate) {
session.setClipboard(null); session.setClipboard(null);

View File

@ -29,10 +29,7 @@ import com.boydti.fawe.util.TextureUtil;
import com.boydti.fawe.util.image.Drawable; import com.boydti.fawe.util.image.Drawable;
import com.boydti.fawe.util.image.ImageViewer; import com.boydti.fawe.util.image.ImageViewer;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.*;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
@ -48,9 +45,7 @@ import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Identifiable; import com.sk89q.worldedit.util.*;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator;
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.biome.BiomeTypes;
@ -68,6 +63,7 @@ import java.lang.reflect.Field;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -750,12 +746,24 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
return BlockVector3.at(getWidth() - 1, 255, getLength() - 1); return BlockVector3.at(getWidth() - 1, 255, getLength() - 1);
} }
@Override
public Set<SideEffect> applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet)
throws WorldEditException{
return SideEffectSet.none().getSideEffectsToApply();
}
@Override @Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block) public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block)
throws WorldEditException { throws WorldEditException {
return setBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ(), block); return setBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ(), block);
} }
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects)
throws WorldEditException {
return setBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ(), block);
}
private boolean setBlock(int x, int y, int z, char combined) { private boolean setBlock(int x, int y, int z, char combined) {
int index = z * getWidth() + x; int index = z * getWidth() + x;
if (index < 0 || index >= getArea()) { if (index < 0 || index >= getArea()) {

View File

@ -0,0 +1,115 @@
package com.boydti.fawe.object.collection;
import com.boydti.fawe.util.MathMan;
public final class BitArrayUnstretched {
private final long[] data;
private final int bitsPerEntry;
private final int maxSeqLocIndex;
private final int emptyBitCount;
private final long mask;
private final int longLen;
public BitArrayUnstretched(int bitsPerEntry, long[] buffer) {
this.bitsPerEntry = bitsPerEntry;
this.mask = (1L << bitsPerEntry) - 1L;
this.emptyBitCount = 64 % bitsPerEntry;
this.maxSeqLocIndex = 64 - (bitsPerEntry + emptyBitCount);
final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntry);
this.longLen = MathMan.ceilZero((float) 4096 / blocksPerLong);
if (buffer.length < longLen) {
this.data = new long[longLen];
} else {
this.data = buffer;
}
}
public long[] getData() {
return data;
}
public final void set(int index, int value) {
if (longLen == 0) return;
int bitIndexStart = index * bitsPerEntry + MathMan.floorZero((double) index / longLen) * emptyBitCount;
int longIndexStart = bitIndexStart >> 6;
int localBitIndexStart = bitIndexStart & 63;
this.data[longIndexStart] = this.data[longIndexStart] & ~(mask << localBitIndexStart) | (long) value << localBitIndexStart;
}
public final int get(int index) {
if (longLen == 0) return 0;
int bitIndexStart = index * bitsPerEntry + MathMan.floorZero((double) index / longLen) * emptyBitCount;
int longIndexStart = bitIndexStart >> 6;
int localBitIndexStart = bitIndexStart & 63;
return (int)(this.data[longIndexStart] >>> localBitIndexStart & mask);
}
public int getLength() {
return longLen;
}
public final void fromRaw(int[] arr) {
final long[] data = this.data;
final int bitsPerEntry = this.bitsPerEntry;
final int maxSeqLocIndex = this.maxSeqLocIndex;
int localStart = 0;
int arrI = 0;
long l = 0;
for (int i = 0; i < longLen; i++) {
int lastVal;
for (; localStart <= maxSeqLocIndex && arrI < 4096; localStart += bitsPerEntry) {
lastVal = arr[arrI++];
l |= ((long) lastVal << localStart);
}
localStart = 0;
data[i] = l;
l = 0;
}
}
public final int[] toRaw() {
return toRaw(new int[4096]);
}
public final int[] toRaw(int[] buffer) {
final long[] data = this.data;
final int bitsPerEntry = this.bitsPerEntry;
final int maxSeqLocIndex = this.maxSeqLocIndex;
int localStart = 0;
int arrI = 0;
for (int i = 0; i < longLen; i++) {
long l = data[i];
char lastVal;
for (; localStart <= maxSeqLocIndex && arrI < 4096; localStart += bitsPerEntry) {
lastVal = (char) (l >>> localStart & this.mask);
buffer[arrI++] = lastVal;
}
localStart = 0;
}
return buffer;
}
public final char[] toRaw(char[] buffer) {
final long[] data = this.data;
final int bitsPerEntry = this.bitsPerEntry;
final int maxSeqLocIndex = this.maxSeqLocIndex;
int localStart = 0;
int arrI = 0;
for (int i = 0; i < longLen; i++) {
long l = data[i];
char lastVal;
for (; localStart <= maxSeqLocIndex && arrI < 4096; localStart += bitsPerEntry) {
lastVal = (char) (l >>> localStart & this.mask);
buffer[arrI++] = lastVal;
}
localStart = 0;
}
return buffer;
}
}

View File

@ -24,9 +24,7 @@ import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.*;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.AbstractWorld;
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;
@ -38,6 +36,7 @@ import com.sk89q.worldedit.world.weather.WeatherType;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List; import java.util.List;
import java.util.Set;
public class WorldWrapper extends AbstractWorld { public class WorldWrapper extends AbstractWorld {
@ -88,6 +87,12 @@ public class WorldWrapper extends AbstractWorld {
return parent.useItem(position, item, face); return parent.useItem(position, item, face);
} }
@Override
public Set<SideEffect> applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet)
throws WorldEditException{
return parent.applySideEffects(position, previousType, sideEffectSet);
}
@Override @Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException { public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException {
return parent.setBlock(position, block, notifyAndLight); return parent.setBlock(position, block, notifyAndLight);
@ -99,6 +104,11 @@ public class WorldWrapper extends AbstractWorld {
return parent.setBlock(x, y, z, block); return parent.setBlock(x, y, z, block);
} }
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException {
return parent.setBlock(position, block, sideEffects);
}
@Override @Override
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException { public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
return parent.setTile(x, y, z, tile); return parent.setTile(x, y, z, tile);

View File

@ -20,6 +20,7 @@
package com.sk89q.util; package com.sk89q.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -331,4 +332,37 @@ public final class StringUtil {
return parsableBlocks; return parsableBlocks;
} }
/**
* Splits a string respecting enclosing quotes.
*
* @param input the input to split.
* @param delimiter the delimiter to split on.
* @param open the opening quote character.
* @param close the closing quote character.
* @return a list of split strings.
*/
public static List<String> split(String input, char delimiter, char open, char close) {
if (input.indexOf(open) == -1 && input.indexOf(close) == -1) {
return Arrays.asList(input.split(String.valueOf(delimiter)));
}
int level = 0;
int begin = 0;
List<String> split = new ArrayList<>();
for (int i = 0; i < input.length(); i++) {
char c = input.charAt(i);
if (c == delimiter && level == 0) {
split.add(input.substring(begin, i));
begin = i + 1;
} else if (c == open) {
level++;
} else if (c == close) {
level--;
}
}
if (begin < input.length()) {
split.add(input.substring(begin));
}
return split;
}
} }

View File

@ -119,7 +119,7 @@ import com.sk89q.worldedit.regions.shape.RegionShape;
import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
@ -575,6 +575,20 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
disableHistory(enabled); disableHistory(enabled);
} }
/**
* Set which block updates should occur.
*
* @param sideEffectSet side effects to enable
*/
public void setSideEffectApplier(SideEffectSet sideEffectSet) {
//Do nothing; TODO: SideEffects currently not fully implemented in FAWE.
}
public SideEffectSet getSideEffectApplier() {
//Do nothing; TODO: SideEffects currently not fully implemented in FAWE.
return SideEffectSet.defaults();
}
/** /**
* Disable history (or re-enable) * Disable history (or re-enable)
* *

View File

@ -72,6 +72,7 @@ import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.Identifiable; import com.sk89q.worldedit.util.Identifiable;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
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;
@ -145,7 +146,7 @@ public class LocalSession implements TextureHolder {
private transient Snapshot snapshotExperimental; private transient Snapshot snapshotExperimental;
private transient boolean hasCUISupport = false; private transient boolean hasCUISupport = false;
private transient int cuiVersion = -1; private transient int cuiVersion = -1;
private transient boolean fastMode = false; private transient SideEffectSet sideEffectSet = SideEffectSet.defaults();
private transient Mask mask; private transient Mask mask;
private transient Mask sourceMask; private transient Mask sourceMask;
private transient TextureUtil texture; private transient TextureUtil texture;
@ -1494,7 +1495,7 @@ public class LocalSession implements TextureHolder {
builder.blockBag(blockBag); builder.blockBag(blockBag);
} }
builder.command(command); builder.command(command);
builder.fastmode(fastMode); builder.fastmode(!this.sideEffectSet.doesApplyAny());
editSession = builder.build(); editSession = builder.build();
@ -1513,7 +1514,7 @@ public class LocalSession implements TextureHolder {
} }
private void prepareEditingExtents(EditSession editSession, Actor actor) { private void prepareEditingExtents(EditSession editSession, Actor actor) {
editSession.setFastMode(fastMode); editSession.setSideEffectApplier(sideEffectSet);
editSession.setReorderMode(reorderMode); editSession.setReorderMode(reorderMode);
if (editSession.getSurvivalExtent() != null) { if (editSession.getSurvivalExtent() != null) {
editSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt")); editSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt"));
@ -1521,13 +1522,32 @@ public class LocalSession implements TextureHolder {
editSession.setTickingWatchdog(tickingWatchdog); editSession.setTickingWatchdog(tickingWatchdog);
} }
/**
* Gets the side effect applier of this session.
*
* @return the side effect applier
*/
public SideEffectSet getSideEffectSet() {
return this.sideEffectSet;
}
/**
* Sets the side effect applier for this session
*
* @param sideEffectSet the side effect applier
*/
public void setSideEffectSet(SideEffectSet sideEffectSet) {
this.sideEffectSet = sideEffectSet;
}
/** /**
* Checks if the session has fast mode enabled. * Checks if the session has fast mode enabled.
* *
* @return true if fast mode is enabled * @return true if fast mode is enabled
*/ */
@Deprecated
public boolean hasFastMode() { public boolean hasFastMode() {
return fastMode; return !this.sideEffectSet.doesApplyAny();
} }
/** /**
@ -1535,8 +1555,9 @@ public class LocalSession implements TextureHolder {
* *
* @param fastMode true if fast mode is enabled * @param fastMode true if fast mode is enabled
*/ */
@Deprecated
public void setFastMode(boolean fastMode) { public void setFastMode(boolean fastMode) {
this.fastMode = fastMode; this.sideEffectSet = fastMode ? SideEffectSet.none() : SideEffectSet.defaults();
} }
/** /**

View File

@ -49,10 +49,13 @@ import java.util.ArrayList;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.formatting.component.PaginationBox; import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.component.SideEffectBox;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -142,24 +145,62 @@ public class GeneralCommands {
@Command( @Command(
name = "/fast", name = "/fast",
desc = "Toggle fast mode" desc = "Toggle fast mode side effects"
) )
@CommandPermissions("worldedit.fast") @CommandPermissions("worldedit.fast")
public void fast(Actor actor, LocalSession session, public void fast(Actor actor, LocalSession session,
@Arg(desc = "The new fast mode state", def = "") @Arg(desc = "The side effect", def = "")
Boolean fastMode) { SideEffect sideEffect,
boolean hasFastMode = session.hasFastMode(); @Arg(desc = "The new side effect state", def = "")
if (fastMode != null && fastMode == hasFastMode) { SideEffect.State newState,
actor.printError(TranslatableComponent.of(fastMode ? "worldedit.fast.enabled.already" : "worldedit.fast.disabled.already")); @Switch(name = 'h', desc = "Show the info box")
return; boolean showInfoBox) throws WorldEditException {
if (sideEffect != null) {
SideEffect.State currentState = session.getSideEffectSet().getState(sideEffect);
if (newState != null && newState == currentState) {
if (!showInfoBox) {
actor.printError(TranslatableComponent.of(
"worldedit.fast.sideeffect.already-set",
TranslatableComponent.of(sideEffect.getDisplayName()),
TranslatableComponent.of(newState.getDisplayName())
));
}
return;
}
if (newState != null) {
session.setSideEffectSet(session.getSideEffectSet().with(sideEffect, newState));
if (!showInfoBox) {
actor.printInfo(TranslatableComponent.of(
"worldedit.fast.sideeffect.set",
TranslatableComponent.of(sideEffect.getDisplayName()),
TranslatableComponent.of(newState.getDisplayName())
));
}
} else {
actor.printInfo(TranslatableComponent.of(
"worldedit.fast.sideeffect.get",
TranslatableComponent.of(sideEffect.getDisplayName()),
TranslatableComponent.of(currentState.getDisplayName())
));
}
} else if (newState != null) {
SideEffectSet applier = session.getSideEffectSet();
for (SideEffect sideEffectEntry : SideEffect.values()) {
applier = applier.with(sideEffectEntry, newState);
}
session.setSideEffectSet(applier);
if (!showInfoBox) {
actor.printInfo(TranslatableComponent.of(
"worldedit.fast.sideeffect.set-all",
TranslatableComponent.of(newState.getDisplayName())
));
}
} }
if (hasFastMode) { if (sideEffect == null || showInfoBox) {
session.setFastMode(false); SideEffectBox sideEffectBox = new SideEffectBox(session.getSideEffectSet());
actor.printInfo(TranslatableComponent.of("worldedit.fast.disabled")); actor.print(sideEffectBox.create(1));
} else {
session.setFastMode(true);
actor.printInfo(TranslatableComponent.of("worldedit.fast.enabled"));
} }
} }

View File

@ -23,6 +23,7 @@ import com.boydti.fawe.object.brush.scroll.Scroll;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.command.util.HookMode; import com.sk89q.worldedit.command.util.HookMode;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
import org.enginehub.piston.CommandManager; import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter; import org.enginehub.piston.converter.ArgumentConverter;
@ -30,6 +31,7 @@ import org.enginehub.piston.converter.MultiKeyConverter;
import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.Key;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
@ -48,6 +50,11 @@ public final class EnumConverter {
full(EditSession.ReorderMode.class, full(EditSession.ReorderMode.class,
r -> ImmutableSet.of(r.getDisplayName()), r -> ImmutableSet.of(r.getDisplayName()),
null)); null));
commandManager.registerConverter(Key.of(SideEffect.State.class),
MultiKeyConverter.from(
EnumSet.of(SideEffect.State.OFF, SideEffect.State.ON),
r -> ImmutableSet.of(r.name().toLowerCase(Locale.US)),
null));
commandManager.registerConverter(Key.of(HookMode.class), commandManager.registerConverter(Key.of(HookMode.class),
basic(HookMode.class)); basic(HookMode.class));
commandManager.registerConverter(Key.of(Scroll.Action.class), commandManager.registerConverter(Key.of(Scroll.Action.class),

View File

@ -0,0 +1,75 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.EntityRemover;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.ConversionResult;
import org.enginehub.piston.converter.FailedConversion;
import org.enginehub.piston.converter.SuccessfulConversion;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
public class SideEffectConverter implements ArgumentConverter<SideEffect> {
public static void register(CommandManager commandManager) {
commandManager.registerConverter(Key.of(SideEffect.class), new SideEffectConverter());
}
private final TextComponent choices = TextComponent.of("any side effect");
private SideEffectConverter() {
}
private Collection<SideEffect> getSideEffects() {
return WorldEdit.getInstance().getPlatformManager().getSupportedSideEffects();
}
@Override
public Component describeAcceptableArguments() {
return choices;
}
@Override
public List<String> getSuggestions(String input, InjectedValueAccess context) {
return limitByPrefix(getSideEffects().stream().map(sideEffect -> sideEffect.name().toLowerCase(Locale.US)), input);
}
@Override
public ConversionResult<SideEffect> convert(String argument, InjectedValueAccess context) {
try {
return SuccessfulConversion.fromSingle(SideEffect.valueOf(argument.toUpperCase(Locale.US)));
} catch (Exception e) {
return FailedConversion.from(e);
}
}
}

View File

@ -58,8 +58,8 @@ public class BlockFactory extends AbstractFactory<BaseBlock> {
*/ */
public Set<BaseBlock> parseFromListInput(String input, ParserContext context) throws InputParseException { public Set<BaseBlock> parseFromListInput(String input, ParserContext context) throws InputParseException {
Set<BaseBlock> blocks = new HashSet<>(); Set<BaseBlock> blocks = new HashSet<>();
String[] splits = input.split(","); // String[] splits = input.split(",");
for (String token : StringUtil.parseListInQuotes(splits, ',', '[', ']', true)) { for (String token : StringUtil.split(input, ',', '[', ']')) {
blocks.add(parseFromInput(token, context)); blocks.add(parseFromInput(token, context));
} }
return blocks; return blocks;

View File

@ -24,6 +24,7 @@ import com.sk89q.worldedit.extension.factory.parser.pattern.BlockCategoryPattern
import com.sk89q.worldedit.extension.factory.parser.pattern.ClipboardPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.ClipboardPatternParser;
import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser;
import com.sk89q.worldedit.extension.factory.parser.pattern.RandomStatePatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.RandomStatePatternParser;
import com.sk89q.worldedit.extension.factory.parser.pattern.SimplexPatternParser;
import com.sk89q.worldedit.extension.factory.parser.pattern.SingleBlockPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.SingleBlockPatternParser;
import com.sk89q.worldedit.extension.factory.parser.pattern.TypeOrStateApplyingPatternParser; import com.sk89q.worldedit.extension.factory.parser.pattern.TypeOrStateApplyingPatternParser;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
@ -54,6 +55,9 @@ public final class PatternFactory extends AbstractFactory<Pattern> {
register(new TypeOrStateApplyingPatternParser(worldEdit)); register(new TypeOrStateApplyingPatternParser(worldEdit));
register(new RandomStatePatternParser(worldEdit)); register(new RandomStatePatternParser(worldEdit));
register(new BlockCategoryPatternParser(worldEdit)); register(new BlockCategoryPatternParser(worldEdit));
// FAWE
register(new SimplexPatternParser(worldEdit));
} }
} }

View File

@ -0,0 +1,118 @@
package com.sk89q.worldedit.extension.factory.parser;
import com.sk89q.util.StringUtil;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.internal.registry.InputParser;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;
import java.util.stream.Stream;
/**
* A rich parser allows parsing of patterns and masks with extra arguments,
* e.g. #simplex[scale][pattern].
*
* @param <E> the parse result.
*/
public abstract class RichParser<E> extends InputParser<E> {
private final String prefix;
private final String required;
/**
* Create a new rich parser with a defined prefix for the result, e.g. {@code #simplex}.
*
* @param worldEdit the worldedit instance.
* @param prefix the prefix of this parser result.
*/
protected RichParser(WorldEdit worldEdit, String prefix) {
super(worldEdit);
this.prefix = prefix;
this.required = prefix + "[";
}
@Override
public Stream<String> getSuggestions(String input) {
// we don't even want to start suggesting if it's not meant to be this parser result
if (input.length() > this.required.length() && !input.startsWith(this.required)) {
return Stream.empty();
}
// suggest until the first [ as long as it isn't fully typed
if (input.length() < this.required.length()) {
return Stream.of(this.required).filter(s -> s.startsWith(input));
}
// we know that it is at least "<required>"
String[] strings = extractArguments(input.substring(this.prefix.length()), false);
StringJoiner joiner = new StringJoiner(",");
for (int i = 0; i < strings.length - 1; i++) {
joiner.add("[" + strings[i] + "]");
}
String previous = this.prefix + joiner;
return getSuggestions(strings[strings.length - 1], strings.length - 1).map(s -> previous + "[" + s + "]");
}
@Override
public E parseFromInput(String input, ParserContext context) throws InputParseException {
if (!input.startsWith(this.prefix)) return null;
if (input.length() < this.prefix.length()) return null;
String[] arguments = extractArguments(input.substring(prefix.length()), true);
return parseFromInput(arguments, context);
}
/**
* Returns a stream of suggestions for the argument at the given index.
*
* @param argumentInput the already provided input for the argument at the given index.
* @param index the index of the argument to get suggestions for.
* @return a stream of suggestions matching the given input for the argument at the given index.
*/
protected abstract Stream<String> getSuggestions(String argumentInput, int index);
/**
* Parses the already split arguments.
*
* @param arguments the array of arguments that were split (can be empty).
* @param context the context of this parsing process.
* @return the resulting parsed type.
* @throws InputParseException if the input couldn't be parsed correctly.
*/
protected abstract E parseFromInput(@NotNull String[] arguments, ParserContext context) throws InputParseException;
/**
* Extracts arguments enclosed by {@code []} into an array.
* Example: {@code [Hello][World]} results in a list containing {@code Hello} and {@code World}.
*
* @param input the input to extract arguments from.
* @param requireClosing whether or not the extraction requires valid bracketing.
* @return an array of extracted arguments.
* @throws InputParseException if {@code requireClosing == true} and the count of [ != the count of ]
*/
protected String[] extractArguments(String input, boolean requireClosing) throws InputParseException {
int open = 0; // the "level"
int openIndex = 0;
int i = 0;
List<String> arguments = new ArrayList<>();
for (; i < input.length(); i++) {
if (input.charAt(i) == '[') {
if (open++ == 0) {
openIndex = i;
}
}
if (input.charAt(i) == ']') {
if (--open == 0) {
arguments.add(input.substring(openIndex + 1, i));
}
}
}
if (!requireClosing && open > 0) {
arguments.add(input.substring(openIndex + 1));
}
if (requireClosing && open != 0) {
throw new InputParseException("Invalid bracketing, are you missing a '[' or ']'?");
}
return arguments.toArray(new String[0]);
}
}

View File

@ -38,8 +38,9 @@ public class RandomPatternParser extends InputParser<Pattern> {
@Override @Override
public Stream<String> getSuggestions(String input) { public Stream<String> getSuggestions(String input) {
String[] splits = input.split(",", -1); List<String> patterns = StringUtil.split(input, ',', '[', ']');
List<String> patterns = StringUtil.parseListInQuotes(splits, ',', '[', ']', true); /*String[] splits = input.split(",", -1);
List<String> patterns = StringUtil.parseListInQuotes(splits, ',', '[', ']', true);*/
if (patterns.size() == 1) { if (patterns.size() == 1) {
return Stream.empty(); return Stream.empty();
} }
@ -63,8 +64,9 @@ public class RandomPatternParser extends InputParser<Pattern> {
public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { public Pattern parseFromInput(String input, ParserContext context) throws InputParseException {
RandomPattern randomPattern = new RandomPattern(); RandomPattern randomPattern = new RandomPattern();
String[] splits = input.split(",", -1); List<String> patterns = StringUtil.split(input, ',', '[', ']');
List<String> patterns = StringUtil.parseListInQuotes(splits, ',', '[', ']', true); /*String[] splits = input.split(",", -1);
List<String> patterns = StringUtil.parseListInQuotes(splits, ',', '[', ']', true);*/
if (patterns.size() == 1) { if (patterns.size() == 1) {
return null; // let a 'single'-pattern parser handle it return null; // let a 'single'-pattern parser handle it
} }
@ -74,7 +76,7 @@ public class RandomPatternParser extends InputParser<Pattern> {
// Parse special percentage syntax // Parse special percentage syntax
if (token.matches("[0-9]+(\\.[0-9]*)?%.*")) { if (token.matches("[0-9]+(\\.[0-9]*)?%.*")) {
String[] p = token.split("%"); String[] p = token.split("%", 2);
if (p.length < 2) { if (p.length < 2) {
throw new InputParseException("Missing the type after the % symbol for '" + input + "'"); throw new InputParseException("Missing the type after the % symbol for '" + input + "'");

View File

@ -0,0 +1,75 @@
package com.sk89q.worldedit.extension.factory.parser.pattern;
import com.boydti.fawe.object.random.SimplexRandom;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.factory.parser.RichParser;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.pattern.RandomPattern;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import org.jetbrains.annotations.NotNull;
import java.util.stream.Stream;
public class SimplexPatternParser extends RichParser<Pattern> {
private static final String SIMPLEX_PREFIX = "#simplex";
public SimplexPatternParser(WorldEdit worldEdit) {
super(worldEdit, SIMPLEX_PREFIX);
}
@Override
protected Stream<String> getSuggestions(String argumentInput, int index) {
if (index == 0) {
if (argumentInput.isEmpty()) {
return Stream.of("1", "2", "3", "4", "5", "6", "7", "8", "9");
}
// if already a valid number, suggest more digits
if (isDouble(argumentInput)) {
Stream<String> numbers = Stream.of("", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
if (argumentInput.indexOf('.') == -1) {
numbers = Stream.concat(numbers, Stream.of("."));
}
return numbers.map(s -> argumentInput + s);
}
// no valid input anymore
return Stream.empty();
}
if (index == 1) {
return worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
}
return Stream.empty();
}
@Override
protected Pattern parseFromInput(@NotNull String[] arguments, ParserContext context) {
if (arguments.length != 2) {
throw new InputParseException("Simplex requires a scale and a pattern, e.g. #simplex[5][dirt,stone]");
}
double scale = Double.parseDouble(arguments[0]);
scale = 1d / Math.max(1, scale);
Pattern inner = worldEdit.getPatternFactory().parseFromInput(arguments[1], context);
if (inner instanceof RandomPattern) {
return new RandomPattern(new SimplexRandom(scale), (RandomPattern) inner);
} else if (inner instanceof BlockStateHolder) {
return inner; // single blocks won't have any impact on how simplex behaves
} else {
throw new InputParseException("Pattern " + inner.getClass().getSimpleName() + " cannot be used with #simplex");
}
}
private static boolean isDouble(String input) {
boolean point = false;
for (char c : input.toCharArray()) {
if (!Character.isDigit(c)) {
if (c == '.' && !point) {
point = true;
} else {
return false;
}
}
}
return true;
}
}

View File

@ -21,14 +21,17 @@ package com.sk89q.worldedit.extension.platform;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.registry.Registries; import com.sk89q.worldedit.world.registry.Registries;
import org.enginehub.piston.CommandManager; import org.enginehub.piston.CommandManager;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* Represents a platform that WorldEdit has been implemented for. * Represents a platform that WorldEdit has been implemented for.
@ -174,4 +177,5 @@ public interface Platform {
*/ */
Map<Capability, Preference> getCapabilities(); Map<Capability, Preference> getCapabilities();
Set<SideEffect> getSupportedSideEffects();
} }

View File

@ -94,6 +94,7 @@ import com.sk89q.worldedit.command.argument.ExpressionConverter;
import com.sk89q.worldedit.command.argument.FactoryConverter; import com.sk89q.worldedit.command.argument.FactoryConverter;
import com.sk89q.worldedit.command.argument.RegionFactoryConverter; import com.sk89q.worldedit.command.argument.RegionFactoryConverter;
import com.sk89q.worldedit.command.argument.RegistryConverter; import com.sk89q.worldedit.command.argument.RegistryConverter;
import com.sk89q.worldedit.command.argument.SideEffectConverter;
import com.sk89q.worldedit.command.argument.VectorConverter; import com.sk89q.worldedit.command.argument.VectorConverter;
import com.sk89q.worldedit.command.argument.WorldConverter; import com.sk89q.worldedit.command.argument.WorldConverter;
import com.sk89q.worldedit.command.argument.ZonedDateTimeConverter; import com.sk89q.worldedit.command.argument.ZonedDateTimeConverter;
@ -255,6 +256,7 @@ public final class PlatformCommandManager {
RegionFactoryConverter.register(commandManager); RegionFactoryConverter.register(commandManager);
WorldConverter.register(commandManager); WorldConverter.register(commandManager);
ExpressionConverter.register(commandManager); ExpressionConverter.register(commandManager);
SideEffectConverter.register(commandManager);
registerBindings(new ConsumeBindings(worldEdit, this)); registerBindings(new ConsumeBindings(worldEdit, this));
registerBindings(new PrimitiveBindings(worldEdit)); registerBindings(new PrimitiveBindings(worldEdit));

View File

@ -48,9 +48,11 @@ import com.sk89q.worldedit.event.platform.PlayerInputEvent;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.eventbus.Subscribe; import com.sk89q.worldedit.util.eventbus.Subscribe;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -304,6 +306,10 @@ public class PlatformManager {
return queryCapability(Capability.CONFIGURATION).getConfiguration(); return queryCapability(Capability.CONFIGURATION).getConfiguration();
} }
public Collection<SideEffect> getSupportedSideEffects() {
return queryCapability(Capability.WORLD_EDITING).getSupportedSideEffects();
}
@Subscribe @Subscribe
public void handlePlatformReady(PlatformReadyEvent event) { public void handlePlatformReady(PlatformReadyEvent event) {
choosePreferred(); choosePreferred();

View File

@ -21,17 +21,16 @@ package com.sk89q.worldedit.extent.buffer;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Maps;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.AbstractBufferingExtent; import com.sk89q.worldedit.extent.AbstractBufferingExtent;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.collection.BlockMap;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Map; import java.util.Map;
import java.util.Optional;
/** /**
* Buffers changes to an {@link Extent} and allows retrieval of the changed blocks, * Buffers changes to an {@link Extent} and allows retrieval of the changed blocks,
@ -39,7 +38,7 @@ import java.util.Optional;
*/ */
public class ExtentBuffer extends AbstractBufferingExtent { public class ExtentBuffer extends AbstractBufferingExtent {
private final Map<BlockVector3, BaseBlock> buffer = Maps.newHashMap(); private final Map<BlockVector3, BaseBlock> buffer = BlockMap.create();
private final Mask mask; private final Mask mask;
/** /**

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.extent.reorder; package com.sk89q.worldedit.extent.reorder;
import com.google.common.collect.ImmutableSortedSet;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.AbstractBufferingExtent; import com.sk89q.worldedit.extent.AbstractBufferingExtent;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;

View File

@ -27,67 +27,38 @@ import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.RunContext; import com.sk89q.worldedit.function.operation.RunContext;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.collection.BlockMap;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
* Implements "fast mode" which may skip physics, lighting, etc. * An extent that sets blocks in the world, with a {@link SideEffectSet}.
*/ */
public class FastModeExtent extends AbstractDelegateExtent { public class SideEffectExtent extends AbstractDelegateExtent {
private final World world; private final World world;
private final Set<BlockVector3> positions = new HashSet<>(); private final Map<BlockVector3, BlockState> positions = BlockMap.create();
private final Set<BlockVector2> dirtyChunks = new HashSet<>(); private final Set<BlockVector2> dirtyChunks = new HashSet<>();
private boolean enabled = true; private SideEffectSet sideEffectSet = SideEffectSet.defaults();
private boolean postEditSimulation; private boolean postEditSimulation;
/**
* Create a new instance with fast mode enabled.
*
* @param world the world
*/
public FastModeExtent(World world) {
this(world, true);
}
/** /**
* Create a new instance. * Create a new instance.
* *
* @param world the world * @param world the world
* @param enabled true to enable fast mode
*/ */
public FastModeExtent(World world, boolean enabled) { public SideEffectExtent(World world) {
super(world); super(world);
checkNotNull(world); checkNotNull(world);
this.world = world; this.world = world;
this.enabled = enabled;
if (enabled) {
this.postEditSimulation = true;
}
}
/**
* Return whether fast mode is enabled.
*
* @return true if fast mode is enabled
*/
public boolean isEnabled() {
return enabled;
}
/**
* Set fast mode enable status.
*
* @param enabled true to enable fast mode
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
} }
public boolean isPostEditSimulationEnabled() { public boolean isPostEditSimulationEnabled() {
@ -98,26 +69,28 @@ public class FastModeExtent extends AbstractDelegateExtent {
this.postEditSimulation = enabled; this.postEditSimulation = enabled;
} }
public SideEffectSet getSideEffectSet() {
return this.sideEffectSet;
}
public void setSideEffectSet(SideEffectSet sideEffectSet) {
this.sideEffectSet = sideEffectSet;
}
@Override @Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException { public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
if (enabled || postEditSimulation) { if (sideEffectSet.getState(SideEffect.LIGHTING) == SideEffect.State.DELAYED) {
dirtyChunks.add(BlockVector2.at(location.getBlockX() >> 4, location.getBlockZ() >> 4)); dirtyChunks.add(BlockVector2.at(location.getBlockX() >> 4, location.getBlockZ() >> 4));
if (world.setBlock(location, block, false)) {
if (!enabled && postEditSimulation) {
positions.add(location);
}
return true;
}
return false;
} else {
return world.setBlock(location, block, true);
} }
if (postEditSimulation) {
positions.put(location, world.getBlock(location));
}
return world.setBlock(location, block, postEditSimulation ? SideEffectSet.none() : sideEffectSet);
} }
public boolean commitRequired() { public boolean commitRequired() {
return enabled || postEditSimulation; return postEditSimulation || !dirtyChunks.isEmpty();
} }
@Override @Override
@ -132,11 +105,11 @@ public class FastModeExtent extends AbstractDelegateExtent {
world.fixAfterFastMode(dirtyChunks); world.fixAfterFastMode(dirtyChunks);
} }
if (!enabled && postEditSimulation) { if (postEditSimulation) {
Iterator<BlockVector3> positionIterator = positions.iterator(); Iterator<Map.Entry<BlockVector3, BlockState>> positionIterator = positions.entrySet().iterator();
while (run.shouldContinue() && positionIterator.hasNext()) { while (run.shouldContinue() && positionIterator.hasNext()) {
BlockVector3 position = positionIterator.next(); Map.Entry<BlockVector3, BlockState> position = positionIterator.next();
world.notifyAndLightBlock(position, BlockTypes.AIR.getDefaultState()); world.applySideEffects(position.getKey(), position.getValue(), sideEffectSet);
positionIterator.remove(); positionIterator.remove();
} }
@ -151,5 +124,4 @@ public class FastModeExtent extends AbstractDelegateExtent {
} }
}; };
} }
} }

View File

@ -52,6 +52,19 @@ public class RandomPattern extends AbstractPattern {
this.random = random; this.random = random;
} }
/**
* Create a random pattern from an existing one but with a different random.
*
* @param random the new random to use.
* @param parent the existing random pattern.
*/
public RandomPattern(SimpleRandom random, RandomPattern parent) {
this.random = random;
this.weights = parent.weights;
this.collection = RandomCollection.of(weights, random);
this.patterns = parent.patterns;
}
/** /**
* Add a pattern to the weight list of patterns. * Add a pattern to the weight list of patterns.
* *

View File

@ -0,0 +1,184 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.internal.wna;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Natively access and perform operations on the world.
*
* @param <NC> the native chunk type
* @param <NBS> the native block state type
* @param <NP> the native position type
*/
public interface WorldNativeAccess<NC, NBS, NP> {
default <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException {
checkNotNull(position);
checkNotNull(block);
setCurrentSideEffectSet(sideEffects);
int x = position.getBlockX();
int y = position.getBlockY();
int z = position.getBlockZ();
// First set the block
NC chunk = getChunk(x >> 4, z >> 4);
NP pos = getPosition(x, y, z);
NBS old = getBlockState(chunk, pos);
NBS newState = toNative(block.toImmutableState());
// change block prior to placing if it should be fixed
if (sideEffects.shouldApply(SideEffect.VALIDATION)) {
newState = getValidBlockForPosition(newState, pos);
}
NBS successState = setBlockState(chunk, pos, newState);
boolean successful = successState != null;
// Create the TileEntity
if (successful || old == newState) {
if (block instanceof BaseBlock) {
BaseBlock baseBlock = (BaseBlock) block;
CompoundTag tag = baseBlock.getNbtData();
if (tag != null) {
tag = tag.createBuilder()
.putString("id", baseBlock.getNbtId())
.putInt("x", position.getX())
.putInt("y", position.getY())
.putInt("z", position.getZ())
.build();
// update if TE changed as well
successful = updateTileEntity(pos, tag);
}
}
}
if (successful) {
if (sideEffects.getState(SideEffect.LIGHTING) == SideEffect.State.ON) {
updateLightingForBlock(pos);
}
markAndNotifyBlock(pos, chunk, old, newState, sideEffects);
}
return successful;
}
default void applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet) {
setCurrentSideEffectSet(sideEffectSet);
NP pos = getPosition(position.getX(), position.getY(), position.getZ());
NC chunk = getChunk(position.getX() >> 4, position.getZ() >> 4);
NBS oldData = toNative(previousType);
NBS newData = getBlockState(chunk, pos);
if (sideEffectSet.getState(SideEffect.LIGHTING) == SideEffect.State.ON) {
updateLightingForBlock(pos);
}
markAndNotifyBlock(pos, chunk, oldData, newData, sideEffectSet);
}
// state-keeping functions for WNA
// may be thread-unsafe, as this is single-threaded code
/**
* Receive the current side-effect set from the high level call.
*
* This allows the implementation to branch on the side-effects internally.
*
* @param sideEffectSet the set of side-effects
*/
default void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
}
// access functions
NC getChunk(int x, int z);
NBS toNative(BlockState state);
NBS getBlockState(NC chunk, NP position);
@Nullable
NBS setBlockState(NC chunk, NP position, NBS state);
NBS getValidBlockForPosition(NBS block, NP position);
NP getPosition(int x, int y, int z);
void updateLightingForBlock(NP position);
boolean updateTileEntity(NP position, CompoundTag tag);
void notifyBlockUpdate(NP position, NBS oldState, NBS newState);
boolean isChunkTicking(NC chunk);
void markBlockChanged(NP position);
void notifyNeighbors(NP pos, NBS oldState, NBS newState);
void updateNeighbors(NP pos, NBS oldState, NBS newState, int recursionLimit);
void onBlockStateChange(NP pos, NBS oldState, NBS newState);
/**
* This is a heavily modified function stripped from MC to apply worldedit-modifications.
*
* See Forge's World.markAndNotifyBlock
*/
default void markAndNotifyBlock(NP pos, NC chunk, NBS oldState, NBS newState, SideEffectSet sideEffectSet) {
NBS blockState1 = getBlockState(chunk, pos);
if (blockState1 != newState) {
return;
}
// Remove redundant branches
if (isChunkTicking(chunk)) {
if (sideEffectSet.shouldApply(SideEffect.ENTITY_AI)) {
notifyBlockUpdate(pos, oldState, newState);
} else {
// If we want to skip entity AI, just mark the block for sending
markBlockChanged(pos);
}
}
if (sideEffectSet.shouldApply(SideEffect.NEIGHBORS)) {
notifyNeighbors(pos, oldState, newState);
}
// Make connection updates optional
if (sideEffectSet.shouldApply(SideEffect.VALIDATION)) {
updateNeighbors(pos, oldState, newState, 512);
}
onBlockStateChange(pos, oldState, newState);
}
}

View File

@ -0,0 +1,25 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* "WNA", or WorldEdit Native Access.
*
* Contains internal helper functions for sharing code between platforms.
*/
package com.sk89q.worldedit.internal.wna;

View File

@ -0,0 +1,68 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.util;
import java.util.Locale;
public enum SideEffect {
LIGHTING(State.ON),
NEIGHBORS(State.ON),
VALIDATION(State.ON),
ENTITY_AI(State.OFF),
EVENTS(State.OFF);
private final String displayName;
private final String description;
private final State defaultValue;
SideEffect(State defaultValue) {
this.displayName = "worldedit.sideeffect." + this.name().toLowerCase(Locale.US);
this.description = "worldedit.sideeffect." + this.name().toLowerCase(Locale.US) + ".description";
this.defaultValue = defaultValue;
}
public String getDisplayName() {
return this.displayName;
}
public String getDescription() {
return this.description;
}
public State getDefaultValue() {
return this.defaultValue;
}
public enum State {
OFF,
ON,
DELAYED;
private final String displayName;
State() {
this.displayName = "worldedit.sideeffect.state." + this.name().toLowerCase(Locale.US);
}
public String getDisplayName() {
return this.displayName;
}
}
}

View File

@ -0,0 +1,94 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.util;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
public class SideEffectSet {
private static final SideEffectSet DEFAULT = new SideEffectSet(
Arrays.stream(SideEffect.values()).collect(Collectors.toMap(Function.identity(), SideEffect::getDefaultValue))
);
private static final SideEffectSet NONE = new SideEffectSet();
private final Map<SideEffect, SideEffect.State> sideEffects;
private final Set<SideEffect> appliedSideEffects;
private final boolean appliesAny;
private SideEffectSet() {
this(ImmutableMap.of());
}
public SideEffectSet(Map<SideEffect, SideEffect.State> sideEffects) {
this.sideEffects = Maps.immutableEnumMap(sideEffects);
appliedSideEffects = sideEffects.entrySet()
.stream()
.filter(entry -> entry.getValue() != SideEffect.State.OFF)
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
appliesAny = !appliedSideEffects.isEmpty();
}
public SideEffectSet with(SideEffect sideEffect, SideEffect.State state) {
Map<SideEffect, SideEffect.State> entries = this.sideEffects.isEmpty() ? Maps.newEnumMap(SideEffect.class) : new EnumMap<>(this.sideEffects);
entries.put(sideEffect, state);
return new SideEffectSet(entries);
}
public boolean doesApplyAny() {
return this.appliesAny;
}
public SideEffect.State getState(SideEffect effect) {
return sideEffects.getOrDefault(effect, effect.getDefaultValue());
}
/**
* Gets whether this side effect is not off.
*
* This returns whether it is either delayed or on.
*
* @param effect The side effect
* @return Whether it should apply
*/
public boolean shouldApply(SideEffect effect) {
return getState(effect) != SideEffect.State.OFF;
}
public Set<SideEffect> getSideEffectsToApply() {
return this.appliedSideEffects;
}
public static SideEffectSet defaults() {
return DEFAULT;
}
public static SideEffectSet none() {
return NONE;
}
}

View File

@ -0,0 +1,88 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.util.formatting.component;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
public class SideEffectBox extends PaginationBox {
private static List<SideEffect> sideEffects;
private SideEffectSet sideEffectSet;
private static List<SideEffect> getSideEffects() {
if (sideEffects == null) {
sideEffects = WorldEdit.getInstance().getPlatformManager().getSupportedSideEffects()
.stream()
.sorted(Comparator.comparing(Enum::name))
.collect(Collectors.toList());
}
return sideEffects;
}
public SideEffectBox(SideEffectSet sideEffectSet) {
super("Side Effects");
this.sideEffectSet = sideEffectSet;
}
private static final SideEffect.State[] SHOWN_VALUES = {SideEffect.State.OFF, SideEffect.State.ON};
@Override
public Component getComponent(int number) {
SideEffect effect = getSideEffects().get(number);
SideEffect.State state = this.sideEffectSet.getState(effect);
TextComponent.Builder builder = TextComponent.builder();
builder = builder.append(TranslatableComponent.of(effect.getDisplayName(), TextColor.YELLOW)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TranslatableComponent.of(effect.getDescription()))));
for (SideEffect.State uiState : SHOWN_VALUES) {
builder = builder.append(TextComponent.space());
builder = builder.append(TranslatableComponent.of(uiState.getDisplayName(), uiState == state ? TextColor.WHITE : TextColor.GRAY)
.clickEvent(ClickEvent.runCommand("//fast -h " + effect.name().toLowerCase(Locale.US) + " " + uiState.name().toLowerCase(Locale.US)))
.hoverEvent(HoverEvent.showText(uiState == state
? TranslatableComponent.of("worldedit.sideeffect.box.current")
: TranslatableComponent.of("worldedit.sideeffect.box.change-to", TranslatableComponent.of(uiState.getDisplayName()))
))
);
}
return builder.build();
}
@Override
public int getComponentsSize() {
return getSideEffects().size();
}
}

View File

@ -32,6 +32,7 @@ import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.weather.WeatherType; import com.sk89q.worldedit.world.weather.WeatherType;
import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockType;
@ -57,7 +58,7 @@ public abstract class AbstractWorld implements World {
@Override @Override
public final <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 pt, B block) throws WorldEditException { public final <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 pt, B block) throws WorldEditException {
return setBlock(pt, block, true); return setBlock(pt, block, SideEffectSet.defaults());
} }
@Override @Override

View File

@ -23,6 +23,7 @@ import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.implementation.packet.ChunkPacket; import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
import com.boydti.fawe.beta.implementation.blocks.NullChunkGet; import com.boydti.fawe.beta.implementation.blocks.NullChunkGet;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.google.common.collect.ImmutableSet;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
@ -35,6 +36,8 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.TreeGenerator.TreeType;
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.biome.BiomeTypes;
@ -48,6 +51,7 @@ import com.sk89q.worldedit.world.weather.WeatherTypes;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* A null implementation of {@link World} that drops all changes and * A null implementation of {@link World} that drops all changes and
@ -71,13 +75,14 @@ public class NullWorld extends AbstractWorld {
} }
@Override @Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException { public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException {
return false; return false;
} }
@Override @Override
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException { public Set<SideEffect> applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet)
return false; throws WorldEditException {
return ImmutableSet.of();
} }
@Override @Override

View File

@ -37,15 +37,19 @@ import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.Keyed;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
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 com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.weather.WeatherType; import com.sk89q.worldedit.world.weather.WeatherType;
import javax.annotation.Nullable;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Locale; import java.util.Locale;
import java.util.Set;
import javax.annotation.Nullable;
/** /**
* Represents a world (dimension). * Represents a world (dimension).
@ -112,10 +116,28 @@ public interface World extends Extent, Keyed, IChunkCache<IChunkGet> {
* @param notifyAndLight true to to notify and light * @param notifyAndLight true to to notify and light
* @return true if the block was successfully set (return value may not be accurate) * @return true if the block was successfully set (return value may not be accurate)
*/ */
@Deprecated
default <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException { default <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException {
return setBlock(position, block); return setBlock(position, block, notifyAndLight ? SideEffectSet.defaults() : SideEffectSet.none());
} }
/**
* Similar to {@link Extent#setBlock(BlockVector3, BlockStateHolder)} but a
* {@code sideEffects} parameter indicates which side effects should be applied
* to the block. This includes block updates, lighting, and others. See {@link SideEffect}
* for a full list.
*
* <p>Not all implementations support all side effects. Use
* {@link Platform#getSupportedSideEffects()} for a list of supported side effects.
* Non-supported side effects will be ignored.</p>
*
* @param position position of the block
* @param block block to set
* @param sideEffects which side effects to perform
* @return true if the block was successfully set (return value may not be accurate)
*/
<B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException;
/** /**
* Notifies the simulation that the block at the given location has * Notifies the simulation that the block at the given location has
* been changed and it must be re-lighted (and issue other events). * been changed and it must be re-lighted (and issue other events).
@ -124,7 +146,20 @@ public interface World extends Extent, Keyed, IChunkCache<IChunkGet> {
* @param previousType the type of the previous block that was there * @param previousType the type of the previous block that was there
* @return true if the block was successfully notified * @return true if the block was successfully notified
*/ */
boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException; @Deprecated
default boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {
return !applySideEffects(position, previousType, SideEffectSet.defaults()).isEmpty();
}
/**
* Applies a set of side effects on the given block.
*
* @param position position of the block
* @param previousType the type of the previous block that was there
* @param sideEffectSet which side effects to perform
* @return a set of side effects that were applied
*/
Set<SideEffect> applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet) throws WorldEditException;
/** /**
* Get the light level at the given block. * Get the light level at the given block.

View File

@ -210,6 +210,10 @@
"worldedit.fast.enabled": "Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes.", "worldedit.fast.enabled": "Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes.",
"worldedit.fast.disabled.already": "Fast mode already disabled.", "worldedit.fast.disabled.already": "Fast mode already disabled.",
"worldedit.fast.enabled.already": "Fast mode already enabled.", "worldedit.fast.enabled.already": "Fast mode already enabled.",
"worldedit.fast.sideeffect.set": "Side effect \"{0}\" set to {1}",
"worldedit.fast.sideeffect.get": "Side effect \"{0}\" is set to {1}",
"worldedit.fast.sideeffect.already-set": "Side effect \"{0}\" is already {1}",
"worldedit.fast.sideeffect.set-all": "All side effects set to {0}",
"worldedit.reorder.current": "The reorder mode is {0}", "worldedit.reorder.current": "The reorder mode is {0}",
"worldedit.reorder.set": "The reorder mode is now {0}", "worldedit.reorder.set": "The reorder mode is now {0}",
"worldedit.gmask.disabled": "Global mask disabled.", "worldedit.gmask.disabled": "Global mask disabled.",
@ -494,6 +498,22 @@
"worldedit.selection.sphere.explain.secondary": "Radius set to {0}.", "worldedit.selection.sphere.explain.secondary": "Radius set to {0}.",
"worldedit.selection.sphere.explain.secondary-defined": "Radius set to {0} ({1}).", "worldedit.selection.sphere.explain.secondary-defined": "Radius set to {0} ({1}).",
"worldedit.sideeffect.lighting": "Lighting",
"worldedit.sideeffect.lighting.description": "Updates block lighting",
"worldedit.sideeffect.neighbors": "Neighbors",
"worldedit.sideeffect.neighbors.description": "Notifies nearby blocks of changes",
"worldedit.sideeffect.validation": "Validation",
"worldedit.sideeffect.validation.description": "Validates and fixes inconsistent world state, such as disconnected blocks",
"worldedit.sideeffect.entity_ai": "Entity AI",
"worldedit.sideeffect.entity_ai.description": "Updates Entity AI paths for the block changes",
"worldedit.sideeffect.events": "Mod/Plugin Events",
"worldedit.sideeffect.events.description": "Tells other mods/plugins about these changes when applicable",
"worldedit.sideeffect.state.on": "On",
"worldedit.sideeffect.state.delayed": "Delayed",
"worldedit.sideeffect.state.off": "Off",
"worldedit.sideeffect.box.current": "Current",
"worldedit.sideeffect.box.change-to": "Click to set to {0}",
"worldedit.help.command-not-found": "The command '{0}' could not be found.", "worldedit.help.command-not-found": "The command '{0}' could not be found.",
"worldedit.help.no-subcommands": "'{0}' has no sub-commands. (Maybe '{1}' is for a parameter?)", "worldedit.help.no-subcommands": "'{0}' has no sub-commands. (Maybe '{1}' is for a parameter?)",
"worldedit.help.subcommand-not-found": "The sub-command '{0}' under '{1}' could not be found.", "worldedit.help.subcommand-not-found": "The sub-command '{0}' under '{1}' could not be found.",

View File

@ -7,8 +7,8 @@ applyShadowConfiguration()
apply(plugin = "fabric-loom") apply(plugin = "fabric-loom")
val minecraftVersion = "1.15.2" val minecraftVersion = "1.15.2"
val yarnMappings = "1.15.2+build.8:v2" val yarnMappings = "1.15.2+build.14:v2"
val loaderVersion = "0.7.6+build.180" val loaderVersion = "0.7.8+build.189"
configurations.all { configurations.all {
resolutionStrategy { resolutionStrategy {
@ -61,16 +61,12 @@ tasks.named<Copy>("processResources") {
} }
} }
<<<<<<< HEAD
addJarManifest(includeClasspath = true)
=======
tasks.named<Jar>("jar") { tasks.named<Jar>("jar") {
manifest { manifest {
attributes("Class-Path" to CLASSPATH, attributes("Class-Path" to CLASSPATH,
"WorldEdit-Version" to project.version) "WorldEdit-Version" to project.version)
} }
} }
>>>>>>> 18a55bc14... Add new experimental snapshot API (#524)
tasks.named<ShadowJar>("shadowJar") { tasks.named<ShadowJar>("shadowJar") {
archiveClassifier.set("dist-dev") archiveClassifier.set("dist-dev")

View File

@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableList;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.fabric.internal.NBTConverter;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.registry.state.BooleanProperty; import com.sk89q.worldedit.registry.state.BooleanProperty;

View File

@ -36,9 +36,10 @@ import com.mojang.datafixers.DataFixerBuilder;
import com.mojang.datafixers.Dynamic; import com.mojang.datafixers.Dynamic;
import com.mojang.datafixers.schemas.Schema; import com.mojang.datafixers.schemas.Schema;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import net.minecraft.datafixers.NbtOps; import com.sk89q.worldedit.fabric.internal.NBTConverter;
import net.minecraft.datafixers.Schemas; import net.minecraft.datafixer.NbtOps;
import net.minecraft.datafixers.TypeReferences; import net.minecraft.datafixer.Schemas;
import net.minecraft.datafixer.TypeReferences;
import net.minecraft.nbt.FloatTag; import net.minecraft.nbt.FloatTag;
import net.minecraft.nbt.ListTag; import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.StringTag; import net.minecraft.nbt.StringTag;

View File

@ -25,6 +25,7 @@ import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.metadata.EntityProperties; import com.sk89q.worldedit.entity.metadata.EntityProperties;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.fabric.internal.NBTConverter;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.NullWorld; import com.sk89q.worldedit.world.NullWorld;

View File

@ -19,6 +19,7 @@
package com.sk89q.worldedit.fabric; package com.sk89q.worldedit.fabric;
import com.google.common.collect.Sets;
import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.command.util.PermissionCondition;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.AbstractPlatform; import com.sk89q.worldedit.extension.platform.AbstractPlatform;
@ -27,13 +28,13 @@ import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.MultiUserPlatform;
import com.sk89q.worldedit.extension.platform.Preference; import com.sk89q.worldedit.extension.platform.Preference;
import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extension.platform.Watchdog;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.registry.Registries; import com.sk89q.worldedit.world.registry.Registries;
import net.minecraft.SharedConstants; import net.minecraft.SharedConstants;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.PlayerManager; import net.minecraft.server.PlayerManager;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.dedicated.MinecraftDedicatedServer; import net.minecraft.server.dedicated.MinecraftDedicatedServer;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
@ -200,6 +201,18 @@ class FabricPlatform extends AbstractPlatform implements MultiUserPlatform {
return capabilities; return capabilities;
} }
private static final Set<SideEffect> SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet(
SideEffect.VALIDATION,
SideEffect.ENTITY_AI,
SideEffect.LIGHTING,
SideEffect.NEIGHBORS
);
@Override
public Set<SideEffect> getSupportedSideEffects() {
return SUPPORTED_SIDE_EFFECTS;
}
@Override @Override
public Collection<Actor> getConnectedUsers() { public Collection<Actor> getConnectedUsers() {
List<Actor> users = new ArrayList<>(); List<Actor> users = new ArrayList<>();

View File

@ -25,6 +25,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extension.platform.AbstractPlayerActor; import com.sk89q.worldedit.extension.platform.AbstractPlayerActor;
import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.fabric.internal.NBTConverter;
import com.sk89q.worldedit.fabric.mixin.AccessorServerPlayerEntity; import com.sk89q.worldedit.fabric.mixin.AccessorServerPlayerEntity;
import com.sk89q.worldedit.fabric.net.handler.WECUIPacketHandler; import com.sk89q.worldedit.fabric.net.handler.WECUIPacketHandler;
import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.internal.cui.CUIEvent;
@ -42,10 +43,10 @@ import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypes;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.client.network.packet.BlockEntityUpdateS2CPacket;
import net.minecraft.client.network.packet.BlockUpdateS2CPacket;
import net.minecraft.client.network.packet.CustomPayloadS2CPacket;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket;
import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.LiteralText; import net.minecraft.text.LiteralText;
import net.minecraft.text.Text; import net.minecraft.text.Text;

View File

@ -24,6 +24,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.Sets;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
@ -33,6 +34,8 @@ import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.fabric.internal.FabricWorldNativeAccess;
import com.sk89q.worldedit.fabric.internal.NBTConverter;
import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.internal.Constants;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
@ -42,6 +45,8 @@ import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
@ -71,6 +76,7 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.WorldSaveHandler; import net.minecraft.world.WorldSaveHandler;
import net.minecraft.world.biome.DefaultBiomeFeatures;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkManager; import net.minecraft.world.chunk.ChunkManager;
import net.minecraft.world.chunk.ChunkStatus; import net.minecraft.world.chunk.ChunkStatus;
@ -104,6 +110,7 @@ import java.util.Locale;
import java.util.Optional; import java.util.Optional;
import java.util.OptionalInt; import java.util.OptionalInt;
import java.util.Random; import java.util.Random;
import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -123,6 +130,7 @@ public class FabricWorld extends AbstractWorld {
private static final net.minecraft.block.BlockState JUNGLE_SHRUB = Blocks.OAK_LEAVES.getDefaultState().with(LeavesBlock.PERSISTENT, Boolean.TRUE); private static final net.minecraft.block.BlockState JUNGLE_SHRUB = Blocks.OAK_LEAVES.getDefaultState().with(LeavesBlock.PERSISTENT, Boolean.TRUE);
private final WeakReference<World> worldRef; private final WeakReference<World> worldRef;
private final FabricWorldNativeAccess worldNativeAccess;
/** /**
* Construct a new world. * Construct a new world.
@ -132,6 +140,7 @@ public class FabricWorld extends AbstractWorld {
FabricWorld(World world) { FabricWorld(World world) {
checkNotNull(world); checkNotNull(world);
this.worldRef = new WeakReference<>(world); this.worldRef = new WeakReference<>(world);
this.worldNativeAccess = new FabricWorldNativeAccess(worldRef);
} }
/** /**
@ -186,61 +195,14 @@ public class FabricWorld extends AbstractWorld {
} }
@Override @Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException { public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException {
checkNotNull(position); return worldNativeAccess.setBlock(position, block, sideEffects);
checkNotNull(block);
World world = getWorldChecked();
int x = position.getBlockX();
int y = position.getBlockY();
int z = position.getBlockZ();
// First set the block
Chunk chunk = world.getChunk(x >> 4, z >> 4);
BlockPos pos = new BlockPos(x, y, z);
net.minecraft.block.BlockState old = chunk.getBlockState(pos);
OptionalInt stateId = BlockStateIdAccess.getBlockStateId(block.toImmutableState());
net.minecraft.block.BlockState newState = stateId.isPresent() ? Block.getStateFromRawId(stateId.getAsInt()) : FabricAdapter.adapt(block.toImmutableState());
net.minecraft.block.BlockState successState = chunk.setBlockState(pos, newState, false);
boolean successful = successState != null;
// Create the TileEntity
if (successful || old == newState) {
if (block instanceof BaseBlock) {
CompoundTag tag = ((BaseBlock) block).getNbtData();
if (tag != null) {
net.minecraft.nbt.CompoundTag nativeTag = NBTConverter.toNative(tag);
BlockEntity tileEntity = getWorld().getWorldChunk(pos).getBlockEntity(pos);
if (tileEntity != null) {
tileEntity.fromTag(nativeTag);
tileEntity.setPos(pos);
tileEntity.setWorld(world);
successful = true; // update if TE changed as well
}
}
}
}
if (successful && notifyAndLight) {
world.getChunkManager().getLightingProvider().enqueueLightUpdate(pos);
world.scheduleBlockRender(pos, old, newState);
world.updateListeners(pos, old, newState, UPDATE | NOTIFY);
world.updateNeighbors(pos, newState.getBlock());
if (old.hasComparatorOutput()) {
world.updateHorizontalAdjacent(pos, newState.getBlock());
}
}
return successful;
} }
@Override @Override
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException { public Set<SideEffect> applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet) throws WorldEditException {
BlockPos pos = new BlockPos(position.getX(), position.getY(), position.getZ()); worldNativeAccess.applySideEffects(position, previousType, sideEffectSet);
net.minecraft.block.BlockState state = getWorld().getBlockState(pos); return Sets.intersection(FabricWorldEdit.inst.getPlatform().getSupportedSideEffects(), sideEffectSet.getSideEffectsToApply());
getWorld().updateListeners(pos, FabricAdapter.adapt(previousType), state, 1 | 2);
getWorld().updateNeighbors(pos, state.getBlock());
return true;
} }
@Override @Override

View File

@ -0,0 +1,139 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.fabric.internal;
import com.sk89q.worldedit.fabric.FabricAdapter;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.world.ChunkHolder;
import net.minecraft.server.world.ServerChunkManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.WorldChunk;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Objects;
public class FabricWorldNativeAccess implements WorldNativeAccess<WorldChunk, BlockState, BlockPos> {
private static final int UPDATE = 1, NOTIFY = 2;
private final WeakReference<World> world;
public FabricWorldNativeAccess(WeakReference<World> world) {
this.world = world;
}
private World getWorld() {
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
}
@Override
public WorldChunk getChunk(int x, int z) {
return getWorld().getChunk(x, z);
}
@Override
public BlockState toNative(com.sk89q.worldedit.world.block.BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.getStateFromRawId(stateId)
: FabricAdapter.adapt(state);
}
@Override
public BlockState getBlockState(WorldChunk chunk, BlockPos position) {
return chunk.getBlockState(position);
}
@Nullable
@Override
public BlockState setBlockState(WorldChunk chunk, BlockPos position, BlockState state) {
return chunk.setBlockState(position, state, false);
}
@Override
public BlockState getValidBlockForPosition(BlockState block, BlockPos position) {
return Block.getRenderingState(block, getWorld(), position);
}
@Override
public BlockPos getPosition(int x, int y, int z) {
return new BlockPos(x, y, z);
}
@Override
public void updateLightingForBlock(BlockPos position) {
getWorld().getChunkManager().getLightingProvider().checkBlock(position);
}
@Override
public boolean updateTileEntity(BlockPos position, com.sk89q.jnbt.CompoundTag tag) {
CompoundTag nativeTag = NBTConverter.toNative(tag);
BlockEntity tileEntity = getWorld().getWorldChunk(position).getBlockEntity(position);
if (tileEntity == null) {
return false;
}
tileEntity.setLocation(getWorld(), position);
tileEntity.fromTag(nativeTag);
return true;
}
@Override
public void notifyBlockUpdate(BlockPos position, BlockState oldState, BlockState newState) {
getWorld().updateListeners(position, oldState, newState, UPDATE | NOTIFY);
}
@Override
public boolean isChunkTicking(WorldChunk chunk) {
return chunk.getLevelType().isAfter(ChunkHolder.LevelType.TICKING);
}
@Override
public void markBlockChanged(BlockPos position) {
((ServerChunkManager) getWorld().getChunkManager()).markForUpdate(position);
}
@Override
public void notifyNeighbors(BlockPos pos, BlockState oldState, BlockState newState) {
getWorld().updateNeighbors(pos, oldState.getBlock());
if (newState.hasComparatorOutput()) {
getWorld().updateHorizontalAdjacent(pos, newState.getBlock());
}
}
@Override
public void updateNeighbors(BlockPos pos, BlockState oldState, BlockState newState) {
World world = getWorld();
// method_11637 = updateDiagonalNeighbors
oldState.method_11637(world, pos, NOTIFY);
newState.updateNeighborStates(world, pos, NOTIFY);
newState.method_11637(world, pos, NOTIFY);
}
@Override
public void onBlockStateChange(BlockPos pos, BlockState oldState, BlockState newState) {
getWorld().onBlockChanged(pos, oldState, newState);
}
}

View File

@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.fabric; package com.sk89q.worldedit.fabric.internal;
import com.sk89q.jnbt.ByteArrayTag; import com.sk89q.jnbt.ByteArrayTag;
import com.sk89q.jnbt.ByteTag; import com.sk89q.jnbt.ByteTag;
@ -44,7 +44,7 @@ import java.util.Set;
/** /**
* Converts between JNBT and Minecraft NBT classes. * Converts between JNBT and Minecraft NBT classes.
*/ */
final class NBTConverter { public final class NBTConverter {
private NBTConverter() { private NBTConverter() {
} }

View File

@ -23,15 +23,9 @@ import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.fabric.FabricAdapter; import com.sk89q.worldedit.fabric.FabricAdapter;
import com.sk89q.worldedit.fabric.FabricPlayer; import com.sk89q.worldedit.fabric.FabricPlayer;
import com.sk89q.worldedit.fabric.FabricWorldEdit; import com.sk89q.worldedit.fabric.FabricWorldEdit;
import net.fabricmc.fabric.api.network.PacketConsumer;
import net.fabricmc.fabric.api.network.PacketContext;
import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.packet.CustomPayloadS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.network.packet.CustomPayloadC2SPacket;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.PacketByteBuf;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -58,4 +52,4 @@ public final class WECUIPacketHandler {
session.describeCUI(actor); session.describeCUI(actor);
}); });
} }
} }

View File

@ -77,7 +77,12 @@ tasks.named<Copy>("processResources") {
} }
} }
addJarManifest(includeClasspath = false) tasks.named<Jar>("jar") {
manifest {
attributes("Class-Path" to CLASSPATH,
"WorldEdit-Version" to project.version)
}
}
tasks.named<ShadowJar>("shadowJar") { tasks.named<ShadowJar>("shadowJar") {
dependencies { dependencies {

View File

@ -25,6 +25,7 @@ import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.metadata.EntityProperties; import com.sk89q.worldedit.entity.metadata.EntityProperties;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.forge.internal.NBTConverter;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.NullWorld; import com.sk89q.worldedit.world.NullWorld;

View File

@ -27,6 +27,7 @@ import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.MultiUserPlatform;
import com.sk89q.worldedit.extension.platform.Preference; import com.sk89q.worldedit.extension.platform.Preference;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.registry.Registries; import com.sk89q.worldedit.world.registry.Registries;
@ -206,6 +207,18 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform {
return capabilities; return capabilities;
} }
private static final Set<SideEffect> SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet(
SideEffect.VALIDATION,
SideEffect.ENTITY_AI,
SideEffect.LIGHTING,
SideEffect.NEIGHBORS
);
@Override
public Set<SideEffect> getSupportedSideEffects() {
return SUPPORTED_SIDE_EFFECTS;
}
@Override @Override
public Collection<Actor> getConnectedUsers() { public Collection<Actor> getConnectedUsers() {
List<Actor> users = new ArrayList<>(); List<Actor> users = new ArrayList<>();

View File

@ -32,6 +32,9 @@ import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.forge.internal.ForgeWorldNativeAccess;
import com.sk89q.worldedit.forge.internal.NBTConverter;
import com.sk89q.worldedit.forge.internal.TileEntityUtils;
import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.internal.Constants;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.util.BiomeMath; import com.sk89q.worldedit.internal.util.BiomeMath;
@ -96,6 +99,7 @@ import net.minecraft.world.gen.feature.SwampTreeFeature;
import net.minecraft.world.gen.feature.TallTaigaTreeFeature; import net.minecraft.world.gen.feature.TallTaigaTreeFeature;
import net.minecraft.world.gen.feature.TreeFeature; import net.minecraft.world.gen.feature.TreeFeature;
import net.minecraft.world.server.ChunkHolder;
import net.minecraft.world.server.ServerChunkProvider; import net.minecraft.world.server.ServerChunkProvider;
import net.minecraft.world.server.ServerWorld; import net.minecraft.world.server.ServerWorld;
import net.minecraft.world.storage.SaveHandler; import net.minecraft.world.storage.SaveHandler;
@ -125,13 +129,13 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class ForgeWorld extends AbstractWorld { public class ForgeWorld extends AbstractWorld {
private static final Random random = new Random(); private static final Random random = new Random();
private static final int UPDATE = 1, NOTIFY = 2;
private static final net.minecraft.block.BlockState JUNGLE_LOG = Blocks.JUNGLE_LOG.getDefaultState(); private static final net.minecraft.block.BlockState JUNGLE_LOG = Blocks.JUNGLE_LOG.getDefaultState();
private static final net.minecraft.block.BlockState JUNGLE_LEAF = Blocks.JUNGLE_LEAVES.getDefaultState().with(LeavesBlock.PERSISTENT, Boolean.TRUE); private static final net.minecraft.block.BlockState JUNGLE_LEAF = Blocks.JUNGLE_LEAVES.getDefaultState().with(LeavesBlock.PERSISTENT, Boolean.TRUE);
private static final net.minecraft.block.BlockState JUNGLE_SHRUB = Blocks.OAK_LEAVES.getDefaultState().with(LeavesBlock.PERSISTENT, Boolean.TRUE); private static final net.minecraft.block.BlockState JUNGLE_SHRUB = Blocks.OAK_LEAVES.getDefaultState().with(LeavesBlock.PERSISTENT, Boolean.TRUE);
private final WeakReference<World> worldRef; private final WeakReference<World> worldRef;
private final ForgeWorldNativeAccess nativeAccess;
/** /**
* Construct a new world. * Construct a new world.
@ -141,6 +145,7 @@ public class ForgeWorld extends AbstractWorld {
ForgeWorld(World world) { ForgeWorld(World world) {
checkNotNull(world); checkNotNull(world);
this.worldRef = new WeakReference<>(world); this.worldRef = new WeakReference<>(world);
this.nativeAccess = new ForgeWorldNativeAccess(worldRef);
} }
/** /**
@ -193,50 +198,14 @@ public class ForgeWorld extends AbstractWorld {
} }
@Override @Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException { public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException {
checkNotNull(position); return nativeAccess.setBlock(position, block, sideEffects);
checkNotNull(block);
World world = getWorldChecked();
int x = position.getBlockX();
int y = position.getBlockY();
int z = position.getBlockZ();
// First set the block
Chunk chunk = world.getChunk(x >> 4, z >> 4);
BlockPos pos = new BlockPos(x, y, z);
net.minecraft.block.BlockState old = chunk.getBlockState(pos);
OptionalInt stateId = BlockStateIdAccess.getBlockStateId(block.toImmutableState());
net.minecraft.block.BlockState newState = stateId.isPresent() ? Block.getStateById(stateId.getAsInt()) : ForgeAdapter.adapt(block.toImmutableState());
net.minecraft.block.BlockState successState = chunk.setBlockState(pos, newState, false);
boolean successful = successState != null;
// Create the TileEntity
if (successful || old == newState) {
if (block instanceof BaseBlock) {
CompoundTag tag = ((BaseBlock) block).getNbtData();
if (tag != null) {
CompoundNBT nativeTag = NBTConverter.toNative(tag);
nativeTag.putString("id", ((BaseBlock) block).getNbtId());
TileEntityUtils.setTileEntity(world, position, nativeTag);
successful = true; // update if TE changed as well
}
}
}
if (successful && notifyAndLight) {
world.getChunkProvider().getLightManager().checkBlock(pos);
world.markAndNotifyBlock(pos, chunk, old, newState, UPDATE | NOTIFY);
}
return successful;
} }
@Override @Override
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException { public Set<SideEffect> applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet) throws WorldEditException {
BlockPos pos = new BlockPos(position.getX(), position.getY(), position.getZ()); nativeAccess.applySideEffects(position, previousType, sideEffectSet);
getWorld().notifyBlockUpdate(pos, ForgeAdapter.adapt(previousType), getWorld().getBlockState(pos), 1 | 2); return Sets.intersection(ForgeWorldEdit.inst.getPlatform().getSupportedSideEffects(), sideEffectSet.getSideEffectsToApply());
return true;
} }
@Override @Override

View File

@ -0,0 +1,152 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.forge.internal;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.forge.ForgeAdapter;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.server.ChunkHolder;
import net.minecraft.world.server.ServerChunkProvider;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Objects;
public class ForgeWorldNativeAccess implements WorldNativeAccess<Chunk, BlockState, BlockPos> {
private static final int UPDATE = 1, NOTIFY = 2;
private final WeakReference<World> world;
private SideEffectSet sideEffectSet;
public ForgeWorldNativeAccess(WeakReference<World> world) {
this.world = world;
}
private World getWorld() {
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
}
@Override
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
this.sideEffectSet = sideEffectSet;
}
@Override
public Chunk getChunk(int x, int z) {
return getWorld().getChunk(x, z);
}
@Override
public BlockState toNative(com.sk89q.worldedit.world.block.BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.getStateById(stateId)
: ForgeAdapter.adapt(state);
}
@Override
public BlockState getBlockState(Chunk chunk, BlockPos position) {
return chunk.getBlockState(position);
}
@Nullable
@Override
public BlockState setBlockState(Chunk chunk, BlockPos position, BlockState state) {
return chunk.setBlockState(position, state, false);
}
@Override
public BlockState getValidBlockForPosition(BlockState block, BlockPos position) {
return Block.getValidBlockForPosition(block, getWorld(), position);
}
@Override
public BlockPos getPosition(int x, int y, int z) {
return new BlockPos(x, y, z);
}
@Override
public void updateLightingForBlock(BlockPos position) {
getWorld().getChunkProvider().getLightManager().checkBlock(position);
}
@Override
public boolean updateTileEntity(BlockPos position, CompoundTag tag) {
CompoundNBT nativeTag = NBTConverter.toNative(tag);
return TileEntityUtils.setTileEntity(getWorld(), position, nativeTag);
}
@Override
public void notifyBlockUpdate(BlockPos position, BlockState oldState, BlockState newState) {
getWorld().notifyBlockUpdate(position, oldState, newState, UPDATE | NOTIFY);
}
@Override
public boolean isChunkTicking(Chunk chunk) {
return chunk.getLocationType().isAtLeast(ChunkHolder.LocationType.TICKING);
}
@Override
public void markBlockChanged(BlockPos position) {
((ServerChunkProvider) getWorld().getChunkProvider()).markBlockChanged(position);
}
@Override
public void notifyNeighbors(BlockPos pos, BlockState oldState, BlockState newState) {
World world = getWorld();
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
world.notifyNeighbors(pos, oldState.getBlock());
} else {
// Manually update each side
Block block = oldState.getBlock();
world.neighborChanged(pos.west(), block, pos);
world.neighborChanged(pos.east(), block, pos);
world.neighborChanged(pos.down(), block, pos);
world.neighborChanged(pos.up(), block, pos);
world.neighborChanged(pos.north(), block, pos);
world.neighborChanged(pos.south(), block, pos);
}
if (newState.hasComparatorInputOverride()) {
world.updateComparatorOutputLevel(pos, newState.getBlock());
}
}
@Override
public void updateNeighbors(BlockPos pos, BlockState oldState, BlockState newState) {
World world = getWorld();
oldState.updateDiagonalNeighbors(world, pos, NOTIFY);
newState.updateNeighbors(world, pos, NOTIFY);
newState.updateDiagonalNeighbors(world, pos, NOTIFY);
}
@Override
public void onBlockStateChange(BlockPos pos, BlockState oldState, BlockState newState) {
getWorld().onBlockStateChange(pos, oldState, newState);
}
}

View File

@ -24,13 +24,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.IntNBT;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nullable;
/** /**
* Utility methods for setting tile entities in the world. * Utility methods for setting tile entities in the world.
*/ */
@ -39,39 +36,21 @@ public final class TileEntityUtils {
private TileEntityUtils() { private TileEntityUtils() {
} }
/**
* Update the given tag compound with position information.
*
* @param tag the tag
* @param position the position
*/
private static void updateForSet(CompoundNBT tag, BlockVector3 position) {
checkNotNull(tag);
checkNotNull(position);
tag.put("x", new IntNBT(position.getBlockX()));
tag.put("y", new IntNBT(position.getBlockY()));
tag.put("z", new IntNBT(position.getBlockZ()));
}
/** /**
* Set a tile entity at the given location using the tile entity ID from * Set a tile entity at the given location using the tile entity ID from
* the tag. * the tag.
* *
* @param world the world * @param world the world
* @param position the position * @param position the position
* @param tag the tag for the tile entity (may be null to do nothing) * @param tag the tag for the tile entity
*/ */
static boolean setTileEntity(World world, BlockVector3 position, @Nullable CompoundNBT tag) { static boolean setTileEntity(World world, BlockPos position, CompoundNBT tag) {
if (tag != null) { TileEntity tileEntity = TileEntity.create(tag);
updateForSet(tag, position); if (tileEntity == null) {
TileEntity tileEntity = TileEntity.create(tag); return false;
if (tileEntity == null) {
return false;
}
world.setTileEntity(new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()), tileEntity);
return true;
} }
world.setTileEntity(new BlockPos(position.getX(), position.getY(), position.getZ()), tileEntity);
return true;
} }
public static CompoundNBT copyNbtData(TileEntity tile) { public static CompoundNBT copyNbtData(TileEntity tile) {

View File

@ -20,6 +20,8 @@
package com.sk89q.worldedit.sponge; package com.sk89q.worldedit.sponge;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandEvent;
@ -31,6 +33,7 @@ import com.sk89q.worldedit.extension.platform.MultiUserPlatform;
import com.sk89q.worldedit.extension.platform.Preference; import com.sk89q.worldedit.extension.platform.Preference;
import com.sk89q.worldedit.internal.command.CommandUtil; import com.sk89q.worldedit.internal.command.CommandUtil;
import com.sk89q.worldedit.sponge.config.SpongeConfiguration; import com.sk89q.worldedit.sponge.config.SpongeConfiguration;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.registry.Registries; import com.sk89q.worldedit.world.registry.Registries;
import org.enginehub.piston.Command; import org.enginehub.piston.Command;
@ -50,6 +53,7 @@ import java.util.EnumMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;
@ -192,6 +196,11 @@ class SpongePlatform extends AbstractPlatform implements MultiUserPlatform {
return capabilities; return capabilities;
} }
@Override
public Set<SideEffect> getSupportedSideEffects() {
return ImmutableSet.of();
}
@Override @Override
public Collection<Actor> getConnectedUsers() { public Collection<Actor> getConnectedUsers() {
List<Actor> users = new ArrayList<>(); List<Actor> users = new ArrayList<>();