This commit is contained in:
MattBDev 2021-01-06 12:53:34 -05:00
commit 653d362806
107 changed files with 1624 additions and 1778 deletions

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

6
renovate.json Normal file
View File

@ -0,0 +1,6 @@
{
"extends": [
"config:base"
],
"ignoreDeps": ["guava", "rhino-runtime", "mockito-core", "antlr4", "antlr4-runtime", "paranamer"]
}

View File

@ -23,6 +23,7 @@ repositories {
name = "ProtocolLib Repo"
url = uri("https://repo.dmulloy2.net/nexus/repository/public/")
}
maven { url = uri("https://repo.inventivetalent.org/content/groups/public/") }
flatDir {dir(File("src/main/resources"))}
}
@ -56,7 +57,7 @@ dependencies {
"compileOnly"("org.jetbrains:annotations:20.1.0")
"testCompileOnly"("org.jetbrains:annotations:20.1.0")
"compileOnly"("org.spigotmc:spigot:1.16.4-R0.1-SNAPSHOT")
"implementation"("io.papermc:paperlib:1.0.4")
"implementation"("io.papermc:paperlib:1.0.6")
"compileOnly"("com.sk89q:dummypermscompat:1.10") {
exclude("com.github.MilkBowl", "VaultAPI")
}
@ -68,15 +69,16 @@ dependencies {
exclude("com.sk89q.worldedit.worldedit-libs", "bukkit")
exclude("com.sk89q.worldedit.worldedit-libs", "core")
}
"compile"("org.bstats:bstats-bukkit:1.7")
"compile"("org.bstats:bstats-bukkit:1.8")
"compile"("com.intellectualsites.paster:Paster:1.0.1-SNAPSHOT")
// Third party
"implementation"("com.github.InventivetalentDev:MapManager:1.7.+") { isTransitive = false }
compileOnlyApi("org.inventivetalent:mapmanager:1.7.+") { isTransitive = false }
"implementation"("com.github.TechFortress:GriefPrevention:16.+") { isTransitive = false }
"implementation"("com.massivecraft:mcore:7.0.1") { isTransitive = false }
"implementation"("com.bekvon.bukkit.residence:Residence:4.5._13.1") { isTransitive = false }
"implementation"("com.palmergames.bukkit:towny:0.84.0.9") { isTransitive = false }
"implementation"("com.thevoxelbox.voxelsniper:voxelsniper:5.171.0") { isTransitive = false }
"implementation"("com.comphenix.protocol:ProtocolLib:4.5.0") { isTransitive = false }
"implementation"("com.comphenix.protocol:ProtocolLib:4.5.1") { isTransitive = false }
}
tasks.named<Copy>("processResources") {
@ -107,17 +109,17 @@ tasks.named<ShadowJar>("shadowJar") {
include(dependency("org.slf4j:slf4j-api"))
include(dependency("org.apache.logging.log4j:log4j-slf4j-impl"))
include(dependency("org.antlr:antlr4-runtime"))
relocate("org.bstats", "com.sk89q.worldedit.bukkit.bstats") {
include(dependency("org.bstats:bstats-bukkit:1.7"))
}
relocate("io.papermc.lib", "com.sk89q.worldedit.bukkit.paperlib") {
include(dependency("io.papermc:paperlib:1.0.4"))
include(dependency("io.papermc:paperlib:1.0.6"))
}
relocate("it.unimi.dsi.fastutil", "com.sk89q.worldedit.bukkit.fastutil") {
include(dependency("it.unimi.dsi:fastutil"))
}
relocate("org.bstats", "com.boydti.metrics") {
include(dependency("org.bstats:bstats-bukkit:1.7"))
include(dependency("org.bstats:bstats-bukkit:1.8"))
}
relocate("com.intellectualsites.paster", "com.boydti.fawe.paster") {
include(dependency("com.intellectualsites.paster:Paster:1.0.1-SNAPSHOT"))
}
}
}

View File

@ -190,37 +190,32 @@ public final class BukkitAdapter_1_15_2 extends NMSAdapter {
return;
}
if (playerChunk.hasBeenLoaded()) {
TaskManager.IMP.sync(() -> {
try {
int dirtyBits = fieldDirtyBits.getInt(playerChunk);
if (dirtyBits == 0) {
nmsWorld.getChunkProvider().playerChunkMap.a(playerChunk);
}
if (mask == 0) {
dirtyBits = 65535;
} else {
dirtyBits |= mask;
}
fieldDirtyBits.set(playerChunk, dirtyBits);
fieldDirtyCount.set(playerChunk, 64);
if (lighting) {
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine());
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
p.playerConnection.sendPacket(packet);
});
}
} catch (IllegalAccessException e) {
e.printStackTrace();
try {
int dirtyBits = fieldDirtyBits.getInt(playerChunk);
if (dirtyBits == 0) {
nmsWorld.getChunkProvider().playerChunkMap.a(playerChunk);
}
return null;
});
return;
if (mask == 0) {
dirtyBits = 65535;
} else {
dirtyBits |= mask;
}
fieldDirtyBits.set(playerChunk, dirtyBits);
fieldDirtyCount.set(playerChunk, 64);
if (lighting) {
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine());
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
p.playerConnection.sendPacket(packet);
});
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return;
}
/*

View File

@ -4,7 +4,6 @@ import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.blocks.CharBlocks;
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
@ -90,6 +89,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
public NibbleArray[] skyLight = new NibbleArray[16];
private boolean createCopy = false;
private BukkitGetBlocks_1_15_2_Copy copy = null;
private boolean forceLoadSections = true;
public BukkitGetBlocks_1_15_2(World world, int chunkX, int chunkZ) {
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
@ -316,7 +316,8 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
copy = createCopy ? new BukkitGetBlocks_1_15_2_Copy(world, getChunkX(), getChunkZ()) : null;
forceLoadSections = false;
copy = createCopy ? new BukkitGetBlocks_1_15_2_Copy(world) : null;
try {
WorldServer nmsWorld = world;
Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
@ -357,13 +358,14 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
if (!set.hasSection(layer)) {
continue;
}
if (createCopy) {
copy.storeSection(layer);
}
bitMask |= 1 << layer;
char[] setArr = set.load(layer);
char[] setArr = set.load(layer).clone();
if (createCopy) {
copy.storeSection(layer, load(layer).clone());
}
ChunkSection newSection;
ChunkSection existingSection = sections[layer];
if (existingSection == null) {
@ -392,7 +394,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
this.nmsChunk = nmsChunk;
this.sections = null;
this.reset();
} else if (existingSection != getSections()[layer]) {
} else if (existingSection != getSections(false)[layer]) {
this.sections[layer] = existingSection;
this.reset();
} else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) {
@ -403,7 +405,6 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
newSection = BukkitAdapter_1_15_2.newChunkSection(layer, this::load, setArr, fastmode);
if (!BukkitAdapter_1_15_2.setSectionAtomic(sections, existingSection, newSection, layer)) {
log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
continue;
} else {
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
}
@ -470,9 +471,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
Set<UUID> entityRemoves = set.getEntityRemoves();
if (entityRemoves != null && !entityRemoves.isEmpty()) {
if (syncTasks == null) {
syncTasks = new Runnable[3];
}
syncTasks = new Runnable[3];
syncTasks[2] = () -> {
final List<Entity>[] entities = nmsChunk.getEntitySlices();
@ -632,12 +631,14 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
} catch (Throwable e) {
e.printStackTrace();
return null;
} finally {
forceLoadSections = true;
}
}
@Override
public synchronized char[] update(int layer, char[] data) {
ChunkSection section = getSections()[layer];
ChunkSection section = getSections(true)[layer];
// Section is null, return empty array
if (section == null) {
data = new char[4096];
@ -752,7 +753,10 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
}
}
public ChunkSection[] getSections() {
public ChunkSection[] getSections(boolean force) {
if (force && forceLoadSections) {
return sections = getChunk().getSections().clone();
}
ChunkSection[] tmp = sections;
if (tmp == null) {
synchronized (this) {
@ -804,7 +808,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
@Override
public boolean hasSection(int layer) {
return getSections()[layer] != null;
return getSections(false)[layer] != null;
}
@Override
@ -817,10 +821,10 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
return super.trim(true);
} else {
for (int i = 0; i < 16; i++) {
if (!hasSection(i) || super.sections[i] == CharBlocks.EMPTY) {
if (!hasSection(i) || !super.sections[i].isFull()) {
continue;
}
ChunkSection existing = getSections()[i];
ChunkSection existing = getSections(true)[i];
try {
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();

View File

@ -2,6 +2,10 @@ package com.boydti.fawe.bukkit.adapter.mc1_15_2;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBlocks;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
import com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt.LazyCompoundTag_1_15_2;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
@ -21,22 +25,25 @@ import net.minecraft.server.v1_15_R1.TileEntity;
import net.minecraft.server.v1_15_R1.WorldServer;
import org.bukkit.craftbukkit.v1_15_R1.block.CraftBlock;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Range;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
public class BukkitGetBlocks_1_15_2_Copy extends BukkitGetBlocks_1_15_2 {
public class BukkitGetBlocks_1_15_2_Copy implements IChunkGet {
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
private final Set<CompoundTag> entities = new HashSet<>();
private BiomeStorage biomeStorage;
private final char[][] blocks = new char[16][4096];
private final char[][] blocks = new char[16][];
private final WorldServer world;
protected BukkitGetBlocks_1_15_2_Copy(WorldServer world, int X, int Z) {
super(world, X, Z);
protected BukkitGetBlocks_1_15_2_Copy(WorldServer world) {
this.world = world;
}
protected void storeTile(TileEntity tile) {
@ -87,6 +94,16 @@ public class BukkitGetBlocks_1_15_2_Copy extends BukkitGetBlocks_1_15_2 {
return null;
}
@Override
public void setCreateCopy(boolean createCopy) {
}
@Override
public boolean isCreateCopy() {
return false;
}
protected void storeBiomes(BiomeStorage biomeStorage) {
this.biomeStorage = new BiomeStorage(BukkitAdapter_1_15_2.getBiomeArray(biomeStorage).clone());
}
@ -105,8 +122,18 @@ public class BukkitGetBlocks_1_15_2_Copy extends BukkitGetBlocks_1_15_2 {
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base)) : null;
}
protected void storeSection(int layer) {
blocks[layer] = update(layer, null).clone();
@Override
public boolean trim(boolean aggressive, int layer) {
return false;
}
@Override
public IBlocks reset() {
return null;
}
protected void storeSection(int layer, char[] data) {
blocks[layer] = data;
}
@Override
@ -115,15 +142,50 @@ public class BukkitGetBlocks_1_15_2_Copy extends BukkitGetBlocks_1_15_2 {
return state.toBaseBlock(this, x, y, z);
}
@Override
public boolean hasSection(@Range(from = 0, to = 15) int layer) {
return blocks[layer] != null;
}
@Override
public char[] load(int layer) {
return blocks[layer];
}
@Override
public BlockState getBlock(int x, int y, int z) {
return BlockTypesCache.states[get(x, y, z)];
}
@Override
public int getSkyLight(int x, int y, int z) {
return 0;
}
@Override
public int getEmmittedLight(int x, int y, int z) {
return 0;
}
@Override
public int[] getHeightMap(HeightMapType type) {
return new int[0];
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
return null;
}
public char get(int x, int y, int z) {
final int layer = y >> 4;
final int index = (y & 15) << 8 | z << 4 | x;
return blocks[layer][index];
}
@Override
public boolean trim(boolean aggressive) {
return false;
}
}

View File

@ -58,7 +58,7 @@ public class FAWEWorldNativeAccess_1_15_2 implements WorldNativeAccess<Chunk, IB
@Override
public IBlockData toNative(com.sk89q.worldedit.world.block.BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
int stateId = adapter.ordinalToIbdID(state.getOrdinalChar());
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.getByCombinedId(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
@ -72,7 +72,8 @@ public class FAWEWorldNativeAccess_1_15_2 implements WorldNativeAccess<Chunk, IB
@Nullable
@Override
public IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
return chunk.setType(position, state, false);
return chunk.setType(position, state,
this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE));
}
@Override
@ -166,9 +167,4 @@ public class FAWEWorldNativeAccess_1_15_2 implements WorldNativeAccess<Chunk, IB
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

@ -12,15 +12,18 @@ import net.minecraft.server.v1_15_R1.NBTTagList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
public class LazyCompoundTag_1_15_2 extends CompoundTag {
private final Supplier<NBTTagCompound> nmsTag;
private CompoundTag cachedValue;
public LazyCompoundTag_1_15_2(Supplier<NBTTagCompound> tag) {
super(null);
super(new HashMap<>());
this.nmsTag = tag;
}
@ -34,12 +37,10 @@ public class LazyCompoundTag_1_15_2 extends CompoundTag {
@Override
public Map<String, Tag> getValue() {
Map<String, Tag> value = super.getValue();
if (value == null) {
Tag tag = WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
setValue(((CompoundTag) tag).getValue());
if (cachedValue == null) {
cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
}
return super.getValue();
return cachedValue.getValue();
}
public boolean containsKey(String key) {
@ -149,4 +150,4 @@ public class LazyCompoundTag_1_15_2 extends CompoundTag {
public String toString() {
return nmsTag.get().toString();
}
}
}

View File

@ -187,35 +187,32 @@ public final class BukkitAdapter_1_16_1 extends NMSAdapter {
return;
}
if (playerChunk.hasBeenLoaded()) {
TaskManager.IMP.sync(() -> {
try {
int dirtyBits = fieldDirtyBits.getInt(playerChunk);
if (dirtyBits == 0) {
nmsWorld.getChunkProvider().playerChunkMap.a(playerChunk);
}
if (mask == 0) {
dirtyBits = 65535;
} else {
dirtyBits |= mask;
}
fieldDirtyBits.set(playerChunk, dirtyBits);
fieldDirtyCount.set(playerChunk, 64);
if (lighting) {
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
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 -> {
p.playerConnection.sendPacket(packet);
});
}
} catch (IllegalAccessException e) {
e.printStackTrace();
try {
int dirtyBits = fieldDirtyBits.getInt(playerChunk);
if (dirtyBits == 0) {
nmsWorld.getChunkProvider().playerChunkMap.a(playerChunk);
}
return null;
});
if (mask == 0) {
dirtyBits = 65535;
} else {
dirtyBits |= mask;
}
fieldDirtyBits.set(playerChunk, dirtyBits);
fieldDirtyCount.set(playerChunk, 64);
if (lighting) {
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
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 -> {
p.playerConnection.sendPacket(packet);
});
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}

View File

@ -4,7 +4,6 @@ import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.blocks.CharBlocks;
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
@ -90,6 +89,7 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks {
public NibbleArray[] skyLight = new NibbleArray[16];
private boolean createCopy = false;
private BukkitGetBlocks_1_16_1_Copy copy = null;
private boolean forceLoadSections = true;
public BukkitGetBlocks_1_16_1(World world, int chunkX, int chunkZ) {
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
@ -316,7 +316,8 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks {
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
copy = createCopy ? new BukkitGetBlocks_1_16_1_Copy(world, getChunkX(), getChunkZ()) : null;
forceLoadSections = false;
copy = createCopy ? new BukkitGetBlocks_1_16_1_Copy(world) : null;
try {
WorldServer nmsWorld = world;
Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
@ -357,13 +358,14 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks {
if (!set.hasSection(layer)) {
continue;
}
if (createCopy) {
copy.storeSection(layer);
}
bitMask |= 1 << layer;
char[] setArr = set.load(layer);
char[] setArr = set.load(layer).clone();
if (createCopy) {
copy.storeSection(layer, load(layer).clone());
}
ChunkSection newSection;
ChunkSection existingSection = sections[layer];
if (existingSection == null) {
@ -392,7 +394,7 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks {
this.nmsChunk = nmsChunk;
this.sections = null;
this.reset();
} else if (existingSection != getSections()[layer]) {
} else if (existingSection != getSections(false)[layer]) {
this.sections[layer] = existingSection;
this.reset();
} else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) {
@ -405,7 +407,6 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks {
if (!BukkitAdapter_1_16_1
.setSectionAtomic(sections, existingSection, newSection, layer)) {
log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
continue;
} else {
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
}
@ -472,9 +473,7 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks {
Set<UUID> entityRemoves = set.getEntityRemoves();
if (entityRemoves != null && !entityRemoves.isEmpty()) {
if (syncTasks == null) {
syncTasks = new Runnable[3];
}
syncTasks = new Runnable[3];
syncTasks[2] = () -> {
final List<Entity>[] entities = nmsChunk.getEntitySlices();
@ -634,12 +633,14 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks {
} catch (Throwable e) {
e.printStackTrace();
return null;
} finally {
forceLoadSections = true;
}
}
@Override
public synchronized char[] update(int layer, char[] data) {
ChunkSection section = getSections()[layer];
ChunkSection section = getSections(true)[layer];
// Section is null, return empty array
if (section == null) {
data = new char[4096];
@ -754,7 +755,10 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks {
}
}
public ChunkSection[] getSections() {
public ChunkSection[] getSections(boolean force) {
if (force && forceLoadSections) {
return sections = getChunk().getSections().clone();
}
ChunkSection[] tmp = sections;
if (tmp == null) {
synchronized (this) {
@ -806,7 +810,7 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks {
@Override
public boolean hasSection(int layer) {
return getSections()[layer] != null;
return getSections(false)[layer] != null;
}
@Override
@ -819,10 +823,10 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks {
return super.trim(true);
} else {
for (int i = 0; i < 16; i++) {
if (!hasSection(i) || super.sections[i] == CharBlocks.EMPTY) {
if (!hasSection(i) || !super.sections[i].isFull()) {
continue;
}
ChunkSection existing = getSections()[i];
ChunkSection existing = getSections(true)[i];
try {
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();

View File

@ -2,6 +2,10 @@ package com.boydti.fawe.bukkit.adapter.mc1_16_1;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBlocks;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
import com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt.LazyCompoundTag_1_16_1;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
@ -16,28 +20,30 @@ import com.sk89q.worldedit.world.block.BlockTypesCache;
import net.minecraft.server.v1_16_R1.BiomeBase;
import net.minecraft.server.v1_16_R1.BiomeStorage;
import net.minecraft.server.v1_16_R1.Entity;
import net.minecraft.server.v1_16_R1.IRegistry;
import net.minecraft.server.v1_16_R1.NBTTagCompound;
import net.minecraft.server.v1_16_R1.TileEntity;
import net.minecraft.server.v1_16_R1.WorldServer;
import org.bukkit.craftbukkit.v1_16_R1.block.CraftBlock;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Range;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
public class BukkitGetBlocks_1_16_1_Copy extends BukkitGetBlocks_1_16_1 {
public class BukkitGetBlocks_1_16_1_Copy implements IChunkGet {
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
private final Set<CompoundTag> entities = new HashSet<>();
private BiomeStorage biomeStorage;
private final char[][] blocks = new char[16][4096];
private final char[][] blocks = new char[16][];
private final WorldServer world;
protected BukkitGetBlocks_1_16_1_Copy(WorldServer world, int X, int Z) {
super(world, X, Z);
protected BukkitGetBlocks_1_16_1_Copy(WorldServer world) {
this.world = world;
}
protected void storeTile(TileEntity tile) {
@ -88,6 +94,16 @@ public class BukkitGetBlocks_1_16_1_Copy extends BukkitGetBlocks_1_16_1 {
return null;
}
@Override
public void setCreateCopy(boolean createCopy) {
}
@Override
public boolean isCreateCopy() {
return false;
}
protected void storeBiomes(BiomeStorage biomeStorage) {
this.biomeStorage = new BiomeStorage(BukkitAdapter_1_16_1.getBiomeArray(biomeStorage).clone());
}
@ -106,8 +122,18 @@ public class BukkitGetBlocks_1_16_1_Copy extends BukkitGetBlocks_1_16_1 {
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base)) : null;
}
protected void storeSection(int layer) {
blocks[layer] = update(layer, null).clone();
@Override
public boolean trim(boolean aggressive, int layer) {
return false;
}
@Override
public IBlocks reset() {
return null;
}
protected void storeSection(int layer, char[] data) {
blocks[layer] = data;
}
@Override
@ -116,15 +142,50 @@ public class BukkitGetBlocks_1_16_1_Copy extends BukkitGetBlocks_1_16_1 {
return state.toBaseBlock(this, x, y, z);
}
@Override
public boolean hasSection(@Range(from = 0, to = 15) int layer) {
return blocks[layer] != null;
}
@Override
public char[] load(int layer) {
return blocks[layer];
}
@Override
public BlockState getBlock(int x, int y, int z) {
return BlockTypesCache.states[get(x, y, z)];
}
@Override
public int getSkyLight(int x, int y, int z) {
return 0;
}
@Override
public int getEmmittedLight(int x, int y, int z) {
return 0;
}
@Override
public int[] getHeightMap(HeightMapType type) {
return new int[0];
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
return null;
}
public char get(int x, int y, int z) {
final int layer = y >> 4;
final int index = (y & 15) << 8 | z << 4 | x;
return blocks[layer][index];
}
@Override
public boolean trim(boolean aggressive) {
return false;
}
}

View File

@ -59,7 +59,7 @@ public class FAWEWorldNativeAccess_1_16 implements WorldNativeAccess<Chunk, IBlo
@Override
public IBlockData toNative(BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
int stateId = adapter.ordinalToIbdID(state.getOrdinalChar());
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.getByCombinedId(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
@ -73,7 +73,8 @@ public class FAWEWorldNativeAccess_1_16 implements WorldNativeAccess<Chunk, IBlo
@Nullable
@Override
public IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
return chunk.setType(position, state, false);
return chunk.setType(position, state,
this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE));
}
@Override
@ -167,9 +168,4 @@ public class FAWEWorldNativeAccess_1_16 implements WorldNativeAccess<Chunk, IBlo
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

@ -12,15 +12,18 @@ import net.minecraft.server.v1_16_R1.NBTTagList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
public class LazyCompoundTag_1_16_1 extends CompoundTag {
private final Supplier<NBTTagCompound> nmsTag;
private CompoundTag cachedValue;
public LazyCompoundTag_1_16_1(Supplier<NBTTagCompound> tag) {
super(null);
super(new HashMap<>());
this.nmsTag = tag;
}
@ -34,12 +37,10 @@ public class LazyCompoundTag_1_16_1 extends CompoundTag {
@Override
public Map<String, Tag> getValue() {
Map<String, Tag> value = super.getValue();
if (value == null) {
Tag tag = WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
setValue(((CompoundTag) tag).getValue());
if (cachedValue == null) {
cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
}
return super.getValue();
return cachedValue.getValue();
}
public boolean containsKey(String key) {

View File

@ -199,51 +199,49 @@ public final class BukkitAdapter_1_16_2 extends NMSAdapter {
return;
}
if (playerChunk.hasBeenLoaded()) {
TaskManager.IMP.sync(() -> {
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
Optional<Chunk> optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
if (optional.isPresent()) {
PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(optional.get(), 65535);
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
Optional<Chunk> optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
if (optional.isPresent()) {
PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(optional.get(), 65535);
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
p.playerConnection.sendPacket(chunkpacket);
});
if (lighting) {
//This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad)
boolean trustEdges = true;
PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges);
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
p.playerConnection.sendPacket(chunkpacket);
p.playerConnection.sendPacket(packet);
});
}
} else if (PaperLib.isPaper()) {
//Require generic here to work with multiple dependencies trying to take control.
PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<?> objects =
nmsWorld.getChunkProvider().playerChunkMap.playerViewDistanceNoTickMap.getObjectsInRange(chunkX, chunkZ);
if (objects == null) {
return;
}
for (Object obj : objects.getBackingSet()) {
if (obj == null) {
continue;
}
EntityPlayer p = (EntityPlayer) obj;
Chunk chunk = nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
if (chunk != null) {
PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(chunk, 65535);
p.playerConnection.sendPacket(chunkpacket);
if (lighting) {
boolean trustEdges = true; //This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad)
PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges);
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
if (lighting) {
//This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad)
boolean trustEdges = true;
PacketPlayOutLightUpdate packet =
new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges);
p.playerConnection.sendPacket(packet);
});
}
} else if (PaperLib.isPaper()) {
//Require generic here to work with multiple dependencies trying to take control.
PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<?> objects =
nmsWorld.getChunkProvider().playerChunkMap.playerViewDistanceNoTickMap.getObjectsInRange(chunkX, chunkZ);
if (objects == null) {
return null;
}
for (Object obj : objects.getBackingSet()) {
if (obj == null) {
continue;
}
EntityPlayer p = (EntityPlayer) obj;
Chunk chunk = nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
if (chunk != null) {
PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(chunk, 65535);
p.playerConnection.sendPacket(chunkpacket);
if (lighting) {
boolean trustEdges =
true; //This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad)
PacketPlayOutLightUpdate packet =
new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges);
p.playerConnection.sendPacket(packet);
}
}
}
}
return null;
});
}
}
}

View File

@ -4,7 +4,6 @@ import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.blocks.CharBlocks;
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
@ -91,6 +90,7 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks {
public NibbleArray[] skyLight = new NibbleArray[16];
private boolean createCopy = false;
private BukkitGetBlocks_1_16_2_Copy copy = null;
private boolean forceLoadSections = true;
public BukkitGetBlocks_1_16_2(World world, int chunkX, int chunkZ) {
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
@ -319,7 +319,8 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks {
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
copy = createCopy ? new BukkitGetBlocks_1_16_2_Copy(world, getChunkX(), getChunkZ()) : null;
forceLoadSections = false;
copy = createCopy ? new BukkitGetBlocks_1_16_2_Copy(world) : null;
try {
WorldServer nmsWorld = world;
Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
@ -360,13 +361,14 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks {
if (!set.hasSection(layer)) {
continue;
}
if (createCopy) {
copy.storeSection(layer);
}
bitMask |= 1 << layer;
char[] setArr = set.load(layer);
char[] setArr = set.load(layer).clone();
if (createCopy) {
copy.storeSection(layer, load(layer).clone());
}
ChunkSection newSection;
ChunkSection existingSection = sections[layer];
if (existingSection == null) {
@ -395,7 +397,7 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks {
this.nmsChunk = nmsChunk;
this.sections = null;
this.reset();
} else if (existingSection != getSections()[layer]) {
} else if (existingSection != getSections(false)[layer]) {
this.sections[layer] = existingSection;
this.reset();
} else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) {
@ -408,7 +410,6 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks {
if (!BukkitAdapter_1_16_2
.setSectionAtomic(sections, existingSection, newSection, layer)) {
log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
continue;
} else {
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
}
@ -475,9 +476,7 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks {
Set<UUID> entityRemoves = set.getEntityRemoves();
if (entityRemoves != null && !entityRemoves.isEmpty()) {
if (syncTasks == null) {
syncTasks = new Runnable[3];
}
syncTasks = new Runnable[3];
syncTasks[2] = () -> {
final List<Entity>[] entities = nmsChunk.getEntitySlices();
@ -637,12 +636,14 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks {
} catch (Throwable e) {
e.printStackTrace();
return null;
} finally {
forceLoadSections = true;
}
}
@Override
public synchronized char[] update(int layer, char[] data) {
ChunkSection section = getSections()[layer];
ChunkSection section = getSections(true)[layer];
// Section is null, return empty array
if (section == null) {
data = new char[4096];
@ -757,7 +758,10 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks {
}
}
public ChunkSection[] getSections() {
public ChunkSection[] getSections(boolean force) {
if (force && forceLoadSections) {
return sections = getChunk().getSections().clone();
}
ChunkSection[] tmp = sections;
if (tmp == null) {
synchronized (this) {
@ -809,7 +813,7 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks {
@Override
public boolean hasSection(int layer) {
return getSections()[layer] != null;
return getSections(false)[layer] != null;
}
@Override
@ -822,10 +826,10 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks {
return super.trim(true);
} else {
for (int i = 0; i < 16; i++) {
if (!hasSection(i) || super.sections[i] == CharBlocks.EMPTY) {
if (!hasSection(i) || !super.sections[i].isFull()) {
continue;
}
ChunkSection existing = getSections()[i];
ChunkSection existing = getSections(true)[i];
try {
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();

View File

@ -2,6 +2,10 @@ package com.boydti.fawe.bukkit.adapter.mc1_16_2;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBlocks;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
import com.boydti.fawe.bukkit.adapter.mc1_16_2.nbt.LazyCompoundTag_1_16_2;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
@ -22,22 +26,25 @@ import net.minecraft.server.v1_16_R2.TileEntity;
import net.minecraft.server.v1_16_R2.WorldServer;
import org.bukkit.craftbukkit.v1_16_R2.block.CraftBlock;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Range;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
public class BukkitGetBlocks_1_16_2_Copy extends BukkitGetBlocks_1_16_2 {
public class BukkitGetBlocks_1_16_2_Copy implements IChunkGet {
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
private final Set<CompoundTag> entities = new HashSet<>();
private BiomeStorage biomeStorage;
private final char[][] blocks = new char[16][4096];
private final char[][] blocks = new char[16][];
private final WorldServer world;
protected BukkitGetBlocks_1_16_2_Copy(WorldServer world, int X, int Z) {
super(world, X, Z);
protected BukkitGetBlocks_1_16_2_Copy(WorldServer world) {
this.world = world;
}
protected void storeTile(TileEntity tile) {
@ -88,6 +95,16 @@ public class BukkitGetBlocks_1_16_2_Copy extends BukkitGetBlocks_1_16_2 {
return null;
}
@Override
public void setCreateCopy(boolean createCopy) {
}
@Override
public boolean isCreateCopy() {
return false;
}
protected void storeBiomes(BiomeStorage biomeStorage) {
this.biomeStorage = new BiomeStorage(biomeStorage.g, BukkitAdapter_1_16_2.getBiomeArray(biomeStorage).clone());
}
@ -106,8 +123,18 @@ public class BukkitGetBlocks_1_16_2_Copy extends BukkitGetBlocks_1_16_2 {
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(world.r().b(IRegistry.ay), base)) : null;
}
protected void storeSection(int layer) {
blocks[layer] = update(layer, null).clone();
@Override
public boolean trim(boolean aggressive, int layer) {
return false;
}
@Override
public IBlocks reset() {
return null;
}
protected void storeSection(int layer, char[] data) {
blocks[layer] = data;
}
@Override
@ -116,15 +143,50 @@ public class BukkitGetBlocks_1_16_2_Copy extends BukkitGetBlocks_1_16_2 {
return state.toBaseBlock(this, x, y, z);
}
@Override
public boolean hasSection(@Range(from = 0, to = 15) int layer) {
return blocks[layer] != null;
}
@Override
public char[] load(int layer) {
return blocks[layer];
}
@Override
public BlockState getBlock(int x, int y, int z) {
return BlockTypesCache.states[get(x, y, z)];
}
@Override
public int getSkyLight(int x, int y, int z) {
return 0;
}
@Override
public int getEmmittedLight(int x, int y, int z) {
return 0;
}
@Override
public int[] getHeightMap(HeightMapType type) {
return new int[0];
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
return null;
}
public char get(int x, int y, int z) {
final int layer = y >> 4;
final int index = (y & 15) << 8 | z << 4 | x;
return blocks[layer][index];
}
@Override
public boolean trim(boolean aggressive) {
return false;
}
}

View File

@ -59,7 +59,7 @@ public class FAWEWorldNativeAccess_1_16 implements WorldNativeAccess<Chunk, IBlo
@Override
public IBlockData toNative(BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
int stateId = adapter.ordinalToIbdID(state.getOrdinalChar());
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.getByCombinedId(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
@ -73,7 +73,8 @@ public class FAWEWorldNativeAccess_1_16 implements WorldNativeAccess<Chunk, IBlo
@Nullable
@Override
public IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
return chunk.setType(position, state, false);
return chunk.setType(position, state,
this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE));
}
@Override
@ -167,9 +168,4 @@ public class FAWEWorldNativeAccess_1_16 implements WorldNativeAccess<Chunk, IBlo
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

@ -12,15 +12,18 @@ import net.minecraft.server.v1_16_R2.NBTTagList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
public class LazyCompoundTag_1_16_2 extends CompoundTag {
private final Supplier<NBTTagCompound> nmsTag;
private CompoundTag cachedValue;
public LazyCompoundTag_1_16_2(Supplier<NBTTagCompound> tag) {
super(null);
super(new HashMap<>());
this.nmsTag = tag;
}
@ -34,12 +37,10 @@ public class LazyCompoundTag_1_16_2 extends CompoundTag {
@Override
public Map<String, Tag> getValue() {
Map<String, Tag> value = super.getValue();
if (value == null) {
Tag tag = WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
setValue(((CompoundTag) tag).getValue());
if (cachedValue == null) {
cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
}
return super.getValue();
return cachedValue.getValue();
}
public boolean containsKey(String key) {

View File

@ -199,51 +199,52 @@ public final class BukkitAdapter_1_16_4 extends NMSAdapter {
return;
}
if (playerChunk.hasBeenLoaded()) {
TaskManager.IMP.sync(() -> {
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
Optional<Chunk> optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
if (optional.isPresent()) {
PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(optional.get(), 65535);
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
Optional<Chunk> optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
if (optional.isPresent()) {
PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(optional.get(), 65535);
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
p.playerConnection.sendPacket(chunkpacket);
});
if (lighting) {
//This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad)
boolean trustEdges = true;
PacketPlayOutLightUpdate packet =
new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(),
trustEdges);
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
p.playerConnection.sendPacket(chunkpacket);
p.playerConnection.sendPacket(packet);
});
}
} else if (PaperLib.isPaper()) {
//Require generic here to work with multiple dependencies trying to take control.
PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<?> objects =
nmsWorld.getChunkProvider().playerChunkMap.playerViewDistanceNoTickMap
.getObjectsInRange(chunkX, chunkZ);
if (objects == null) {
return;
}
for (Object obj : objects.getBackingSet()) {
if (obj == null) {
continue;
}
EntityPlayer p = (EntityPlayer) obj;
Chunk chunk = nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
if (chunk != null) {
PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(chunk, 65535);
p.playerConnection.sendPacket(chunkpacket);
if (lighting) {
boolean trustEdges = true; //This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad)
PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges);
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
if (lighting) {
//This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad)
boolean trustEdges = true;
PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair,
nmsWorld.getChunkProvider().getLightEngine(), trustEdges);
p.playerConnection.sendPacket(packet);
});
}
} else if (PaperLib.isPaper()) {
//Require generic here to work with multiple dependencies trying to take control.
PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<?> objects =
nmsWorld.getChunkProvider().playerChunkMap.playerViewDistanceNoTickMap.getObjectsInRange(chunkX, chunkZ);
if (objects == null) {
return null;
}
for (Object obj : objects.getBackingSet()) {
if (obj == null) {
continue;
}
EntityPlayer p = (EntityPlayer) obj;
Chunk chunk = nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
if (chunk != null) {
PacketPlayOutMapChunk chunkpacket = new PacketPlayOutMapChunk(chunk, 65535);
p.playerConnection.sendPacket(chunkpacket);
if (lighting) {
boolean trustEdges =
true; //This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad)
PacketPlayOutLightUpdate packet =
new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(), trustEdges);
p.playerConnection.sendPacket(packet);
}
}
}
}
return null;
});
}
}
}

View File

@ -4,7 +4,6 @@ import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.blocks.CharBlocks;
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
@ -91,6 +90,7 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks {
public NibbleArray[] skyLight = new NibbleArray[16];
private boolean createCopy = false;
private BukkitGetBlocks_1_16_4_Copy copy = null;
private boolean forceLoadSections = true;
public BukkitGetBlocks_1_16_4(World world, int chunkX, int chunkZ) {
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
@ -319,7 +319,8 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks {
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
copy = createCopy ? new BukkitGetBlocks_1_16_4_Copy(world, getChunkX(), getChunkZ()) : null;
forceLoadSections = false;
copy = createCopy ? new BukkitGetBlocks_1_16_4_Copy(world) : null;
try {
WorldServer nmsWorld = world;
Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
@ -360,13 +361,14 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks {
if (!set.hasSection(layer)) {
continue;
}
if (createCopy) {
copy.storeSection(layer);
}
bitMask |= 1 << layer;
char[] setArr = set.load(layer);
char[] setArr = set.load(layer).clone();
if (createCopy) {
copy.storeSection(layer, load(layer).clone());
}
ChunkSection newSection;
ChunkSection existingSection = sections[layer];
if (existingSection == null) {
@ -395,7 +397,7 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks {
this.nmsChunk = nmsChunk;
this.sections = null;
this.reset();
} else if (existingSection != getSections()[layer]) {
} else if (existingSection != getSections(false)[layer]) {
this.sections[layer] = existingSection;
this.reset();
} else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) {
@ -408,7 +410,6 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks {
if (!BukkitAdapter_1_16_4
.setSectionAtomic(sections, existingSection, newSection, layer)) {
log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
continue;
} else {
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
}
@ -475,9 +476,7 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks {
Set<UUID> entityRemoves = set.getEntityRemoves();
if (entityRemoves != null && !entityRemoves.isEmpty()) {
if (syncTasks == null) {
syncTasks = new Runnable[3];
}
syncTasks = new Runnable[3];
syncTasks[2] = () -> {
final List<Entity>[] entities = nmsChunk.getEntitySlices();
@ -637,12 +636,14 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks {
} catch (Throwable e) {
e.printStackTrace();
return null;
} finally {
forceLoadSections = true;
}
}
@Override
public synchronized char[] update(int layer, char[] data) {
ChunkSection section = getSections()[layer];
ChunkSection section = getSections(true)[layer];
// Section is null, return empty array
if (section == null) {
data = new char[4096];
@ -757,7 +758,10 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks {
}
}
public ChunkSection[] getSections() {
public ChunkSection[] getSections(boolean force) {
if (force && forceLoadSections) {
return sections = getChunk().getSections().clone();
}
ChunkSection[] tmp = sections;
if (tmp == null) {
synchronized (this) {
@ -809,7 +813,7 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks {
@Override
public boolean hasSection(int layer) {
return getSections()[layer] != null;
return getSections(false)[layer] != null;
}
@Override
@ -822,10 +826,10 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks {
return super.trim(true);
} else {
for (int i = 0; i < 16; i++) {
if (!hasSection(i) || super.sections[i] == CharBlocks.EMPTY) {
if (!hasSection(i) || !super.sections[i].isFull()) {
continue;
}
ChunkSection existing = getSections()[i];
ChunkSection existing = getSections(true)[i];
try {
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();

View File

@ -2,6 +2,10 @@ package com.boydti.fawe.bukkit.adapter.mc1_16_4;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBlocks;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
import com.boydti.fawe.bukkit.adapter.mc1_16_4.nbt.LazyCompoundTag_1_16_4;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
@ -22,22 +26,25 @@ import net.minecraft.server.v1_16_R3.TileEntity;
import net.minecraft.server.v1_16_R3.WorldServer;
import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Range;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
public class BukkitGetBlocks_1_16_4_Copy extends BukkitGetBlocks_1_16_4 {
public class BukkitGetBlocks_1_16_4_Copy implements IChunkGet {
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
private final Set<CompoundTag> entities = new HashSet<>();
private BiomeStorage biomeStorage;
private final char[][] blocks = new char[16][4096];
private final char[][] blocks = new char[16][];
private final WorldServer world;
protected BukkitGetBlocks_1_16_4_Copy(WorldServer world, int X, int Z) {
super(world, X, Z);
protected BukkitGetBlocks_1_16_4_Copy(WorldServer world) {
this.world = world;
}
protected void storeTile(TileEntity tile) {
@ -88,6 +95,16 @@ public class BukkitGetBlocks_1_16_4_Copy extends BukkitGetBlocks_1_16_4 {
return null;
}
@Override
public void setCreateCopy(boolean createCopy) {
}
@Override
public boolean isCreateCopy() {
return false;
}
protected void storeBiomes(BiomeStorage biomeStorage) {
this.biomeStorage = new BiomeStorage(biomeStorage.g, BukkitAdapter_1_16_4.getBiomeArray(biomeStorage).clone());
}
@ -106,8 +123,18 @@ public class BukkitGetBlocks_1_16_4_Copy extends BukkitGetBlocks_1_16_4 {
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(world.r().b(IRegistry.ay), base)) : null;
}
protected void storeSection(int layer) {
blocks[layer] = update(layer, null).clone();
@Override
public boolean trim(boolean aggressive, int layer) {
return false;
}
@Override
public IBlocks reset() {
return null;
}
protected void storeSection(int layer, char[] data) {
blocks[layer] = data;
}
@Override
@ -116,15 +143,50 @@ public class BukkitGetBlocks_1_16_4_Copy extends BukkitGetBlocks_1_16_4 {
return state.toBaseBlock(this, x, y, z);
}
@Override
public boolean hasSection(@Range(from = 0, to = 15) int layer) {
return blocks[layer] != null;
}
@Override
public char[] load(int layer) {
return blocks[layer];
}
@Override
public BlockState getBlock(int x, int y, int z) {
return BlockTypesCache.states[get(x, y, z)];
}
@Override
public int getSkyLight(int x, int y, int z) {
return 0;
}
@Override
public int getEmmittedLight(int x, int y, int z) {
return 0;
}
@Override
public int[] getHeightMap(HeightMapType type) {
return new int[0];
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
return null;
}
public char get(int x, int y, int z) {
final int layer = y >> 4;
final int index = (y & 15) << 8 | z << 4 | x;
return blocks[layer][index];
}
@Override
public boolean trim(boolean aggressive) {
return false;
}
}

View File

@ -60,7 +60,7 @@ public class FAWEWorldNativeAccess_1_16 implements WorldNativeAccess<Chunk, IBlo
@Override
public IBlockData toNative(BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
int stateId = adapter.ordinalToIbdID(state.getOrdinalChar());
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.getByCombinedId(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
@ -74,7 +74,8 @@ public class FAWEWorldNativeAccess_1_16 implements WorldNativeAccess<Chunk, IBlo
@Nullable
@Override
public IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
return chunk.setType(position, state, false);
return chunk.setType(position, state,
this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE));
}
@Override
@ -168,9 +169,4 @@ public class FAWEWorldNativeAccess_1_16 implements WorldNativeAccess<Chunk, IBlo
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

@ -12,15 +12,18 @@ import net.minecraft.server.v1_16_R3.NBTTagList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
public class LazyCompoundTag_1_16_4 extends CompoundTag {
private final Supplier<NBTTagCompound> nmsTag;
private CompoundTag cachedValue;
public LazyCompoundTag_1_16_4(Supplier<NBTTagCompound> tag) {
super(null);
super(new HashMap<>());
this.nmsTag = tag;
}
@ -34,12 +37,10 @@ public class LazyCompoundTag_1_16_4 extends CompoundTag {
@Override
public Map<String, Tag> getValue() {
Map<String, Tag> value = super.getValue();
if (value == null) {
Tag tag = WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
setValue(((CompoundTag) tag).getValue());
if (cachedValue == null) {
cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
}
return super.getValue();
return cachedValue.getValue();
}
public boolean containsKey(String key) {

View File

@ -1,6 +1,5 @@
package com.boydti.fawe.bukkit.regions.plotsquared;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.clipboard.ReadOnlyClipboard;
import com.boydti.fawe.object.io.PGZIPOutputStream;
@ -9,36 +8,46 @@ import com.boydti.fawe.util.IOUtil;
import com.boydti.fawe.util.TaskManager;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.location.Location;
import com.plotsquared.core.plot.schematic.Schematic;
import com.plotsquared.core.queue.LocalBlockQueue;
import com.plotsquared.core.util.MainUtil;
import com.plotsquared.core.util.SchematicHandler;
import com.plotsquared.core.util.task.RunnableVal;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.CompressedCompoundTag;
import com.sk89q.jnbt.CompressedSchematicTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.Tag;
import com.sk89q.jnbt.fawe.CompressedSchematicTag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.FastSchematicReader;
import com.sk89q.worldedit.extent.clipboard.io.FastSchematicWriter;
import com.sk89q.worldedit.extent.clipboard.io.MCEditSchematicReader;
import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicReader;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.world.World;
import net.jpountz.lz4.LZ4BlockInputStream;
import org.jetbrains.annotations.NotNull;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.zip.GZIPInputStream;
import static org.bukkit.Bukkit.getWorld;
@ -114,16 +123,14 @@ public class FaweSchematicHandler extends SchematicHandler {
com.plotsquared.core.util.task.TaskManager.runTask(whenDone);
return;
}
CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag);
if (weTag instanceof CompressedSchematicTag) {
Clipboard clipboard = ((CompressedSchematicTag) weTag).getSource();
URL url = FaweAPI.upload(clipboard, BuiltInClipboardFormat.SPONGE_SCHEMATIC);
whenDone.run(url);
return;
}
final CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag);
MainUtil.upload(uuid, file, "schem", new RunnableVal<OutputStream>() {
@Override
public void run(OutputStream output) {
if (weTag instanceof CompressedSchematicTag) {
Clipboard clipboard = ((CompressedSchematicTag) weTag).getSource();
BuiltInClipboardFormat.SPONGE_SCHEMATIC.write(output, clipboard);
}
try {
try (PGZIPOutputStream gzip = new PGZIPOutputStream(output)) {
try (NBTOutputStream nos = new NBTOutputStream(gzip)) {
@ -137,4 +144,42 @@ public class FaweSchematicHandler extends SchematicHandler {
}
}, whenDone);
}
@Override
public Schematic getSchematic(@NotNull InputStream is) {
try {
FastSchematicReader schematicReader = new FastSchematicReader(
new NBTInputStream(new BufferedInputStream(new GZIPInputStream(new BufferedInputStream(is)))));
Clipboard clip = schematicReader.read();
return new Schematic(clip);
} catch (IOException e) {
if (e instanceof EOFException) {
e.printStackTrace();
return null;
}
try {
SpongeSchematicReader schematicReader =
new SpongeSchematicReader(new NBTInputStream(new GZIPInputStream(is)));
Clipboard clip = schematicReader.read();
return new Schematic(clip);
} catch (IOException e2) {
if (e2 instanceof EOFException) {
e.printStackTrace();
return null;
}
try {
MCEditSchematicReader schematicReader =
new MCEditSchematicReader(new NBTInputStream(new GZIPInputStream(is)));
Clipboard clip = schematicReader.read();
return new Schematic(clip);
} catch (IOException e3) {
e.printStackTrace();
PlotSquared.debug(
is.toString() + " | " + is.getClass().getCanonicalName() + " is not in GZIP format : " + e
.getMessage());
}
}
}
return null;
}
}

View File

@ -15,7 +15,7 @@ import com.github.intellectualsites.plotsquared.plot.util.SchematicHandler;
import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.CompressedCompoundTag;
import com.sk89q.jnbt.CompressedSchematicTag;
import com.sk89q.jnbt.fawe.CompressedSchematicTag;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession;
@ -65,6 +65,7 @@ public class FaweSchematicHandler extends SchematicHandler {
ReadOnlyClipboard clipboard = ReadOnlyClipboard.of(editSession, region, false, true);
Clipboard holder = new BlockArrayClipboard(region, clipboard);
CompressedSchematicTag tag = new CompressedSchematicTag(holder);
whenDone.run(tag);
});

View File

@ -26,8 +26,8 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.RayTraceResult;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@ -70,32 +70,32 @@ public class AsyncBlock implements Block {
return world.getBlock(x, y, z).getBlockType().getInternalId();
}
@NotNull
@Nonnull
@Override
public AsyncBlock getRelative(int modX, int modY, int modZ) {
return new AsyncBlock(world, x + modX, y + modY, z + modZ);
}
@NotNull
@Nonnull
@Override
public AsyncBlock getRelative(BlockFace face) {
return this.getRelative(face.getModX(), face.getModY(), face.getModZ());
}
@NotNull
@Nonnull
@Override
public AsyncBlock getRelative(BlockFace face, int distance) {
return this.getRelative(face.getModX() * distance, face.getModY() * distance,
face.getModZ() * distance);
}
@NotNull
@Nonnull
@Override
public Material getType() {
return getBlockData().getMaterial();
}
@NotNull
@Nonnull
@Override
public BlockData getBlockData() {
return BukkitAdapter.adapt(world.getBlock(x, y, z));
@ -141,7 +141,7 @@ public class AsyncBlock implements Block {
return (byte) 15;
}
@NotNull
@Nonnull
@Override
public AsyncWorld getWorld() {
return world;
@ -162,7 +162,7 @@ public class AsyncBlock implements Block {
return z;
}
@NotNull
@Nonnull
@Override
public Location getLocation() {
return new Location(world, x, y, z);
@ -179,14 +179,14 @@ public class AsyncBlock implements Block {
return loc;
}
@NotNull
@Nonnull
@Override
public AsyncChunk getChunk() {
return world.getChunkAt(x >> 4, z >> 4);
}
@Override
public void setBlockData(@NotNull BlockData blockData) {
public void setBlockData(@Nonnull BlockData blockData) {
try {
world.setBlock(x, y, z, BukkitAdapter.adapt(blockData));
} catch (WorldEditException e) {
@ -195,12 +195,12 @@ public class AsyncBlock implements Block {
}
@Override
public void setBlockData(@NotNull BlockData blockData, boolean b) {
public void setBlockData(@Nonnull BlockData blockData, boolean b) {
setBlockData(blockData);
}
@Override
public void setType(@NotNull Material type) {
public void setType(@Nonnull Material type) {
try {
world.setBlock(x, y, z, BukkitAdapter.asBlockType(type).getDefaultState());
} catch (WorldEditException e) {
@ -209,12 +209,12 @@ public class AsyncBlock implements Block {
}
@Override
public void setType(@NotNull Material type, boolean applyPhysics) {
public void setType(@Nonnull Material type, boolean applyPhysics) {
setType(type);
}
@Override
public BlockFace getFace(@NotNull Block block) {
public BlockFace getFace(@Nonnull Block block) {
BlockFace[] directions = BlockFace.values();
for (BlockFace face : directions) {
if (this.getX() + face.getModX() == block.getX()
@ -226,7 +226,7 @@ public class AsyncBlock implements Block {
return null;
}
@NotNull
@Nonnull
@Override
public AsyncBlockState getState() {
BaseBlock state = world.getFullBlock(x, y, z);
@ -250,19 +250,19 @@ public class AsyncBlock implements Block {
}
@Override
@NotNull
@Nonnull
public AsyncBlockState getState(boolean useSnapshot) {
return getState();
}
@NotNull
@Nonnull
@Override
public Biome getBiome() {
return world.getAdapter().adapt(world.getBiomeType(x, y, z));
}
@Override
public void setBiome(@NotNull Biome bio) {
public void setBiome(@Nonnull Biome bio) {
BiomeType biome = world.getAdapter().adapt(bio);
world.setBiome(x, 0, z, biome);
}
@ -278,17 +278,17 @@ public class AsyncBlock implements Block {
}
@Override
public boolean isBlockFacePowered(@NotNull BlockFace face) {
public boolean isBlockFacePowered(@Nonnull BlockFace face) {
return false;
}
@Override
public boolean isBlockFaceIndirectlyPowered(@NotNull BlockFace face) {
public boolean isBlockFaceIndirectlyPowered(@Nonnull BlockFace face) {
return false;
}
@Override
public int getBlockPower(@NotNull BlockFace face) {
public int getBlockPower(@Nonnull BlockFace face) {
return 0;
}
@ -314,6 +314,21 @@ public class AsyncBlock implements Block {
return world.getBlock(x, y, z).getMaterial().isLiquid();
}
@Override
public boolean isBuildable() {
return this.getUnsafeBlock().isBuildable();
}
@Override
public boolean isBurnable() {
return this.getType().isBurnable();
}
@Override
public boolean isReplaceable() {
return this.getUnsafeBlock().isReplaceable();
}
@Override
public double getTemperature() {
return this.getWorld().getTemperature(this.getX(), this.getZ());
@ -324,7 +339,7 @@ public class AsyncBlock implements Block {
return this.getWorld().getHumidity(this.getX(), this.getZ());
}
@NotNull
@Nonnull
@Override
public PistonMoveReaction getPistonMoveReaction() {
return PistonMoveReaction.IGNORE;
@ -341,23 +356,23 @@ public class AsyncBlock implements Block {
}
@Override
public boolean breakNaturally(@NotNull ItemStack tool) {
public boolean breakNaturally(@Nonnull ItemStack tool) {
return TaskManager.IMP.sync(() -> getUnsafeBlock().breakNaturally(tool));
}
public boolean breakNaturally(@NotNull ItemStack tool, boolean value) {
public boolean breakNaturally(@Nonnull ItemStack tool, boolean value) {
return TaskManager.IMP.sync(() -> getUnsafeBlock().breakNaturally(tool));
}
@NotNull
@Nonnull
@Override
public Collection<ItemStack> getDrops() {
return TaskManager.IMP.sync(() -> getUnsafeBlock().getDrops());
}
@NotNull
@Nonnull
@Override
public Collection<ItemStack> getDrops(@NotNull ItemStack tool) {
public Collection<ItemStack> getDrops(@Nonnull ItemStack tool) {
return TaskManager.IMP.sync(() -> getUnsafeBlock().getDrops(tool));
}
@ -366,23 +381,23 @@ public class AsyncBlock implements Block {
}
@Override
public void setMetadata(@NotNull String metadataKey, @NotNull MetadataValue newMetadataValue) {
public void setMetadata(@Nonnull String metadataKey, @Nonnull MetadataValue newMetadataValue) {
this.getUnsafeBlock().setMetadata(metadataKey, newMetadataValue);
}
@NotNull
@Nonnull
@Override
public List<MetadataValue> getMetadata(@NotNull String metadataKey) {
public List<MetadataValue> getMetadata(@Nonnull String metadataKey) {
return this.getUnsafeBlock().getMetadata(metadataKey);
}
@Override
public boolean hasMetadata(@NotNull String metadataKey) {
public boolean hasMetadata(@Nonnull String metadataKey) {
return this.getUnsafeBlock().hasMetadata(metadataKey);
}
@Override
public void removeMetadata(@NotNull String metadataKey, @NotNull Plugin owningPlugin) {
public void removeMetadata(@Nonnull String metadataKey, @Nonnull Plugin owningPlugin) {
this.getUnsafeBlock().removeMetadata(metadataKey, owningPlugin);
}
@ -392,12 +407,12 @@ public class AsyncBlock implements Block {
}
@Override
public RayTraceResult rayTrace(@NotNull Location arg0, @NotNull Vector arg1, double arg2,
@NotNull FluidCollisionMode arg3) {
public RayTraceResult rayTrace(@Nonnull Location arg0, @Nonnull Vector arg1, double arg2,
@Nonnull FluidCollisionMode arg3) {
return this.getUnsafeBlock().rayTrace(arg0, arg1, arg2, arg3);
}
public boolean applyBoneMeal(@NotNull BlockFace face) {
public boolean applyBoneMeal(@Nonnull BlockFace face) {
throw new UnsupportedOperationException("FAWE does not support this yet");
}
@ -405,22 +420,28 @@ public class AsyncBlock implements Block {
throw new UnsupportedOperationException("FAWE does not support this yet");
}
@NotNull
@Nonnull
@Override
public float getDestroySpeed(@NotNull ItemStack itemStack) {
public float getDestroySpeed(@Nonnull ItemStack itemStack) {
throw new UnsupportedOperationException("FAWE does not support this yet");
}
@NotNull
@Nonnull
@Override
public BoundingBox getBoundingBox() {
return this.getUnsafeBlock().getBoundingBox();
}
@Override
@NotNull
@Nonnull
public BlockSoundGroup getSoundGroup() {
return TaskManager.IMP.sync(() -> getUnsafeBlock().getSoundGroup());
}
@Override
@Nonnull
public boolean isSolid() {
return this.getType().isSolid();
}
}

View File

@ -1,6 +1,7 @@
package com.boydti.fawe.bukkit.wrapper;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.world.block.BaseBlock;
@ -16,8 +17,12 @@ import org.bukkit.material.MaterialData;
import org.bukkit.metadata.MetadataValue;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class AsyncBlockState implements BlockState {
@ -25,10 +30,6 @@ public class AsyncBlockState implements BlockState {
private BlockData blockData;
private final AsyncBlock block;
public AsyncBlockState(AsyncBlock block) {
this(block, block.world.getFullBlock(block.x, block.y, block.z));
}
public AsyncBlockState(AsyncBlock block, BaseBlock state) {
this.state = state;
this.block = block;
@ -112,11 +113,11 @@ public class AsyncBlockState implements BlockState {
@Override
public void setBlockData(BlockData blockData) {
this.blockData = blockData;
CompoundTag nbt = state.getNbtData();
CompoundTag nbt = this.getNbtData();
BlockType oldType = state.getBlockType();
com.sk89q.worldedit.world.block.BlockState newState = BukkitAdapter.adapt(blockData);
if (nbt != null && newState.getBlockType() == oldType) {
state = newState.toBaseBlock(nbt);
this.setNbtData(nbt);
} else {
state = newState.toBaseBlock();
}
@ -146,14 +147,47 @@ public class AsyncBlockState implements BlockState {
}
}
public CompoundTag getNbtData() {
/**
* Returns the (unmodifiable) tag compound that belongs to this block state.
* If the block state is null, this will return null.
*
* @return NBT data
*/
public synchronized @Nullable CompoundTag getNbtData() {
if (this.state == null) {
return null;
}
return state.getNbtData();
}
public void setNbtData(CompoundTag nbt) {
/**
* Clone the NBT {@link CompoundTag} into a new {@link Map}.
*
* @return Modifiable clone of NBT data
*/
public @NotNull Map<String, Tag> cloneNbtMap() {
return Optional.ofNullable(this.getNbtData()).map(CompoundTag::getValue)
.map(HashMap::new).orElse(new HashMap<>());
}
/**
* Set the NBT data of the block.
*
* @param nbt New NBT data
*/
public synchronized void setNbtData(@Nullable final CompoundTag nbt) {
state = this.state.toBaseBlock(nbt);
}
/**
* Set the NBT data of the block.
*
* @param map New NBT data
*/
public void setNbtData(@NotNull final Map<String, Tag> map) {
this.setNbtData(new CompoundTag(map));
}
@Override
public byte getRawData() {
return (byte) (state.getInternalId() >> BlockTypesCache.BIT_OFFSET);
@ -163,7 +197,7 @@ public class AsyncBlockState implements BlockState {
public void setRawData(byte data) {
int combinedId = getTypeId() + (data << BlockTypesCache.BIT_OFFSET);
state = com.sk89q.worldedit.world.block.BlockState.getFromInternalId(combinedId)
.toBaseBlock(state.getNbtData());
.toBaseBlock(this.getNbtData());
this.blockData = BukkitAdapter.adapt(state);
}

View File

@ -6,6 +6,7 @@ import com.boydti.fawe.util.TaskManager;
import org.bukkit.Chunk;
import org.bukkit.ChunkSnapshot;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Entity;
@ -14,6 +15,8 @@ import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class AsyncChunk implements Chunk {
@ -120,6 +123,16 @@ public class AsyncChunk implements Chunk {
return TaskManager.IMP.sync(() -> world.getChunkAt(x, z).getTileEntities(useSnapshot));
}
@NotNull @Override
public Collection<BlockState> getTileEntities(@NotNull Predicate<Block> blockPredicate,
boolean useSnapshot) {
if (!isLoaded()) {
return Collections.emptyList();
}
return TaskManager.IMP.sync(() -> world.getChunkAt(x, z)
.getTileEntities(blockPredicate, useSnapshot));
}
@Override
public boolean isLoaded() {
return world.isChunkLoaded(x, z);

View File

@ -16,17 +16,24 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
public final class AsyncDataContainer implements PersistentDataContainer {
private final CompoundTag root;
public AsyncDataContainer(CompoundTag root) {
this.root = root;
private final Supplier<CompoundTag> supplier;
private final Consumer<CompoundTag> consumer;
public AsyncDataContainer(
final @NotNull Supplier<CompoundTag> supplier,
final @NotNull Consumer<CompoundTag> consumer
) {
this.supplier = supplier;
this.consumer = consumer;
}
private CompoundTag root() {
CompoundTag value = (CompoundTag) root.getValue().get("PublicBukkitValues");
return value;
return (CompoundTag) supplier.get().getValue().get("PublicBukkitValues");
}
private Map<String, Tag> get() {
@ -40,8 +47,9 @@ public final class AsyncDataContainer implements PersistentDataContainer {
if (!create) {
return Collections.emptyMap();
}
Map<String, Tag> map = root.getValue();
final Map<String, Tag> map = new HashMap<>(root().getValue());
map.put("PublicBukkitValues", new CompoundTag(raw = new HashMap<>()));
this.consumer.accept(new CompoundTag(map));
} else {
raw = tag.getValue();
}
@ -52,7 +60,14 @@ public final class AsyncDataContainer implements PersistentDataContainer {
Validate.notNull(key, "The provided key for the custom value was null");
Validate.notNull(type, "The provided type for the custom value was null");
Validate.notNull(value, "The provided value for the custom value was null");
get().put(key.toString(), FaweCache.IMP.asTag(type.toPrimitive(value, null)));
// Modify public values
final Map<String, Tag> publicValues = new HashMap<>(this.get());
publicValues.put(key.toString(), FaweCache.IMP.asTag(type.toPrimitive(value, null)));
// Modify the root tag
final Map<String, Tag> map = new HashMap<>(root().getValue());
map.put("PublicBukkitValues", new CompoundTag(publicValues));
// Update the owning object
this.consumer.accept(new CompoundTag(map));
}
public <T, Z> boolean has(NamespacedKey key, PersistentDataType<T, Z> type) {
@ -60,7 +75,7 @@ public final class AsyncDataContainer implements PersistentDataContainer {
Validate.notNull(type, "The provided type for the custom value was null");
Tag value = get(false).get(key.toString());
if (value == null) {
return type == null;
return false;
}
return type.getPrimitiveType() == value.getValue().getClass();
}
@ -93,7 +108,14 @@ public final class AsyncDataContainer implements PersistentDataContainer {
public void remove(NamespacedKey key) {
Validate.notNull(key, "The provided key for the custom value was null");
get(false).remove(key.toString());
// Modify public values
final Map<String, Tag> publicValues = new HashMap<>(this.get(false));
publicValues.remove(key.toString());
// Modify the root tag
final Map<String, Tag> map = new HashMap<>(root().getValue());
map.put("PublicBukkitValues", new CompoundTag(publicValues));
// Update the owning object
this.consumer.accept(new CompoundTag(map));
}
public boolean isEmpty() {

View File

@ -19,6 +19,7 @@ import java.util.Locale;
import java.util.Map;
public class AsyncSign extends AsyncBlockState implements Sign {
public AsyncSign(AsyncBlock block, BaseBlock state) {
super(block, state);
}
@ -59,11 +60,12 @@ public class AsyncSign extends AsyncBlockState implements Sign {
@Override
public void setLine(int index, String line) throws IndexOutOfBoundsException {
CompoundTag nbt = getNbtData();
if (nbt != null) {
Map<String, Tag> map = nbt.getValue();
map.put("Text" + (index + 1), new StringTag(toJson(line)));
final Map<String, Tag> map = this.cloneNbtMap();
if (map.isEmpty()) {
return;
}
map.put("Text" + (index + 1), new StringTag(toJson(line)));
this.setNbtData(map);
}
@Override
@ -79,13 +81,13 @@ public class AsyncSign extends AsyncBlockState implements Sign {
@Override
@NotNull
public PersistentDataContainer getPersistentDataContainer() {
return new AsyncDataContainer(getNbtData());
return new AsyncDataContainer(this::getNbtData, this::setNbtData);
}
@Override
@Nullable
public DyeColor getColor() {
CompoundTag nbt = getNbtData();
CompoundTag nbt = this.getNbtData();
if (nbt != null) {
String color = nbt.getString("Color").toUpperCase(Locale.ROOT);
if (!color.isEmpty()) {
@ -97,10 +99,11 @@ public class AsyncSign extends AsyncBlockState implements Sign {
@Override
public void setColor(DyeColor color) {
CompoundTag nbt = getNbtData();
if (nbt != null) {
Map<String, Tag> map = nbt.getValue();
map.put("Color", new StringTag(color.name().toLowerCase(Locale.ROOT)));
final Map<String, Tag> map = this.cloneNbtMap();
if (map.isEmpty()) {
return;
}
map.put("Color", new StringTag(color.name().toLowerCase(Locale.ROOT)));
this.setNbtData(map);
}
}

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.bukkit;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.bukkit.FaweBukkit;
import com.google.common.base.Joiner;
@ -93,19 +92,6 @@ import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAM
*/
public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
// This must be before the Logger is initialized, which fails in 1.8
private static final String FAILED_VERSION_CHECK =
"\n**********************************************\n"
+ "** This Minecraft version (%s) is not supported by this version of WorldEdit.\n"
+ "** Please download an OLDER version of WorldEdit which does.\n"
+ "**********************************************\n";
static {
if (PaperLib.getMinecraftVersion() < 13) {
throw new IllegalStateException(String.format(FAILED_VERSION_CHECK, Bukkit.getVersion()));
}
}
private static final Logger log = LoggerFactory.getLogger(WorldEditPlugin.class);
public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui";
private static WorldEditPlugin INSTANCE;

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.bukkit.adapter.impl;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
@ -93,20 +92,21 @@ import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.OptionalInt;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<NBTBase> {
private final Spigot_v1_15_R2 parent;
private char[] ibdToStateOrdinal;
private int[] ordinalToIbdID;
// ------------------------------------------------------------------------
// Code that may break between versions of Minecraft
// ------------------------------------------------------------------------
@ -124,12 +124,15 @@ public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements I
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
return false;
}
ibdToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
BlockState state = BlockTypesCache.states[i];
BlockMaterial_1_15_2 material = (BlockMaterial_1_15_2) state.getMaterial();
int id = Block.REGISTRY_ID.getId(material.getState());
ibdToStateOrdinal[id] = state.getOrdinalChar();
char ordinal = state.getOrdinalChar();
ibdToStateOrdinal[id] = ordinal;
ordinalToIbdID[ordinal] = id;
}
return true;
}
@ -267,13 +270,13 @@ public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements I
if (id != null) {
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
Supplier<CompoundTag> saveTag = () -> {
NBTTagCompound tag = new NBTTagCompound();
readEntityIntoTag(mcEntity, tag);
final NBTTagCompound minecraftTag = new NBTTagCompound();
readEntityIntoTag(mcEntity, minecraftTag);
//add Id for AbstractChangeSet to work
CompoundTag natve = (CompoundTag) toNative(tag);
natve.getValue().put("Id", new StringTag(id));
return natve;
final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
final Map<String, Tag> tags = new HashMap<>(tag.getValue());
tags.put("Id", new StringTag(id));
return new CompoundTag(tags);
};
return new LazyBaseEntity(type, saveTag);
} else {
@ -347,6 +350,16 @@ public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements I
}
}
}
public int ordinalToIbdID(char ordinal) {
synchronized (this) {
try {
return ordinalToIbdID[ordinal];
} catch (NullPointerException e) {
init();
return ordinalToIbdID(ordinal);
}
}
}
@Override
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {

View File

@ -92,20 +92,21 @@ import org.bukkit.craftbukkit.v1_16_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_16_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.OptionalInt;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
public final class FAWE_Spigot_v1_16_R1 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<NBTBase> {
private final Spigot_v1_16_R1 parent;
private char[] ibdToStateOrdinal;
private int[] ordinalToIbdID;
// ------------------------------------------------------------------------
// Code that may break between versions of Minecraft
// ------------------------------------------------------------------------
@ -123,12 +124,15 @@ public final class FAWE_Spigot_v1_16_R1 extends CachedBukkitAdapter implements I
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
return false;
}
ibdToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
BlockState state = BlockTypesCache.states[i];
BlockMaterial_1_16_1 material = (BlockMaterial_1_16_1) state.getMaterial();
int id = Block.REGISTRY_ID.getId(material.getState());
ibdToStateOrdinal[id] = state.getOrdinalChar();
char ordinal = state.getOrdinalChar();
ibdToStateOrdinal[id] = ordinal;
ordinalToIbdID[ordinal] = id;
}
return true;
}
@ -266,13 +270,13 @@ public final class FAWE_Spigot_v1_16_R1 extends CachedBukkitAdapter implements I
if (id != null) {
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
Supplier<CompoundTag> saveTag = () -> {
NBTTagCompound tag = new NBTTagCompound();
readEntityIntoTag(mcEntity, tag);
final NBTTagCompound minecraftTag = new NBTTagCompound();
readEntityIntoTag(mcEntity, minecraftTag);
//add Id for AbstractChangeSet to work
CompoundTag natve = (CompoundTag) toNative(tag);
natve.getValue().put("Id", new StringTag(id));
return natve;
final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
final Map<String, Tag> tags = new HashMap<>(tag.getValue());
tags.put("Id", new StringTag(id));
return new CompoundTag(tags);
};
return new LazyBaseEntity(type, saveTag);
} else {
@ -347,6 +351,17 @@ public final class FAWE_Spigot_v1_16_R1 extends CachedBukkitAdapter implements I
}
}
public int ordinalToIbdID(char ordinal) {
synchronized (this) {
try {
return ordinalToIbdID[ordinal];
} catch (NullPointerException e) {
init();
return ordinalToIbdID(ordinal);
}
}
}
@Override
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {
BlockMaterial_1_16_1 material = (BlockMaterial_1_16_1) state.getMaterial();

View File

@ -92,20 +92,22 @@ import org.bukkit.craftbukkit.v1_16_R2.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_16_R2.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.OptionalInt;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
public final class FAWE_Spigot_v1_16_R2 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<NBTBase> {
private final Spigot_v1_16_R2 parent;
private char[] ibdToStateOrdinal;
private int[] ordinalToIbdID;
// ------------------------------------------------------------------------
// Code that may break between versions of Minecraft
@ -124,12 +126,15 @@ public final class FAWE_Spigot_v1_16_R2 extends CachedBukkitAdapter implements I
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
return false;
}
ibdToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
BlockState state = BlockTypesCache.states[i];
BlockMaterial_1_16_2 material = (BlockMaterial_1_16_2) state.getMaterial();
int id = Block.REGISTRY_ID.getId(material.getState());
ibdToStateOrdinal[id] = state.getOrdinalChar();
char ordinal = state.getOrdinalChar();
ibdToStateOrdinal[id] = ordinal;
ordinalToIbdID[ordinal] = id;
}
return true;
}
@ -267,13 +272,13 @@ public final class FAWE_Spigot_v1_16_R2 extends CachedBukkitAdapter implements I
if (id != null) {
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
Supplier<CompoundTag> saveTag = () -> {
NBTTagCompound tag = new NBTTagCompound();
readEntityIntoTag(mcEntity, tag);
final NBTTagCompound minecraftTag = new NBTTagCompound();
readEntityIntoTag(mcEntity, minecraftTag);
//add Id for AbstractChangeSet to work
CompoundTag natve = (CompoundTag) toNative(tag);
natve.getValue().put("Id", new StringTag(id));
return natve;
final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
final Map<String, Tag> tags = new HashMap<>(tag.getValue());
tags.put("Id", new StringTag(id));
return new CompoundTag(tags);
};
return new LazyBaseEntity(type, saveTag);
} else {
@ -347,6 +352,16 @@ public final class FAWE_Spigot_v1_16_R2 extends CachedBukkitAdapter implements I
}
}
}
public int ordinalToIbdID(char ordinal) {
synchronized (this) {
try {
return ordinalToIbdID[ordinal];
} catch (NullPointerException e) {
init();
return ordinalToIbdID(ordinal);
}
}
}
@Override
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.bukkit.adapter.impl;
import com.bekvon.bukkit.residence.commands.material;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
@ -96,6 +95,7 @@ import org.bukkit.entity.Player;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.OptionalInt;
import java.util.Set;
@ -107,6 +107,7 @@ import static org.slf4j.LoggerFactory.getLogger;
public final class FAWE_Spigot_v1_16_R3 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<NBTBase> {
private final Spigot_v1_16_R3 parent;
private char[] ibdToStateOrdinal;
private int[] ordinalToIbdID;
// ------------------------------------------------------------------------
// Code that may break between versions of Minecraft
@ -125,12 +126,15 @@ public final class FAWE_Spigot_v1_16_R3 extends CachedBukkitAdapter implements I
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
return false;
}
ibdToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
BlockState state = BlockTypesCache.states[i];
BlockMaterial_1_16_4 material = (BlockMaterial_1_16_4) state.getMaterial();
int id = Block.REGISTRY_ID.getId(material.getState());
ibdToStateOrdinal[id] = state.getOrdinalChar();
char ordinal = state.getOrdinalChar();
ibdToStateOrdinal[id] = ordinal;
ordinalToIbdID[ordinal] = id;
}
return true;
}
@ -268,13 +272,13 @@ public final class FAWE_Spigot_v1_16_R3 extends CachedBukkitAdapter implements I
if (id != null) {
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
Supplier<CompoundTag> saveTag = () -> {
NBTTagCompound tag = new NBTTagCompound();
readEntityIntoTag(mcEntity, tag);
final NBTTagCompound minecraftTag = new NBTTagCompound();
readEntityIntoTag(mcEntity, minecraftTag);
//add Id for AbstractChangeSet to work
CompoundTag natve = (CompoundTag) toNative(tag);
natve.getValue().put("Id", new StringTag(id));
return natve;
final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
final Map<String, Tag> tags = new HashMap<>(tag.getValue());
tags.put("Id", new StringTag(id));
return new CompoundTag(tags);
};
return new LazyBaseEntity(type, saveTag);
} else {
@ -349,6 +353,17 @@ public final class FAWE_Spigot_v1_16_R3 extends CachedBukkitAdapter implements I
}
}
public int ordinalToIbdID(char ordinal) {
synchronized (this) {
try {
return ordinalToIbdID[ordinal];
} catch (NullPointerException e) {
init();
return ordinalToIbdID(ordinal);
}
}
}
@Override
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {
BlockMaterial_1_16_4 material = (BlockMaterial_1_16_4) state.getMaterial();

View File

@ -28,14 +28,14 @@ configurations.all {
dependencies {
"api"(project(":worldedit-libs:core"))
"implementation"("de.schlichtherle:truezip:6.8.3")
"implementation"("net.java.truevfs:truevfs-profile-default_2.13:0.12.1")
"implementation"("de.schlichtherle:truezip:6.8.4")
"implementation"("net.java.truevfs:truevfs-profile-default_2.13:0.12.2")
"implementation"("org.mozilla:rhino-runtime:1.7.12")
"implementation"("org.yaml:snakeyaml:1.23")
"implementation"("org.yaml:snakeyaml:1.27")
"implementation"("com.google.guava:guava:${Versions.GUAVA}")
"implementation"("com.google.code.findbugs:jsr305:3.0.2")
"implementation"("com.google.code.gson:gson:${Versions.GSON}")
"implementation"("org.slf4j:slf4j-api:1.7.27")
"implementation"("org.slf4j:slf4j-api:1.7.30")
"implementation"("it.unimi.dsi:fastutil:${Versions.FAST_UTIL}")
val antlrVersion = "4.7.2"
@ -51,14 +51,15 @@ dependencies {
"annotationProcessor"("com.google.auto.value:auto-value:${Versions.AUTO_VALUE}")
"testImplementation"("ch.qos.logback:logback-core:${Versions.LOGBACK}")
"testImplementation"("ch.qos.logback:logback-classic:${Versions.LOGBACK}")
"compile"("com.github.luben:zstd-jni:1.4.3-1")
"compile"("com.github.luben:zstd-jni:1.4.8-1")
"compileOnly"("net.fabiozumbi12:redprotect:1.9.6")
"compile"("com.github.intellectualsites.plotsquared:PlotSquared-API:latest") {
isTransitive = false
}
"compile"("com.plotsquared:PlotSquared-Core:5.12.2") {
"compile"("com.plotsquared:PlotSquared-Core:5.13.3") {
isTransitive = false
}
"api"("com.intellectualsites.paster:Paster:1.0.1-SNAPSHOT")
}
tasks.named<Test>("test") {
@ -109,7 +110,7 @@ tasks.named<Copy>("processResources") {
}
tasks.named<ShadowJar>("shadowJar") {
dependencies {
include(dependency("com.github.luben:zstd-jni:1.4.3-1"))
include(dependency("com.github.luben:zstd-jni:1.4.8-1"))
}
}

View File

@ -235,8 +235,8 @@ public class Fawe {
// Setting up config.yml
File file = new File(this.implementation.getDirectory(), "config.yml");
Settings.IMP.PLATFORM = implementation.getPlatform().replace("\"", "");
try (InputStream stream = getClass().getResourceAsStream(File.separator + "fawe.properties");
BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
try (InputStream stream = getClass().getResourceAsStream("/fawe.properties");
BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
String versionString = br.readLine();
String commitString = br.readLine();
String dateString = br.readLine();

View File

@ -9,39 +9,57 @@ import org.jetbrains.annotations.Range;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.locks.ReentrantLock;
public abstract class CharBlocks implements IBlocks {
public static final Logger logger = LoggerFactory.getLogger(CharBlocks.class);
public static final Section FULL = new Section() {
protected static final Section FULL = new Section() {
@Override
public final char[] get(CharBlocks blocks, int layer) {
return blocks.blocks[layer];
}
};
public static final Section EMPTY = new Section() {
@Override
public final synchronized char[] get(CharBlocks blocks, int layer) {
char[] arr = blocks.blocks[layer];
if (arr == null) {
arr = blocks.blocks[layer] = blocks.update(layer, null);
public final boolean isFull() {
return true;
}
};
protected static final Section EMPTY = new Section() {
@Override
public final char[] get(CharBlocks blocks, int layer) {
blocks.loadLock.lock();
try {
char[] arr = blocks.blocks[layer];
if (arr == null) {
throw new IllegalStateException("Array cannot be null: " + blocks.getClass());
arr = blocks.blocks[layer] = blocks.update(layer, null);
if (arr == null) {
throw new IllegalStateException("Array cannot be null: " + blocks.getClass());
}
} else {
blocks.blocks[layer] = blocks.update(layer, arr);
if (blocks.blocks[layer] == null) {
throw new IllegalStateException("Array cannot be null (update): " + blocks.getClass());
}
}
} else {
blocks.blocks[layer] = blocks.update(layer, arr);
if (blocks.blocks[layer] == null) {
throw new IllegalStateException("Array cannot be null (update): " + blocks.getClass());
if (blocks.blocks[layer] != null) {
blocks.sections[layer] = FULL;
}
return arr;
} finally {
blocks.loadLock.unlock();
}
if (blocks.blocks[layer] != null) {
blocks.sections[layer] = FULL;
}
return arr;
}
@Override
public final boolean isFull() {
return false;
}
};
public final char[][] blocks;
public final Section[] sections;
private final ReentrantLock loadLock = new ReentrantLock ();
public CharBlocks() {
blocks = new char[16][];
@ -55,7 +73,7 @@ public abstract class CharBlocks implements IBlocks {
public boolean trim(boolean aggressive) {
boolean result = true;
for (int i = 0; i < 16; i++) {
if (sections[i] == EMPTY && blocks[i] != null) {
if (!sections[i].isFull() && blocks[i] != null) {
blocks[i] = null;
} else {
result = false;
@ -67,7 +85,7 @@ public abstract class CharBlocks implements IBlocks {
@Override
public boolean trim(boolean aggressive, int layer) {
boolean result = true;
if (sections[layer] == EMPTY && blocks[layer] != null) {
if (!sections[layer].isFull() && blocks[layer] != null) {
blocks[layer] = null;
} else {
result = false;
@ -99,7 +117,7 @@ public abstract class CharBlocks implements IBlocks {
@Override
public boolean hasSection(@Range(from = 0, to = 15) int layer) {
return sections[layer] == FULL;
return sections[layer].isFull();
}
@Override
@ -149,6 +167,8 @@ public abstract class CharBlocks implements IBlocks {
public abstract char[] get(CharBlocks blocks, @Range(from = 0, to = 15) int layer);
public abstract boolean isFull();
public final char get(CharBlocks blocks, @Range(from = 0, to = 15) int layer, int index) {
return get(blocks, layer)[index];
}

View File

@ -140,7 +140,7 @@ public class ParallelQueueExtent extends PassthroughExtent implements IQueueWrap
return
// Apply a filter over a region
apply(region, searchMask
.toFilter(new CountFilter()), false) // Adapt the mask to a filter which counts
.toFilter(new CountFilter()), searchMask.replacesAir()) // Adapt the mask to a filter which counts
.getParent() // Get the counter of this mask
.getTotal(); // Get the total from the counter
}

View File

@ -200,7 +200,7 @@ public class StreamDelegate {
Object raw = is.readTagPayloadRaw(type, depth);
valueReader.apply(0, raw);
} else {
is.readTagPaylodLazy(type, depth + 1, this);
is.readTagPayloadLazy(type, depth + 1, this);
}
}

View File

@ -137,10 +137,8 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
}
if (!tilesTo.isEmpty()) {
for (Map.Entry<BlockVector3, CompoundTag> entry : tilesTo.entrySet()) {
CompoundTag nbt = entry.getValue();
BlockVector3 pos = entry.getKey();
MainUtil.setPosition(nbt, pos.getX() + bx, pos.getY(), pos.getZ() + bz);
addTileCreate(nbt);
addTileCreate(MainUtil.setPosition(entry.getValue(), pos.getX() + bx, pos.getY(), pos.getZ() + bz));
}
}
Set<UUID> entRemoves = set.getEntityRemoves();
@ -176,11 +174,12 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
int zz = z + bz;
for (int x = 0; x < 16; x++, index++) {
int xx = bx + x;
int combinedFrom = blocksGet[index];
if (combinedFrom == 0) {
combinedFrom = BlockID.AIR;
int from = blocksGet[index];
if (from == 0) {
from = BlockID.AIR;
}
int combinedTo = blocksSet[index];
final int combinedFrom = from;
final int combinedTo = blocksSet[index];
if (combinedTo != 0) {
add(xx, yy, zz, combinedFrom, combinedTo);
}
@ -249,14 +248,12 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
public void add(EntityCreate change) {
CompoundTag tag = change.state.getNbtData();
MainUtil.setEntityInfo(tag, change.getEntity());
addEntityCreate(tag);
addEntityCreate(MainUtil.setEntityInfo(tag, change.getEntity()));
}
public void add(EntityRemove change) {
CompoundTag tag = change.state.getNbtData();
MainUtil.setEntityInfo(tag, change.getEntity());
addEntityRemove(tag);
addEntityRemove(MainUtil.setEntityInfo(tag, change.getEntity()));
}
@Override
@ -299,14 +296,12 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
if (from.hasNbtData()) {
CompoundTag nbt = from.getNbtData();
assert nbt != null;
MainUtil.setPosition(nbt, x, y, z);
addTileRemove(nbt);
addTileRemove(MainUtil.setPosition(nbt, x, y, z));
}
if (to.hasNbtData()) {
CompoundTag nbt = to.getNbtData();
assert nbt != null;
MainUtil.setPosition(nbt, x, y, z);
addTileCreate(nbt);
addTileCreate(MainUtil.setPosition(nbt, x, y, z));
}
int combinedFrom = from.getOrdinal();
int combinedTo = to.getOrdinal();
@ -322,8 +317,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
if (to.hasNbtData()) {
CompoundTag nbt = to.getNbtData();
assert nbt != null;
MainUtil.setPosition(nbt, x, y, z);
addTileCreate(nbt);
addTileCreate(MainUtil.setPosition(nbt, x, y, z));
}
int combinedTo = to.getInternalId();
add(x, y, z, combinedFrom, combinedTo);
@ -357,7 +351,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
wrappedTask.run();
return Futures.immediateCancelledFuture();
} else {
return Fawe.get().getQueueHandler().async(wrappedTask);
return Fawe.get().getQueueHandler().submit(wrappedTask);
}
}
}

View File

@ -152,10 +152,8 @@ public class CPUOptimizedClipboard extends LinearClipboard {
@Override
public Collection<CompoundTag> getTileEntities() {
convertTilesToIndex();
for (Map.Entry<Integer, CompoundTag> entry : nbtMapIndex.entrySet()) {
int index = entry.getKey();
CompoundTag tag = entry.getValue();
Map<String, Tag> values = tag.getValue();
nbtMapIndex.replaceAll((index, tag) -> {
Map<String, Tag> values = new HashMap<>(tag.getValue());
if (!values.containsKey("x")) {
int y = index / getArea();
index -= y * getArea();
@ -164,23 +162,26 @@ public class CPUOptimizedClipboard extends LinearClipboard {
values.put("x", new IntTag(x));
values.put("y", new IntTag(y));
values.put("z", new IntTag(z));
return new CompoundTag(values);
} else {
return tag;
}
}
});
return nbtMapIndex.values();
}
@Override
public boolean setTile(int x, int y, int z, CompoundTag tag) {
nbtMapLoc.put(new IntTriple(x, y, z), tag);
nbtMapLoc.put(new IntTriple(x, y, z), new CompoundTag(tag.getValue()));
return true;
}
public boolean setTile(int index, CompoundTag tag) {
nbtMapIndex.put(index, tag);
Map<String, Tag> values = tag.getValue();
final Map<String, Tag> values = new HashMap<>(tag.getValue());
values.remove("x");
values.remove("y");
values.remove("z");
nbtMapIndex.put(index, new CompoundTag(values));
return true;
}

View File

@ -24,6 +24,7 @@ import com.sk89q.worldedit.world.block.BlockTypes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.File;
@ -44,7 +45,6 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
/**
* A clipboard with disk backed storage. (lower memory + loads on crash)
@ -390,11 +390,11 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable
@Override
public boolean setTile(int x, int y, int z, CompoundTag tag) {
nbtMap.put(new IntTriple(x, y, z), tag);
Map<String, Tag> values = tag.getValue();
final Map<String, Tag> values = new HashMap<>(tag.getValue());
values.put("x", new IntTag(x));
values.put("y", new IntTag(y));
values.put("z", new IntTag(z));
nbtMap.put(new IntTriple(x, y, z), new CompoundTag(values));
return true;
}

View File

@ -21,10 +21,6 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.UUID;
/**
* Best used when clipboard selections are small, or using legacy formats
* (Small being < Integer.MAX_VALUE/BLOCK_SIZE_BYTES blocks)
*/
public abstract class LinearClipboard extends SimpleClipboard {
protected final HashSet<ClipboardEntity> entities = new HashSet<>();

View File

@ -257,11 +257,11 @@ public class MemoryOptimizedClipboard extends LinearClipboard {
@Override
public boolean setTile(int x, int y, int z, CompoundTag tag) {
nbtMap.put(new IntTriple(x, y, z), tag);
Map<String, Tag> values = tag.getValue();
final Map<String, Tag> values = new HashMap<>(tag.getValue());
values.put("x", new IntTag(x));
values.put("y", new IntTag(y));
values.put("z", new IntTag(z));
nbtMap.put(new IntTriple(x, y, z), new CompoundTag(values));
return true;
}

View File

@ -14,7 +14,7 @@ public abstract class SimpleClipboard implements Clipboard {
SimpleClipboard(BlockVector3 dimensions) {
this.size = dimensions;
long longVolume = (long) getWidth() * (long) getHeight() * (long) getLength();
if (longVolume >= Integer.MAX_VALUE >> 2) {
if (longVolume >= Integer.MAX_VALUE) {
throw new IllegalArgumentException("Dimensions are too large for this clipboard format.");
}
this.area = getWidth() * getLength();

View File

@ -16,4 +16,9 @@ public class AirMask extends BlockMask {
return new AirMask(getExtent());
}
@Override
public boolean replacesAir() {
return true;
}
}

View File

@ -37,4 +37,9 @@ public class IdDataMask extends AbstractExtentMask implements ResettableMask {
return new IdDataMask(getExtent());
}
@Override
public boolean replacesAir() {
return true;
}
}

View File

@ -38,4 +38,9 @@ public class IdMask extends AbstractExtentMask implements ResettableMask {
return new IdMask(getExtent());
}
@Override
public boolean replacesAir() {
return true;
}
}

View File

@ -1,298 +0,0 @@
package com.boydti.fawe.util;
import com.boydti.fawe.Fawe;
import com.google.common.base.Charsets;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.sk89q.worldedit.util.paste.Paster;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
/**
* Single class paster for the Incendo paste service
*
* @author Sauilitired
*/
@SuppressWarnings({"unused", "WeakerAccess"})
public final class IncendoPaster implements Paster {
/**
* Upload service URL
*/
public static final String UPLOAD_PATH = "https://athion.net/ISPaster/paste/upload";
/**
* Valid paste applications
*/
public static final Collection<String>
VALID_APPLICATIONS = Arrays
.asList("plotsquared", "fastasyncworldedit", "incendopermissions", "kvantum");
private final Collection<PasteFile> files = new ArrayList<>();
private final String pasteApplication;
/**
* Construct a new paster
*
* @param pasteApplication The application that is sending the paste
*/
public IncendoPaster(final String pasteApplication) {
if (pasteApplication == null || pasteApplication.isEmpty()) {
throw new IllegalArgumentException("paste application cannot be null, nor empty");
}
if (!VALID_APPLICATIONS.contains(pasteApplication.toLowerCase(Locale.ROOT))) {
throw new IllegalArgumentException(
String.format("Unknown application name: %s", pasteApplication));
}
this.pasteApplication = pasteApplication;
}
@Override
public Callable<URL> paste(String content) {
return new PasteTask(content);
}
private final class PasteTask implements Callable<URL> {
private PasteTask(String content) {}
@Override
public URL call() throws Exception {
return new URL(debugPaste());
}
}
/**
* Get an immutable collection containing all the files that have been added to this paster
*
* @return Unmodifiable collection
*/
public final Collection<PasteFile> getFiles() {
return Collections.unmodifiableCollection(this.files);
}
/**
* Add a file to the paster
*
* @param file File to paste
*/
public void addFile(final PasteFile file) {
if (file == null) {
throw new IllegalArgumentException("File cannot be null");
}
// Check to see that no duplicate files are submitted
for (final PasteFile pasteFile : this.files) {
if (pasteFile.fileName.equalsIgnoreCase(file.getFileName())) {
throw new IllegalArgumentException(String.format("Found duplicate file with name %s",
file.getFileName()));
}
}
this.files.add(file);
}
/**
* Create a JSON string from the submitted information
*
* @return compiled JSON string
*/
private String toJsonString() {
final StringBuilder builder = new StringBuilder("{\n");
builder.append("\"paste_application\": \"").append(this.pasteApplication).append("\",\n\"files\": \"");
Iterator<PasteFile> fileIterator = this.files.iterator();
while (fileIterator.hasNext()) {
final PasteFile file = fileIterator.next();
builder.append(file.getFileName());
if (fileIterator.hasNext()) {
builder.append(",");
}
}
builder.append("\",\n");
fileIterator = this.files.iterator();
while (fileIterator.hasNext()) {
final PasteFile file = fileIterator.next();
builder.append("\"file-").append(file.getFileName()).append("\": \"")
.append(file.getContent().replaceAll("\"", "\\\\\"")).append("\"");
if (fileIterator.hasNext()) {
builder.append(",\n");
}
}
builder.append("\n}");
return builder.toString();
}
/**
* Upload the paste and return the status message
*
* @return Status message
* @throws Throwable any and all exceptions
*/
public final String upload() throws Throwable {
final URL url = new URL(UPLOAD_PATH);
final URLConnection connection = url.openConnection();
final HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
final byte[] content = toJsonString().getBytes(Charsets.UTF_8);
httpURLConnection.setFixedLengthStreamingMode(content.length);
httpURLConnection.setRequestProperty("Content-Type", "application/json");
httpURLConnection.setRequestProperty("Accept", "*/*");
httpURLConnection.connect();
try (final OutputStream stream = httpURLConnection.getOutputStream()) {
stream.write(content);
}
if (!httpURLConnection.getResponseMessage().contains("OK")) {
throw new IllegalStateException(String.format("Server returned status: %d %s",
httpURLConnection.getResponseCode(), httpURLConnection.getResponseMessage()));
}
final StringBuilder input = new StringBuilder();
try (final BufferedReader inputStream = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()))) {
String line;
while ((line = inputStream.readLine()) != null) {
input.append(line).append("\n");
}
}
return input.toString();
}
/**
* Simple class that represents a paste file
*/
public static class PasteFile {
private final String fileName;
private final String content;
/**
* Construct a new paste file
*
* @param fileName File name, cannot be empty, nor null
* @param content File content, cannot be empty, nor null
*/
public PasteFile(final String fileName, final String content) {
if (fileName == null || fileName.isEmpty()) {
throw new IllegalArgumentException("file name cannot be null, nor empty");
}
if (content == null || content.isEmpty()) {
throw new IllegalArgumentException("content cannot be null, nor empty");
}
this.fileName = fileName;
this.content = content;
}
/**
* Get the file name
*
* @return File name
*/
public String getFileName() {
return this.fileName;
}
/**
* Get the file content as a single string
*
* @return File content
*/
public String getContent() {
return this.content;
}
}
public static String debugPaste() throws IOException {
final IncendoPaster incendoPaster = new IncendoPaster("fastasyncworldedit");
StringBuilder b = new StringBuilder();
b.append(
"# Welcome to this paste\n# It is meant to provide us at IntellectualSites with better information about your "
+ "problem\n");
b.append("\n# Server Information\n");
b.append(Fawe.imp().getDebugInfo());
b.append("\n# YAY! Now, let's see what we can find in your JVM\n");
Runtime runtime = Runtime.getRuntime();
RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
b.append("Uptime: ").append(TimeUnit.MINUTES.convert(rb.getUptime(), TimeUnit.MILLISECONDS))
.append(" minutes").append('\n');
b.append("JVM Flags: ").append(rb.getInputArguments()).append('\n');
b.append("Free Memory: ").append(runtime.freeMemory() / 1024 / 1024).append(" MB").append('\n');
b.append("Max Memory: ").append(runtime.maxMemory() / 1024 / 1024).append(" MB").append('\n');
b.append("Total Memory: ").append(runtime.totalMemory() / 1024 / 1024).append(" MB").append('\n');
b.append("Available Processors: ").append(runtime.availableProcessors()).append('\n');
b.append("Java Name: ").append(rb.getVmName()).append('\n');
b.append("Java Version: '").append(System.getProperty("java.version")).append("'\n");
b.append("Java Vendor: '").append(System.getProperty("java.vendor")).append("'\n");
b.append("Operating System: '").append(System.getProperty("os.name")).append("'\n");
b.append("OS Version: ").append(System.getProperty("os.version")).append('\n');
b.append("OS Arch: ").append(System.getProperty("os.arch")).append('\n');
b.append("# Okay :D Great. You are now ready to create your bug report!");
b.append("\n# You can do so at https://github.com/IntellectualSites/FastAsyncWorldEdit/issues");
b.append("\n# or via our Discord at https://discord.gg/KxkjDVg");
incendoPaster.addFile(new IncendoPaster.PasteFile("information", b.toString()));
try {
final File logFile = new File(Fawe.imp().getDirectory(), "../../logs/latest.log");
final String file;
if (Files.size(logFile.toPath()) > 14_000_000) {
file = "too big :(";
} else {
file = readFile(logFile);
}
incendoPaster.addFile(new IncendoPaster.PasteFile("latest.log", file));
} catch (IOException ignored) {
}
incendoPaster.addFile(new PasteFile("config.yml", readFile(new File(Fawe.imp().getDirectory(), "config.yml"))));
incendoPaster.addFile(new PasteFile("config-legacy.yml", readFile(new File(Fawe.imp().getDirectory(), "config-legacy.yml"))));
final String rawResponse;
try {
rawResponse = incendoPaster.upload();
} catch (Throwable throwable) {
throw new IOException(String.format("Failed to upload files: %s", throwable.getMessage()), throwable);
}
final JsonObject jsonObject = new JsonParser().parse(rawResponse).getAsJsonObject();
if (jsonObject.has("created")) {
final String pasteId = jsonObject.get("paste_id").getAsString();
return String.format("https://athion.net/ISPaster/paste/view/%s", pasteId);
} else {
throw new IOException(String.format("Failed to upload files: %s",
jsonObject.get("response").getAsString()));
}
}
private static String readFile(final File file) throws IOException {
final StringBuilder content = new StringBuilder();
final List<String> lines = new ArrayList<>();
try (final BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
}
for (int i = Math.max(0, lines.size() - 1000); i < lines.size(); i++) {
content.append(lines.get(i)).append("\n");
}
return content.toString();
}
}

View File

@ -34,6 +34,9 @@ import net.jpountz.lz4.LZ4InputStream;
import net.jpountz.lz4.LZ4Utils;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.imageio.ImageIO;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
@ -66,6 +69,7 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@ -83,8 +87,6 @@ import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.annotation.Nullable;
import javax.imageio.ImageIO;
import static java.lang.System.arraycopy;
import static org.slf4j.LoggerFactory.getLogger;
@ -448,24 +450,44 @@ public class MainUtil {
}
}
public static void setPosition(CompoundTag tag, int x, int y, int z) {
Map<String, Tag> value = tag.getValue();
/**
* Create a copy of the tag and modify the (x, y, z) coordinates
*
* @param tag Tag to copy
* @param x New X coordinate
* @param y New Y coordinate
* @param z New Z coordinate
* @return New tag
*/
public static @NotNull CompoundTag setPosition(@Nonnull CompoundTag tag, int x, int y, int z) {
Map<String, Tag> value = new HashMap<>(tag.getValue());
value.put("x", new IntTag(x));
value.put("y", new IntTag(y));
value.put("z", new IntTag(z));
return new CompoundTag(value);
}
public static void setEntityInfo(CompoundTag tag, Entity entity) {
Map<String, Tag> map = tag.getValue();
/**
* Create a copy of the tag and modify the entity inf
*
* @param tag Tag to copy
* @param entity Entity
* @return New tag
*/
public static @NotNull CompoundTag setEntityInfo(@NotNull CompoundTag tag, @NotNull Entity entity) {
Map<String, Tag> map = new HashMap<>(tag.getValue());
map.put("Id", new StringTag(entity.getState().getType().getId()));
ListTag pos = (ListTag) map.get("Pos");
if (pos != null) {
Location loc = entity.getLocation();
List<Tag> posList = ReflectionUtils.getList(pos.getValue());
// Create a copy, because the list is immutable...
List<Tag> posList = new ArrayList<>(pos.getValue());
posList.set(0, new DoubleTag(loc.getX()));
posList.set(1, new DoubleTag(loc.getY()));
posList.set(2, new DoubleTag(loc.getZ()));
map.put("Pos", new ListTag(pos.getType(), posList));
}
return new CompoundTag(map);
}
public static String getText(String url) throws IOException {

View File

@ -1,5 +1,6 @@
package com.boydti.fawe.util;
import com.plotsquared.core.util.PseudoRandom;
import com.sk89q.worldedit.world.block.BlockType;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
@ -34,6 +35,8 @@ public class RandomTextureUtil extends CachedTextureUtil {
if (i < 0) {
int i1 = -i;
return -ThreadLocalRandom.current().nextInt(i1);
} else if( i == 0) {
return 0;
} else {
return ThreadLocalRandom.current().nextInt(i);
}

View File

@ -67,22 +67,6 @@ public class ReflectionUtils {
blankField(enumClass, "enumConstants"); // IBM JDK
}
public static <T> List<T> getList(List<T> list) {
try {
Class<? extends List<T>> clazz = (Class<? extends List<T>>) Class
.forName("java.util.Collections$UnmodifiableList");
if (!clazz.isInstance(list)) {
return list;
}
Field m = clazz.getDeclaredField("list");
m.setAccessible(true);
return (List<T>) m.get(list);
} catch (Throwable e) {
e.printStackTrace();
return list;
}
}
public static Object getHandle(Object wrapper) {
final Method getHandle = makeMethod(wrapper.getClass(), "getHandle");
return callMethod(getHandle, wrapper);

View File

@ -629,7 +629,6 @@ public class TextureUtil implements TextureHolder {
mods.add(modId);
}
}
continue;
}
String modelsDir = "assets/%1$s/models/block/%2$s.json";
String texturesDir = "assets/%1$s/textures/%2$s.png";
@ -638,14 +637,14 @@ public class TextureUtil implements TextureHolder {
}.getType();
for (BlockType blockType : BlockTypesCache.values) {
if (!blockType.getMaterial().isFullCube()) {
if (!blockType.getMaterial().isFullCube() || blockType.getId().toLowerCase().contains("shulker")) {
continue;
}
int combined = blockType.getInternalId();
String id = blockType.getId();
String[] split = id.split(":", 2);
String name = split.length == 1 ? id : split[1];
String nameSpace = split.length == 1 ? "minecraft" : split[0];
String nameSpace = split.length == 1 ? "" : split[0];
Map<String, String> texturesMap = new ConcurrentHashMap<>();
// Read models
@ -684,8 +683,11 @@ public class TextureUtil implements TextureHolder {
continue;
}
String[] texSplit = models.iterator().next().split(":");
String texture = texSplit[texSplit.length - 1];
textureFileName =
String.format(texturesDir, nameSpace, models.iterator().next());
String.format(texturesDir, nameSpace, texture);
}
BufferedImage image = readImage(zipFile, textureFileName);

View File

@ -26,11 +26,6 @@ import java.util.Locale;
*/
public final class ByteArrayTag extends Tag {
@Override
public int getTypeCode() {
return NBTConstants.TYPE_BYTE_ARRAY;
}
private final byte[] value;
/**
@ -61,4 +56,11 @@ public final class ByteArrayTag extends Tag {
return "TAG_Byte_Array(" + hex + ")";
}
// FAWE Start
@Override
public int getTypeCode() {
return NBTConstants.TYPE_BYTE_ARRAY;
}
// FAWE End
}

View File

@ -19,14 +19,12 @@
package com.sk89q.jnbt;
import com.sk89q.jnbt.fawe.NumberTag;
/**
* The {@code TAG_Byte} tag.
*/
public final class ByteTag extends NumberTag {
@Override
public int getTypeCode() {
return NBTConstants.TYPE_BYTE;
}
private final byte value;
@ -50,4 +48,11 @@ public final class ByteTag extends NumberTag {
return "TAG_Byte(" + value + ")";
}
// FAWE Start
@Override
public int getTypeCode() {
return NBTConstants.TYPE_BYTE;
}
// FAWE End
}

View File

@ -19,6 +19,7 @@
package com.sk89q.jnbt;
import com.sk89q.jnbt.fawe.NumberTag;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.util.Location;
@ -34,12 +35,7 @@ import java.util.UUID;
*/
public class CompoundTag extends Tag {
@Override
public int getTypeCode() {
return NBTConstants.TYPE_COMPOUND;
}
private Map<String, Tag> value;
private final Map<String, Tag> value;
/**
* Creates the tag with an empty name.
@ -48,7 +44,7 @@ public class CompoundTag extends Tag {
*/
public CompoundTag(Map<String, Tag> value) {
super();
this.value = value;
this.value = Collections.unmodifiableMap(value);
}
/**
@ -58,7 +54,7 @@ public class CompoundTag extends Tag {
* @return true if the tag contains the given key
*/
public boolean containsKey(String key) {
return getValue().containsKey(key);
return value.containsKey(key);
}
@Override
@ -66,17 +62,6 @@ public class CompoundTag extends Tag {
return value;
}
/**
* Return a new compound tag with the given values.
*
* @param value the value
* @return the new compound tag
*/
public CompoundTag setValue(Map<String, Tag> value) {
this.value = value;
return this;
}
/**
* Create a compound tag builder.
*
@ -96,7 +81,7 @@ public class CompoundTag extends Tag {
* @return a byte array
*/
public byte[] getByteArray(String key) {
Tag tag = getValue().get(key);
Tag tag = value.get(key);
if (tag instanceof ByteArrayTag) {
return ((ByteArrayTag) tag).getValue();
} else {
@ -114,7 +99,7 @@ public class CompoundTag extends Tag {
* @return a byte
*/
public byte getByte(String key) {
Tag tag = getValue().get(key);
Tag tag = value.get(key);
if (tag instanceof ByteTag) {
return ((ByteTag) tag).getValue();
} else {
@ -132,7 +117,7 @@ public class CompoundTag extends Tag {
* @return a double
*/
public double getDouble(String key) {
Tag tag = getValue().get(key);
Tag tag = value.get(key);
if (tag instanceof DoubleTag) {
return ((DoubleTag) tag).getValue();
} else {
@ -151,9 +136,25 @@ public class CompoundTag extends Tag {
* @return a double
*/
public double asDouble(String key) {
Tag tag = getValue().get(key);
if (tag instanceof NumberTag) {
return ((NumberTag) tag).getValue().doubleValue();
Tag tag = value.get(key);
if (tag instanceof ByteTag) {
return ((ByteTag) tag).getValue();
} else if (tag instanceof ShortTag) {
return ((ShortTag) tag).getValue();
} else if (tag instanceof IntTag) {
return ((IntTag) tag).getValue();
} else if (tag instanceof LongTag) {
return ((LongTag) tag).getValue();
} else if (tag instanceof FloatTag) {
return ((FloatTag) tag).getValue();
} else if (tag instanceof DoubleTag) {
return ((DoubleTag) tag).getValue();
} else {
return 0;
}
@ -169,7 +170,7 @@ public class CompoundTag extends Tag {
* @return a float
*/
public float getFloat(String key) {
Tag tag = getValue().get(key);
Tag tag = value.get(key);
if (tag instanceof FloatTag) {
return ((FloatTag) tag).getValue();
} else {
@ -187,7 +188,7 @@ public class CompoundTag extends Tag {
* @return an int array
*/
public int[] getIntArray(String key) {
Tag tag = getValue().get(key);
Tag tag = value.get(key);
if (tag instanceof IntArrayTag) {
return ((IntArrayTag) tag).getValue();
} else {
@ -205,7 +206,7 @@ public class CompoundTag extends Tag {
* @return an int
*/
public int getInt(String key) {
Tag tag = getValue().get(key);
Tag tag = value.get(key);
if (tag instanceof IntTag) {
return ((IntTag) tag).getValue();
} else {
@ -224,9 +225,25 @@ public class CompoundTag extends Tag {
* @return an int
*/
public int asInt(String key) {
Tag tag = getValue().get(key);
if (tag instanceof NumberTag) {
return ((NumberTag) tag).getValue().intValue();
Tag tag = value.get(key);
if (tag instanceof ByteTag) {
return ((ByteTag) tag).getValue();
} else if (tag instanceof ShortTag) {
return ((ShortTag) tag).getValue();
} else if (tag instanceof IntTag) {
return ((IntTag) tag).getValue();
} else if (tag instanceof LongTag) {
return ((LongTag) tag).getValue().intValue();
} else if (tag instanceof FloatTag) {
return ((FloatTag) tag).getValue().intValue();
} else if (tag instanceof DoubleTag) {
return ((DoubleTag) tag).getValue().intValue();
} else {
return 0;
}
@ -242,7 +259,7 @@ public class CompoundTag extends Tag {
* @return a list of tags
*/
public List<Tag> getList(String key) {
Tag tag = getValue().get(key);
Tag tag = value.get(key);
if (tag instanceof ListTag) {
return ((ListTag) tag).getValue();
} else {
@ -260,7 +277,7 @@ public class CompoundTag extends Tag {
* @return a tag list instance
*/
public ListTag getListTag(String key) {
Tag tag = getValue().get(key);
Tag tag = value.get(key);
if (tag instanceof ListTag) {
return (ListTag) tag;
} else {
@ -273,7 +290,7 @@ public class CompoundTag extends Tag {
*
* <p>If the key does not exist or its value is not a list tag,
* then an empty list will be returned. If the given key references
* a list but the list of a different type, then an empty
* a list but the list of of a different type, then an empty
* list will also be returned.</p>
*
* @param key the key
@ -283,7 +300,7 @@ public class CompoundTag extends Tag {
*/
@SuppressWarnings("unchecked")
public <T extends Tag> List<T> getList(String key, Class<T> listType) {
Tag tag = getValue().get(key);
Tag tag = value.get(key);
if (tag instanceof ListTag) {
ListTag listTag = (ListTag) tag;
if (listTag.getType().equals(listType)) {
@ -299,14 +316,14 @@ public class CompoundTag extends Tag {
/**
* Get a {@code long[]} named with the given key.
*
* <p>If the key does not exist or its value is not a long array tag,
* <p>If the key does not exist or its value is not an long array tag,
* then an empty array will be returned.</p>
*
* @param key the key
* @return an int array
*/
public long[] getLongArray(String key) {
Tag tag = getValue().get(key);
Tag tag = value.get(key);
if (tag instanceof LongArrayTag) {
return ((LongArrayTag) tag).getValue();
} else {
@ -324,7 +341,7 @@ public class CompoundTag extends Tag {
* @return a long
*/
public long getLong(String key) {
Tag tag = getValue().get(key);
Tag tag = value.get(key);
if (tag instanceof LongTag) {
return ((LongTag) tag).getValue();
} else {
@ -343,9 +360,25 @@ public class CompoundTag extends Tag {
* @return a long
*/
public long asLong(String key) {
Tag tag = getValue().get(key);
if (tag instanceof NumberTag) {
return ((NumberTag) tag).getValue().longValue();
Tag tag = value.get(key);
if (tag instanceof ByteTag) {
return ((ByteTag) tag).getValue();
} else if (tag instanceof ShortTag) {
return ((ShortTag) tag).getValue();
} else if (tag instanceof IntTag) {
return ((IntTag) tag).getValue();
} else if (tag instanceof LongTag) {
return ((LongTag) tag).getValue();
} else if (tag instanceof FloatTag) {
return ((FloatTag) tag).getValue().longValue();
} else if (tag instanceof DoubleTag) {
return ((DoubleTag) tag).getValue().longValue();
} else {
return 0L;
}
@ -361,7 +394,7 @@ public class CompoundTag extends Tag {
* @return a short
*/
public short getShort(String key) {
Tag tag = getValue().get(key);
Tag tag = value.get(key);
if (tag instanceof ShortTag) {
return ((ShortTag) tag).getValue();
} else {
@ -379,7 +412,7 @@ public class CompoundTag extends Tag {
* @return a string
*/
public String getString(String key) {
Tag tag = getValue().get(key);
Tag tag = value.get(key);
if (tag instanceof StringTag) {
return ((StringTag) tag).getValue();
} else {
@ -388,17 +421,17 @@ public class CompoundTag extends Tag {
}
@Override
public Map<String, Object> toRaw() {
HashMap<String, Object> raw = new HashMap<>();
if (this.getValue().isEmpty()) {
return raw;
public String toString() {
StringBuilder bldr = new StringBuilder();
bldr.append("TAG_Compound").append(": ").append(value.size()).append(" entries\r\n{\r\n");
for (Map.Entry<String, Tag> entry : value.entrySet()) {
bldr.append(" ").append(entry.getValue().toString().replaceAll("\r\n", "\r\n ")).append("\r\n");
}
for (Map.Entry<String, Tag> entry : getValue().entrySet()) {
raw.put(entry.getKey(), entry.getValue().toRaw());
}
return raw;
bldr.append("}");
return bldr.toString();
}
// FAWE Start
public UUID getUUID() {
long most = getLong("UUIDMost");
long least = getLong("UUIDLeast");
@ -421,15 +454,21 @@ public class CompoundTag extends Tag {
}
@Override
public String toString() {
Map<String, Tag> value = getValue();
StringBuilder bldr = new StringBuilder();
bldr.append("TAG_Compound").append(": ").append(getValue().size()).append(" entries\r\n{\r\n");
for (Map.Entry<String, Tag> entry : getValue().entrySet()) {
bldr.append(" ").append(entry.getValue().toString().replaceAll("\r\n", "\r\n ")).append("\r\n");
}
bldr.append("}");
return bldr.toString();
public int getTypeCode() {
return NBTConstants.TYPE_COMPOUND;
}
@Override
public Map<String, Object> toRaw() {
HashMap<String, Object> raw = new HashMap<>();
if (this.getValue().isEmpty()) {
return raw;
}
for (Map.Entry<String, Tag> entry : getValue().entrySet()) {
raw.put(entry.getKey(), entry.getValue().toRaw());
}
return raw;
}
// FAWE End
}

View File

@ -19,14 +19,12 @@
package com.sk89q.jnbt;
import com.sk89q.jnbt.fawe.NumberTag;
/**
* The {@code TAG_Double} tag.
*/
public final class DoubleTag extends NumberTag {
@Override
public int getTypeCode() {
return NBTConstants.TYPE_DOUBLE;
}
private final double value;
@ -50,4 +48,11 @@ public final class DoubleTag extends NumberTag {
return "TAG_Double(" + value + ")";
}
// FAWE Start
@Override
public int getTypeCode() {
return NBTConstants.TYPE_DOUBLE;
}
// FAWE End
}

View File

@ -24,11 +24,6 @@ package com.sk89q.jnbt;
*/
public final class EndTag extends Tag {
@Override
public int getTypeCode() {
return NBTConstants.TYPE_END;
}
@Override
public Object getValue() {
return null;
@ -39,4 +34,11 @@ public final class EndTag extends Tag {
return "TAG_End";
}
// FAWE Start
@Override
public int getTypeCode() {
return NBTConstants.TYPE_END;
}
// FAWE End
}

View File

@ -19,14 +19,12 @@
package com.sk89q.jnbt;
import com.sk89q.jnbt.fawe.NumberTag;
/**
* The {@code TAG_Float} tag.
*/
public final class FloatTag extends NumberTag {
@Override
public int getTypeCode() {
return NBTConstants.TYPE_FLOAT;
}
private final float value;
@ -50,4 +48,11 @@ public final class FloatTag extends NumberTag {
return "TAG_Float(" + value + ")";
}
// FAWE Start
@Override
public int getTypeCode() {
return NBTConstants.TYPE_FLOAT;
}
// FAWE End
}

View File

@ -28,11 +28,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public final class IntArrayTag extends Tag {
@Override
public int getTypeCode() {
return NBTConstants.TYPE_INT_ARRAY;
}
private final int[] value;
/**
@ -64,4 +59,11 @@ public final class IntArrayTag extends Tag {
return "TAG_Int_Array(" + hex + ")";
}
// FAWE Start
@Override
public int getTypeCode() {
return NBTConstants.TYPE_INT_ARRAY;
}
// FAWE End
}

View File

@ -19,14 +19,12 @@
package com.sk89q.jnbt;
import com.sk89q.jnbt.fawe.NumberTag;
/**
* The {@code TAG_Int} tag.
*/
public final class IntTag extends NumberTag {
@Override
public int getTypeCode() {
return NBTConstants.TYPE_INT;
}
private final int value;
@ -50,4 +48,11 @@ public final class IntTag extends NumberTag {
return "TAG_Int(" + value + ")";
}
// FAWE Start
@Override
public int getTypeCode() {
return NBTConstants.TYPE_INT;
}
// FAWE End
}

View File

@ -19,10 +19,9 @@
package com.sk89q.jnbt;
import java.util.ArrayList;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
@ -31,11 +30,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public final class ListTag extends Tag {
@Override
public int getTypeCode() {
return NBTConstants.TYPE_LIST;
}
private final Class<? extends Tag> type;
private final List<Tag> value;
@ -421,18 +415,6 @@ public final class ListTag extends Tag {
}
}
@Override
public ArrayList toRaw() {
ArrayList<Object> raw = new ArrayList<>();
if (this.value.isEmpty()) {
return raw;
}
for (Tag elem : this.value) {
raw.add(elem.toRaw());
}
return raw;
}
@Override
public String toString() {
StringBuilder bldr = new StringBuilder();
@ -444,4 +426,11 @@ public final class ListTag extends Tag {
return bldr.toString();
}
// FAWE Start
@Override
public int getTypeCode() {
return NBTConstants.TYPE_LIST;
}
// FAWE End
}

View File

@ -28,11 +28,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public class LongArrayTag extends Tag {
@Override
public int getTypeCode() {
return NBTConstants.TYPE_LONG_ARRAY;
}
private final long[] value;
/**
@ -64,4 +59,11 @@ public class LongArrayTag extends Tag {
return "TAG_Long_Array(" + hex + ")";
}
// FAWE Start
@Override
public int getTypeCode() {
return NBTConstants.TYPE_LONG_ARRAY;
}
// FAWE End
}

View File

@ -19,14 +19,12 @@
package com.sk89q.jnbt;
import com.sk89q.jnbt.fawe.NumberTag;
/**
* The {@code TAG_Long} tag.
*/
public final class LongTag extends NumberTag {
@Override
public int getTypeCode() {
return NBTConstants.TYPE_LONG;
}
private final long value;
@ -50,4 +48,11 @@ public final class LongTag extends NumberTag {
return "TAG_Long(" + value + ")";
}
// FAWE Start
@Override
public int getTypeCode() {
return NBTConstants.TYPE_LONG;
}
// FAWE End
}

View File

@ -20,14 +20,13 @@
package com.sk89q.jnbt;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* A class which holds constant values.
*/
public final class NBTConstants {
public static final Charset CHARSET = StandardCharsets.UTF_8;
public static final Charset CHARSET = Charset.forName("UTF-8");
public static final int TYPE_END = 0;
public static final int TYPE_BYTE = 1;

View File

@ -32,6 +32,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
// THIS CLASS HAS BEEN HEAVILY MODIFIED BY FAWE
/**
* This class reads <strong>NBT</strong>, or <strong>Named Binary Tag</strong>
* streams, and produces an object graph of subclasses of the {@code Tag}
@ -61,6 +63,14 @@ public final class NBTInputStream implements Closeable {
this.is = dis;
}
public void mark(int mark) {
is.mark(mark);
}
public void reset() throws IOException {
is.reset();
}
/**
* Reads an NBT tag from the stream.
*
@ -99,7 +109,7 @@ public final class NBTInputStream implements Closeable {
if (child != null) {
child.acceptRoot(this, type, 0);
} else {
readTagPaylodLazy(type, 0);
readTagPayloadLazy(type, 0);
}
} catch (Throwable e) {
e.printStackTrace();
@ -119,7 +129,7 @@ public final class NBTInputStream implements Closeable {
private byte[] buf;
public void readTagPaylodLazy(int type, int depth) throws IOException {
public void readTagPayloadLazy(int type, int depth) throws IOException {
switch (type) {
case NBTConstants.TYPE_END:
return;
@ -152,7 +162,7 @@ public final class NBTInputStream implements Closeable {
int childType = is.readByte();
length = is.readInt();
for (int i = 0; i < length; ++i) {
readTagPaylodLazy(childType, depth + 1);
readTagPayloadLazy(childType, depth + 1);
}
return;
}
@ -165,7 +175,7 @@ public final class NBTInputStream implements Closeable {
return;
}
is.skipBytes(is.readShort() & 0xFFFF);
readTagPaylodLazy(childType, depth + 1);
readTagPayloadLazy(childType, depth + 1);
}
}
case NBTConstants.TYPE_INT_ARRAY: {
@ -181,7 +191,7 @@ public final class NBTInputStream implements Closeable {
}
}
public void readTagPaylodLazy(int type, int depth, StreamDelegate scope) throws IOException {
public void readTagPayloadLazy(int type, int depth, StreamDelegate scope) throws IOException {
switch (type) {
case NBTConstants.TYPE_END:
return;
@ -293,11 +303,11 @@ public final class NBTInputStream implements Closeable {
child = scope.get0();
if (child == null) {
for (int i = 0; i < length; ++i) {
readTagPaylodLazy(childType, depth + 1);
readTagPayloadLazy(childType, depth + 1);
}
} else {
for (int i = 0; i < length; ++i) {
readTagPaylodLazy(childType, depth + 1, child);
readTagPayloadLazy(childType, depth + 1, child);
}
}
return;
@ -330,9 +340,9 @@ public final class NBTInputStream implements Closeable {
}
StreamDelegate child = scope.get(is);
if (child == null) {
readTagPaylodLazy(childType, depth + 1);
readTagPayloadLazy(childType, depth + 1);
} else {
readTagPaylodLazy(childType, depth + 1, child);
readTagPayloadLazy(childType, depth + 1, child);
}
}
}
@ -461,7 +471,7 @@ public final class NBTInputStream implements Closeable {
case NBTConstants.TYPE_END:
if (depth == 0) {
throw new IOException(
"TAG_End found without a TAG_Compound/TAG_List tag preceding it.");
"TAG_End found without a TAG_Compound/TAG_List tag preceding it.");
} else {
return null;
}

View File

@ -32,6 +32,8 @@ import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
// THIS CLASS HAS BEEN HEAVILY MODIFIED BY FAWE
/**
* This class writes <strong>NBT</strong>, or <strong>Named Binary Tag</strong>
* {@code Tag} objects to an underlying {@code OutputStream}.

View File

@ -49,7 +49,7 @@ public final class NBTUtils {
return "TAG_Byte_Array";
} else if (clazz.equals(ByteTag.class)) {
return "TAG_Byte";
} else if (CompoundTag.class.isAssignableFrom(clazz)) {
} else if (clazz.equals(CompoundTag.class)) {
return "TAG_Compound";
} else if (clazz.equals(DoubleTag.class)) {
return "TAG_Double";

View File

@ -1,41 +0,0 @@
package com.sk89q.jnbt;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Some data with a name
*/
public class NamedData<T> {
private final String name;
private final T data;
/**
* Create a new named tag.
*
* @param name the name
* @param data the data
*/
public NamedData(String name, T data) {
checkNotNull(name);
this.name = name;
this.data = data;
}
/**
* Get the name of the tag.
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Get the tag.
*
* @return the tag
*/
public T getValue() {
return data;
}
}

View File

@ -19,14 +19,12 @@
package com.sk89q.jnbt;
import com.sk89q.jnbt.fawe.NumberTag;
/**
* The {@code TAG_Short} tag.
*/
public final class ShortTag extends NumberTag {
@Override
public int getTypeCode() {
return NBTConstants.TYPE_SHORT;
}
private final short value;
@ -50,4 +48,11 @@ public final class ShortTag extends NumberTag {
return "TAG_Short(" + value + ")";
}
// FAWE Start
@Override
public int getTypeCode() {
return NBTConstants.TYPE_SHORT;
}
// FAWE End
}

View File

@ -26,11 +26,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public final class StringTag extends Tag {
@Override
public int getTypeCode() {
return NBTConstants.TYPE_STRING;
}
private final String value;
/**
@ -54,4 +49,11 @@ public final class StringTag extends Tag {
return "TAG_String(" + value + ")";
}
// FAWE Start
@Override
public int getTypeCode() {
return NBTConstants.TYPE_STRING;
}
// FAWE End
}

View File

@ -31,10 +31,12 @@ public abstract class Tag {
*/
public abstract Object getValue();
// FAWE Start
public Object toRaw() {
return getValue();
}
public abstract int getTypeCode();
// FAWE End
}

View File

@ -7,6 +7,7 @@ import java.util.HashMap;
import java.util.Map;
public abstract class CompressedCompoundTag<T> extends CompoundTag {
private T in;
public CompressedCompoundTag(T in) {
@ -41,4 +42,5 @@ public abstract class CompressedCompoundTag<T> extends CompoundTag {
throw new RuntimeException(e);
}
}
}

View File

@ -1,7 +1,9 @@
package com.sk89q.jnbt;
package com.sk89q.jnbt.fawe;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.object.io.FastByteArraysInputStream;
import com.sk89q.jnbt.CompressedCompoundTag;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.FastSchematicWriter;
import net.jpountz.lz4.LZ4BlockInputStream;
@ -10,6 +12,7 @@ import net.jpountz.lz4.LZ4BlockOutputStream;
import java.io.IOException;
public class CompressedSchematicTag extends CompressedCompoundTag<Clipboard> {
public CompressedSchematicTag(Clipboard holder) {
super(holder);
}
@ -26,4 +29,5 @@ public class CompressedSchematicTag extends CompressedCompoundTag<Clipboard> {
FastByteArraysInputStream in = new FastByteArraysInputStream(blocksOut.toByteArrays());
return new LZ4BlockInputStream(in);
}
}

View File

@ -1,6 +1,13 @@
package com.sk89q.jnbt;
package com.sk89q.jnbt.fawe;
import com.sk89q.jnbt.Tag;
/**
* A numerical {@link Tag}
*/
public abstract class NumberTag extends Tag {
@Override
public abstract Number getValue();
}

View File

@ -0,0 +1,4 @@
/**
* These are classes added by FAWE. They do not exist in WorldEdit
*/
package com.sk89q.jnbt.fawe;

View File

@ -125,8 +125,6 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockCategories;
import com.sk89q.worldedit.world.block.BlockID;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
@ -148,6 +146,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@ -2046,18 +2045,18 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
int yy;
double nextXn = invRadiusX;
double nextXn = 0;
forX: for (int x = 0; x <= ceilRadiusX; ++x) {
final double xn = nextXn;
double dx = xn * xn;
nextXn = (x + 1) * invRadiusX;
double nextZn = invRadiusZ;
double nextZn = 0;
forZ: for (int z = 0; z <= ceilRadiusZ; ++z) {
final double zn = nextZn;
double dz = zn * zn;
double dxz = dx + dz;
nextZn = (z + 1) * invRadiusZ;
double nextYn = invRadiusY;
double nextYn = 0;
forY: for (int y = 0; y <= ceilRadiusY; ++y) {
final double yn = nextYn;
@ -2767,7 +2766,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
newVset = this.getHollowed(newVset);
}
}
return setBlocks(newVset, pattern);
return this.changes += setBlocks(newVset, pattern);
}
/**
@ -2840,7 +2839,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
if (!filled) {
vset = getHollowed(vset);
}
return setBlocks(vset, pattern);
return this.changes += setBlocks(vset, pattern);
}
/**
@ -2892,7 +2891,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
if (!filled) {
newVset = this.getHollowed(newVset);
}
return setBlocks(newVset, pattern);
return this.changes += setBlocks(newVset, pattern);
}
return changes;
}
@ -3008,23 +3007,21 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
}
public int makeBiomeShape(final Region region, final Vector3 zero, final Vector3 unit, final BiomeType biomeType,
final String expressionString, final boolean hollow)
throws ExpressionException, MaxChangedBlocksException {
final String expressionString, final boolean hollow) throws ExpressionException {
return makeBiomeShape(region, zero, unit, biomeType, expressionString, hollow, WorldEdit.getInstance().getConfiguration().calculationTimeout);
}
public int makeBiomeShape(final Region region, final Vector3 zero, final Vector3 unit, final BiomeType biomeType,
final String expressionString, final boolean hollow, final int timeout)
throws ExpressionException, MaxChangedBlocksException {
final String expressionString, final boolean hollow, final int timeout) throws ExpressionException {
final Expression expression = Expression.compile(expressionString, "x", "z");
final Expression expression = Expression.compile(expressionString, "x", "y", "z");
expression.optimize();
final EditSession editSession = this;
final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(editSession, unit, zero);
expression.setEnvironment(environment);
final int[] timedOut = {0};
AtomicInteger timedOut = new AtomicInteger();
final ArbitraryBiomeShape shape = new ArbitraryBiomeShape(region) {
@Override
protected BiomeType getBiome(int x, int y, int z, BiomeType defaultBiomeType) {
@ -3041,7 +3038,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
// TODO: Allow biome setting via a script variable (needs BiomeType<->int mapping)
return defaultBiomeType;
} catch (ExpressionTimeoutException e) {
timedOut[0] = timedOut[0] + 1;
timedOut.getAndIncrement();
return null;
} catch (Exception e) {
log.warn("Failed to create shape", e);
@ -3050,10 +3047,10 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
}
};
int changed = shape.generate(this, biomeType, hollow);
if (timedOut[0] > 0) {
if (timedOut.get() > 0) {
throw new ExpressionTimeoutException(
String.format("%d blocks changed. %d blocks took too long to evaluate (increase time with //timeout)",
changed, timedOut[0]));
String.format("%d biomes changed. %d biomes took too long to evaluate (increase time with //timeout)",
changed, timedOut.get()));
}
return changed;
}

View File

@ -85,7 +85,6 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.CreatureButcher;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.binding.ProvideBindings;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.function.Contextual;
@ -130,6 +129,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.nio.file.FileSystems;
import java.util.List;
@ -498,22 +498,23 @@ public class BrushCommands {
set(context, brush).setSize(radius).setFill(fill);
}
@Command(
name = "image",
@Command(name = "image",
desc = "Use a height map to paint a surface",
descFooter = "Use a height map to paint any surface.\n"
)
@CommandPermissions("worldedit.brush.stencil")
public void imageBrush(LocalSession session, InjectedValueAccess context,
@Arg(desc = "The size of the brush", def = "5")
Expression radius, ProvideBindings.ImageUri imageUri,
@Arg(def = "1", desc = "scale height")
double yscale,
@Switch(name = 'a', desc = "Use image Alpha")
boolean alpha,
@Switch(name = 'f', desc = "Blend the image with existing terrain")
boolean fadeOut) throws WorldEditException, IOException {
BufferedImage image = imageUri.load();
descFooter = "Use a height map to paint any surface.\n")
@CommandPermissions("worldedit.brush.image")
public void imageBrush(LocalSession session,
InjectedValueAccess context,
@Arg(desc = "Image URL (imgur only)") String imageURL,
@Arg(desc = "The size of the brush", def = "5") Expression radius,
@Arg(def = "1", desc = "scale height") double yscale,
@Switch(name = 'a', desc = "Use image Alpha") boolean alpha,
@Switch(name = 'f', desc = "Blend the image with existing terrain") boolean fadeOut)
throws WorldEditException, IOException {
URL url = new URL(imageURL);
if (!url.getHost().equalsIgnoreCase("i.imgur.com")) {
throw new IOException("Only i.imgur.com links are allowed!");
}
BufferedImage image = MainUtil.readImage(url);
worldEdit.checkMaxBrushRadius(radius);
if (yscale != 1) {
ImageUtil.scaleAlpha(image, yscale);

View File

@ -277,7 +277,7 @@ public class ClipboardCommands {
)
@Deprecated
@CommandPermissions({"worldedit.clipboard.download"})
public void download(final Player player, final LocalSession session, @Arg(name = "format", desc = "String", def = "schem") final String formatName) throws WorldEditException {
public void download(final Player player, final LocalSession session, @Arg(name = "format", desc = "String", def = "fast") final String formatName) throws WorldEditException {
final ClipboardFormat format = ClipboardFormats.findByAlias(formatName);
if (format == null) {
player.print(Caption.of("fawe.worldedit.clipboard.clipboard.invalid.format", formatName));

View File

@ -58,7 +58,7 @@ import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch;
import org.jetbrains.annotations.Range;
import java.awt.RenderingHints;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
@ -131,20 +131,26 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.image")
@Logging(PLACEMENT)
public void image(Actor actor, LocalSession session, EditSession editSession, String argStr, @Arg(desc = "boolean", def = "true") boolean randomize,
@Arg(desc = "TODO", def = "100") int threshold, @Arg(desc = "BlockVector2", def = "") BlockVector2 dimensions) throws WorldEditException, IOException {
public void image(Actor actor,
LocalSession session,
EditSession editSession,
@Arg(desc = "Image URL (imgur only)") String imageURL,
@Arg(desc = "boolean", def = "true") boolean randomize,
@Arg(desc = "TODO", def = "100") int threshold,
@Arg(desc = "BlockVector2", def = "") BlockVector2 dimensions) throws WorldEditException, IOException {
TextureUtil tu = Fawe.get().getCachedTextureUtil(randomize, 0, threshold);
URL url = new URL(argStr);
URL url = new URL(imageURL);
if (!url.getHost().equalsIgnoreCase("i.imgur.com")) {
throw new IOException("Only i.imgur.com links are allowed!");
}
BufferedImage image = MainUtil.readImage(url);
if (dimensions != null) {
image = ImageUtil.getScaledInstance(image, dimensions.getBlockX(), dimensions.getBlockZ(), RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
image = ImageUtil.getScaledInstance(image, dimensions.getBlockX(), dimensions.getBlockZ(),
RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
}
BlockVector3 pos1 = session.getPlacementPosition(actor);
BlockVector3 pos2 = pos1.add(image.getWidth() - 1, 0, image.getHeight() - 1);
BlockVector3 pos1 = session.getPlacementPosition(actor);
BlockVector3 pos2 = pos1.add(image.getWidth() - 1, 0, image.getHeight() - 1);
CuboidRegion region = new CuboidRegion(pos1, pos2);
int[] count = new int[1];
final BufferedImage finalImage = image;

View File

@ -147,7 +147,7 @@ public class SchematicCommands {
@Deprecated
@CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.load.web", "worldedit.schematic.load.asset"})
public void loadall(Player player, LocalSession session,
@Arg(desc = "Format name.", def = "schematic")
@Arg(desc = "Format name.", def = "fast")
String formatName,
@Arg(desc = "File name.")
String filename,
@ -223,7 +223,7 @@ public class SchematicCommands {
public void load(Actor actor, LocalSession session,
@Arg(desc = "File name.")
String filename,
@Arg(desc = "Format name.", def = "sponge")
@Arg(desc = "Format name.", def = "fast")
String formatName) throws FilenameException {
LocalConfiguration config = worldEdit.getConfiguration();
@ -323,7 +323,7 @@ public class SchematicCommands {
public void save(Actor actor, LocalSession session,
@Arg(desc = "File name.")
String filename,
@Arg(desc = "Format name.", def = "sponge")
@Arg(desc = "Format name.", def = "fast")
String formatName,
@Switch(name = 'f', desc = "Overwrite an existing file.")
boolean allowOverwrite,

View File

@ -22,7 +22,7 @@ package com.sk89q.worldedit.command;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweVersion;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.util.IncendoPaster;
import com.intellectualsites.paster.IncendoPaster;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
@ -47,6 +47,7 @@ import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch;
import java.io.File;
import java.io.IOException;
import java.time.ZoneId;
import java.time.ZonedDateTime;
@ -139,7 +140,10 @@ public class WorldEditCommands {
public void report(Actor actor) throws WorldEditException {
String dest;
try {
dest = IncendoPaster.debugPaste();
final File logFile = new File(Fawe.imp().getDirectory(), "../../logs/latest.log");
final File config = new File(Fawe.imp().getDirectory(), "config.yml");
final File legacyConfig = new File(Fawe.imp().getDirectory(), "config-legacy.yml");
dest = IncendoPaster.debugPaste(logFile, Fawe.imp().getDebugInfo(), config, legacyConfig);
} catch (IOException e) {
actor.printInfo(TextComponent.of(e.getMessage()));
return;

View File

@ -24,8 +24,11 @@ import com.boydti.fawe.object.io.ResettableFileInputStream;
import com.boydti.fawe.object.schematic.MinecraftStructure;
import com.boydti.fawe.object.schematic.PNGWriter;
import com.google.common.collect.ImmutableSet;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.Tag;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@ -35,6 +38,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@ -44,40 +48,7 @@ import java.util.zip.GZIPOutputStream;
*/
public enum BuiltInClipboardFormat implements ClipboardFormat {
/**
* The Schematic format used by MCEdit.
*/
MCEDIT_SCHEMATIC("mcedit", "mce", "schematic") {
@Override
public String getPrimaryFileExtension() {
return "schematic";
}
@Override
public ClipboardReader getReader(InputStream inputStream) throws IOException {
if (inputStream instanceof FileInputStream) {
inputStream = new ResettableFileInputStream((FileInputStream) inputStream);
}
BufferedInputStream buffered = new BufferedInputStream(inputStream);
NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered)));
SchematicReader input = new SchematicReader(nbtStream);
input.setUnderlyingStream(inputStream);
return input;
}
@Override
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
throw new IOException("This format does not support saving, use `schem` or `sponge` as format"); // Is more helpful
}
@Override
public boolean isFormat(File file) {
String name = file.getName().toLowerCase(Locale.ROOT);
return name.endsWith(".schematic") || name.endsWith(".mcedit") || name.endsWith(".mce");
}
},
SPONGE_SCHEMATIC("sponge", "schem") {
FAST("fast", "fawe") {
@Override
public String getPrimaryFileExtension() {
@ -115,6 +86,129 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
},
SPONGE_SCHEMATIC("sponge", "schem") {
@Override
public String getPrimaryFileExtension() {
return "schem";
}
@Override
public ClipboardReader getReader(InputStream inputStream) throws IOException {
NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(inputStream));
return new SpongeSchematicReader(nbtStream);
}
@Override
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
NBTOutputStream nbtStream = new NBTOutputStream(new GZIPOutputStream(outputStream));
return new SpongeSchematicWriter(nbtStream);
}
@Override
public boolean isFormat(File file) {
try (NBTInputStream str = new NBTInputStream(new GZIPInputStream(new FileInputStream(file)))) {
NamedTag rootTag = str.readNamedTag();
if (!rootTag.getName().equals("Schematic")) {
return false;
}
CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
// Check
Map<String, Tag> schematic = schematicTag.getValue();
if (!schematic.containsKey("Version")) {
return false;
}
} catch (Exception e) {
return false;
}
return true;
}
},
/**
* The Schematic format used by MCEdit.
*/
MCEDIT_SCHEMATIC("mcedit", "mce", "schematic") {
@Override
public String getPrimaryFileExtension() {
return "schematic";
}
@Override
public ClipboardReader getReader(InputStream inputStream) throws IOException {
NBTInputStream nbtStream = new NBTInputStream(new GZIPInputStream(inputStream));
return new MCEditSchematicReader(nbtStream);
}
@Override
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
throw new IOException("This format does not support saving");
}
@Override
public boolean isFormat(File file) {
try (NBTInputStream str = new NBTInputStream(new GZIPInputStream(new FileInputStream(file)))) {
NamedTag rootTag = str.readNamedTag();
if (!rootTag.getName().equals("Schematic")) {
return false;
}
CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
// Check
Map<String, Tag> schematic = schematicTag.getValue();
if (!schematic.containsKey("Materials")) {
return false;
}
} catch (Exception e) {
return false;
}
return true;
}
},
BROKENENTITY("brokenentity", "legacyentity", "le", "be", "brokenentities", "legacyentities") {
@Override
public String getPrimaryFileExtension() {
return "schem";
}
@Override
public ClipboardReader getReader(InputStream inputStream) throws IOException {
if (inputStream instanceof FileInputStream) {
inputStream = new ResettableFileInputStream((FileInputStream) inputStream);
}
BufferedInputStream buffered = new BufferedInputStream(inputStream);
NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered)));
FastSchematicReader reader = new FastSchematicReader(nbtStream);
reader.setBrokenEntities(true);
return reader;
}
@Override
public ClipboardWriter getWriter(OutputStream outputStream) throws IOException {
OutputStream gzip;
if (outputStream instanceof PGZIPOutputStream || outputStream instanceof GZIPOutputStream) {
gzip = outputStream;
} else {
outputStream = new BufferedOutputStream(outputStream);
gzip = new PGZIPOutputStream(outputStream);
}
NBTOutputStream nbtStream = new NBTOutputStream(new BufferedOutputStream(gzip));
FastSchematicWriter writer = new FastSchematicWriter(nbtStream);
writer.setBrokenEntities(true);
return writer;
}
@Override
public boolean isFormat(File file) {
return false;
}
},
/**
* The structure block format:
* http://minecraft.gamepedia.com/Structure_block_file_format

View File

@ -30,10 +30,12 @@ import com.boydti.fawe.object.io.FastByteArraysInputStream;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
@ -45,6 +47,7 @@ import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.entity.EntityTypes;
@ -55,9 +58,11 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.OptionalInt;
import java.util.UUID;
import java.util.function.Function;
@ -70,9 +75,10 @@ public class FastSchematicReader extends NBTSchematicReader {
private static final Logger log = LoggerFactory.getLogger(FastSchematicReader.class);
private final NBTInputStream inputStream;
private DataFixer fixer = null;
private DataFixer fixer;
private int dataVersion = -1;
private int version = -1;
private int faweWritten = -1;
private FastByteArrayOutputStream blocksOut;
private FaweOutputStream blocks;
@ -92,6 +98,8 @@ public class FastSchematicReader extends NBTSchematicReader {
private char[] palette;
private char[] biomePalette;
private BlockVector3 min = BlockVector3.ZERO;
private boolean brokenEntities = false;
private boolean isWorldEdit = false;
/**
@ -105,6 +113,10 @@ public class FastSchematicReader extends NBTSchematicReader {
this.fixer = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataFixer();
}
public void setBrokenEntities(boolean brokenEntities) {
this.brokenEntities = brokenEntities;
}
private String fix(String palettePart) {
if (fixer == null || dataVersion == -1) {
return palettePart;
@ -133,7 +145,7 @@ public class FastSchematicReader extends NBTSchematicReader {
return fixer.fixUp(DataFixer.FixTypes.BIOME, biomePalettePart, dataVersion);
}
public StreamDelegate createDelegate() {
public StreamDelegate createVersionDelegate() {
StreamDelegate root = new StreamDelegate();
StreamDelegate schematic = root.add("Schematic");
schematic.add("DataVersion").withInt((i, v) -> dataVersion = v);
@ -143,6 +155,12 @@ public class FastSchematicReader extends NBTSchematicReader {
dataVersion = Constants.DATA_VERSION_MC_1_13_2;
}
});
return root;
}
public StreamDelegate createDelegate() {
StreamDelegate root = new StreamDelegate();
StreamDelegate schematic = root.add("Schematic");
schematic.add("Width").withInt((i, v) -> width = v);
schematic.add("Height").withInt((i, v) -> height = v);
schematic.add("Length").withInt((i, v) -> length = v);
@ -152,17 +170,23 @@ public class FastSchematicReader extends NBTSchematicReader {
metadata.add("WEOffsetX").withInt((i, v) -> offsetX = v);
metadata.add("WEOffsetY").withInt((i, v) -> offsetY = v);
metadata.add("WEOffsetZ").withInt((i, v) -> offsetZ = v);
metadata.add("FAWEVersion").withInt((i, v) -> faweWritten = v);
StreamDelegate worldEditSection = metadata.add("WorldEdit");
worldEditSection.withValue((ValueReader<String>) (index, v) -> isWorldEdit = true);
StreamDelegate paletteDelegate = schematic.add("Palette");
paletteDelegate.withValue((ValueReader<Map<String, Object>>) (ignore, v) -> {
palette = new char[v.size()];
for (Entry<String, Object> entry : v.entrySet()) {
BlockState state = null;
BlockState state;
String palettePart = fix(entry.getKey());
try {
String palettePart = fix(entry.getKey());
state = BlockState.get(palettePart);
} catch (InputParseException e) {
e.printStackTrace();
} catch (InputParseException ignored) {
log.warn("Invalid BlockState in palette: " + palettePart + ". Block will be replaced with air.");
state = BlockTypes.AIR.getDefaultState();
}
int index = (int) entry.getValue();
palette[index] = (char) state.getOrdinal();
@ -224,10 +248,14 @@ public class FastSchematicReader extends NBTSchematicReader {
@Override
public Clipboard read(UUID uuid, Function<BlockVector3, Clipboard> createOutput) throws IOException {
StreamDelegate root = createDelegate();
StreamDelegate versions = createVersionDelegate();
inputStream.mark(Integer.MAX_VALUE);
inputStream.readNamedTagLazy(versions);
inputStream.reset();
inputStream.readNamedTagLazy(root);
if (version != 1 && version != 2) {
throw new IOException("This schematic version is currently not supported");
throw new IOException("This schematic version is currently not supported (" + version + ")");
}
if (blocks != null) {
@ -240,9 +268,11 @@ public class FastSchematicReader extends NBTSchematicReader {
biomes = null;
BlockVector3 dimensions = BlockVector3.at(width, height, length);
BlockVector3 origin = BlockVector3.ZERO;
BlockVector3 origin;
if (offsetX != Integer.MIN_VALUE && offsetY != Integer.MIN_VALUE && offsetZ != Integer.MIN_VALUE) {
origin = BlockVector3.at(-offsetX, -offsetY, -offsetZ);
} else {
origin = BlockVector3.ZERO;
}
Clipboard clipboard = createOutput.apply(dimensions);
@ -326,7 +356,7 @@ public class FastSchematicReader extends NBTSchematicReader {
y = pos[1];
z = pos[2];
}
Map<String, Tag> values = tile.getValue();
Map<String, Tag> values = new HashMap<>(tile.getValue());
Tag id = values.get("Id");
if (id != null) {
values.put("x", new IntTag(x));
@ -337,22 +367,19 @@ public class FastSchematicReader extends NBTSchematicReader {
values.remove("Id");
values.remove("Pos");
tile = fixBlockEntity(tile);
clipboard.setTile(x, y, z, tile);
clipboard.setTile(x, y, z, fixBlockEntity(new CompoundTag(values)));
}
}
// entities
if (entities != null && !entities.isEmpty()) {
for (Map<String, Object> entRaw : entities) {
CompoundTag ent = FaweCache.IMP.asTag(entRaw);
Map<String, Tag> value = ent.getValue();
Map<String, Tag> value = new HashMap<>(FaweCache.IMP.asTag(entRaw).getValue());
StringTag id = (StringTag) value.get("Id");
if (id == null) {
id = (StringTag) value.get("id");
if (id == null) {
return null;
continue;
}
}
value.put("id", id);
@ -360,10 +387,29 @@ public class FastSchematicReader extends NBTSchematicReader {
EntityType type = EntityTypes.parse(id.getValue());
if (type != null) {
ent = fixEntity(ent);
final CompoundTag ent = fixEntity(new CompoundTag(value));
BaseEntity state = new BaseEntity(type, ent);
Location loc = ent.getEntityLocation(clipboard);
clipboard.createEntity(loc, state);
if (brokenEntities) {
clipboard.createEntity(loc, state);
continue;
}
if (!isWorldEdit && faweWritten == -1) {
int locX = loc.getBlockX();
int locY = loc.getBlockY();
int locZ = loc.getBlockZ();
BlockVector3 max = min.add(dimensions).subtract(BlockVector3.ONE);
if (locX < min.getX() || locY < min.getY() || locZ < min.getZ()
|| locX > max.getX() || locY > max.getY() || locZ > max.getZ()) {
for (Entity e : clipboard.getEntities()) {
clipboard.removeEntity(e);
}
log.error("Detected schematic entity outside clipboard region. FAWE will not load entities. "
+ "Please try loading the schematic with the format \"legacyentity\"");
break;
}
}
clipboard.createEntity(loc.setPosition(loc.subtract(min.toVector3())), state);
} else {
log.debug("Invalid entity: " + id);
}
@ -372,7 +418,7 @@ public class FastSchematicReader extends NBTSchematicReader {
clipboard.setOrigin(origin);
if (!min.equals(BlockVector3.ZERO)) {
new BlockArrayClipboard(clipboard, min);
clipboard = new BlockArrayClipboard(clipboard, min);
}
return clipboard;

View File

@ -19,10 +19,10 @@
package com.sk89q.worldedit.extent.clipboard.io;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.jnbt.streamer.IntValueReader;
import com.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.util.IOUtil;
import com.google.common.collect.Maps;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntArrayTag;
import com.sk89q.jnbt.ListTag;
@ -39,6 +39,7 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.visitor.Order;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock;
@ -58,8 +59,6 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
@ -72,6 +71,7 @@ public class FastSchematicWriter implements ClipboardWriter {
private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE;
private final NBTOutputStream outputStream;
private boolean brokenEntities = false;
/**
* Create a new schematic writer.
@ -83,6 +83,10 @@ public class FastSchematicWriter implements ClipboardWriter {
this.outputStream = outputStream;
}
public void setBrokenEntities(boolean brokenEntities) {
this.brokenEntities = brokenEntities;
}
@Override
public void write(Clipboard clipboard) throws IOException {
// For now always write the latest version. Maybe provide support for earlier if more appear.
@ -123,15 +127,16 @@ public class FastSchematicWriter implements ClipboardWriter {
// The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin'
out.writeNamedTag("Offset", new int[]{
min.getBlockX(),
min.getBlockY(),
min.getBlockZ(),
min.getBlockX(),
min.getBlockY(),
min.getBlockZ(),
});
out.writeLazyCompoundTag("Metadata", out1 -> {
out1.writeNamedTag("WEOffsetX", offset.getBlockX());
out1.writeNamedTag("WEOffsetY", offset.getBlockY());
out1.writeNamedTag("WEOffsetZ", offset.getBlockZ());
out1.writeNamedTag("FAWEVersion", Fawe.get().getVersion().build);
});
ByteArrayOutputStream blocksCompressed = new ByteArrayOutputStream();
@ -157,7 +162,7 @@ public class FastSchematicWriter implements ClipboardWriter {
BaseBlock block = pos.getFullBlock(finalClipboard);
CompoundTag nbt = block.getNbtData();
if (nbt != null) {
Map<String, Tag> values = nbt.getValue();
Map<String, Tag> values = new HashMap<>(nbt.getValue());
// Positions are kept in NBT, we don't want that.
values.remove("x");
@ -170,12 +175,13 @@ public class FastSchematicWriter implements ClipboardWriter {
// Dum.
values.remove("id");
values.put("Pos", new IntArrayTag(new int[]{
pos.getX(),
pos.getY(),
pos.getZ()
pos.getX(),
pos.getY(),
pos.getZ()
}));
numTiles++;
tilesOut.writeTagPayload(block.getNbtData());
tilesOut.writeTagPayload(new CompoundTag(values));
}
int ordinal = block.getOrdinal();
@ -240,8 +246,12 @@ public class FastSchematicWriter implements ClipboardWriter {
// Store our location data, overwriting any
values.remove("id");
Location loc = entity.getLocation();
if (!brokenEntities) {
loc = loc.setPosition(loc.add(min.toVector3()));
}
values.put("Id", new StringTag(state.getType().getId()));
values.put("Pos", writeVector(entity.getLocation()));
values.put("Pos", writeVector(loc));
values.put("Rotation", writeRotation(entity.getLocation()));
CompoundTag entityTag = new CompoundTag(values);
@ -311,30 +321,6 @@ public class FastSchematicWriter implements ClipboardWriter {
}
}
private void writeEntities(Clipboard clipboard, NBTOutputStream schematic) throws IOException {
List<CompoundTag> entities = clipboard.getEntities().stream().map(e -> {
BaseEntity state = e.getState();
if (state == null) {
return null;
}
Map<String, Tag> values = Maps.newHashMap();
CompoundTag rawData = state.getNbtData();
if (rawData != null) {
values.putAll(rawData.getValue());
}
values.remove("id");
values.put("Id", new StringTag(state.getType().getId()));
values.put("Pos", writeVector(e.getLocation().toVector()));
values.put("Rotation", writeRotation(e.getLocation()));
return new CompoundTag(values);
}).filter(Objects::nonNull).collect(Collectors.toList());
if (entities.isEmpty()) {
return;
}
schematic.writeNamedTag("Entities", new ListTag(CompoundTag.class, entities));
}
@Override
public void close() throws IOException {
outputStream.close();

View File

@ -1,4 +0,0 @@
package com.sk89q.worldedit.extent.clipboard.io;
public class FaweFormat {
}

View File

@ -68,26 +68,24 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* Reads schematic files that are compatible with MCEdit and other editors.
* @deprecated Use SchematicStreamer
*/
@Deprecated
public class MCEditSchematicReader extends NBTSchematicReader {
private static final Logger log = LoggerFactory.getLogger(MCEditSchematicReader.class);
private final NBTInputStream inputStream;
private final DataFixer fixer;
private static final ImmutableList<NBTCompatibilityHandler> COMPATIBILITY_HANDLERS
= ImmutableList.of(
new SignCompatibilityHandler(),
new FlowerPotCompatibilityHandler(),
new NoteBlockCompatibilityHandler(),
new SkullBlockCompatibilityHandler(),
new BannerBlockCompatibilityHandler(),
new BedBlockCompatibilityHandler()
= ImmutableList.of(
new SignCompatibilityHandler(),
new FlowerPotCompatibilityHandler(),
new NoteBlockCompatibilityHandler(),
new SkullBlockCompatibilityHandler(),
new BannerBlockCompatibilityHandler(),
new BedBlockCompatibilityHandler()
);
private static final ImmutableList<EntityNBTCompatibilityHandler> ENTITY_COMPATIBILITY_HANDLERS
= ImmutableList.of(
new Pre13HangingCompatibilityHandler()
= ImmutableList.of(
new Pre13HangingCompatibilityHandler()
);
/**
@ -99,8 +97,8 @@ public class MCEditSchematicReader extends NBTSchematicReader {
checkNotNull(inputStream);
this.inputStream = inputStream;
this.fixer = null;
//com.sk89q.worldedit.WorldEdit.getInstance().getPlatformManager().queryCapability(
//com.sk89q.worldedit.extension.platform.Capability.WORLD_EDITING).getDataFixer();
//com.sk89q.worldedit.WorldEdit.getInstance().getPlatformManager().queryCapability(
//com.sk89q.worldedit.extension.platform.Capability.WORLD_EDITING).getDataFixer();
}
@Override
@ -207,7 +205,7 @@ public class MCEditSchematicReader extends NBTSchematicReader {
if (newBlock != null) {
for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) {
if (handler.isAffectedBlock(newBlock)) {
newBlock = handler.updateNBT(block, values);
newBlock = handler.updateNBT(block, values).toImmutableState();
if (newBlock == null || values.isEmpty()) {
break;
}
@ -256,7 +254,7 @@ public class MCEditSchematicReader extends NBTSchematicReader {
int combined = block << 8 | data;
if (unknownBlocks.add(combined)) {
log.warn("Unknown block when loading schematic: "
+ block + ":" + data + ". This is most likely a bad schematic.");
+ block + ":" + data + ". This is most likely a bad schematic.");
}
}
} catch (WorldEditException ignored) { // BlockArrayClipboard won't throw this
@ -302,7 +300,7 @@ public class MCEditSchematicReader extends NBTSchematicReader {
}
private String convertEntityId(String id) {
switch(id) {
switch (id) {
case "AreaEffectCloud": return "area_effect_cloud";
case "ArmorStand": return "armor_stand";
case "CaveSpider": return "cave_spider";

View File

@ -1,536 +0,0 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extent.clipboard.io;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.jnbt.streamer.StreamDelegate;
import com.boydti.fawe.jnbt.streamer.ValueReader;
import com.boydti.fawe.object.FaweInputStream;
import com.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.object.clipboard.LinearClipboard;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.object.io.FastByteArraysInputStream;
import com.boydti.fawe.object.io.ResettableFileInputStream;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.BannerBlockCompatibilityHandler;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.BedBlockCompatibilityHandler;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.EntityNBTCompatibilityHandler;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.FlowerPotCompatibilityHandler;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NBTCompatibilityHandler;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NoteBlockCompatibilityHandler;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.Pre13HangingCompatibilityHandler;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.SignCompatibilityHandler;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.SkullBlockCompatibilityHandler;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.registry.state.PropertyKey;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockCategories;
import com.sk89q.worldedit.world.block.BlockID;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypeSwitch;
import com.sk89q.worldedit.world.block.BlockTypeSwitchBuilder;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.entity.EntityTypes;
import com.sk89q.worldedit.world.registry.BlockMaterial;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import java.util.zip.GZIPInputStream;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Reads schematic files based that are compatible with MCEdit and other editors.
*/
public class SchematicReader implements ClipboardReader {
private static final Logger log = LoggerFactory.getLogger(SchematicReader.class);
private static final NBTCompatibilityHandler[] COMPATIBILITY_HANDLERS = {
new SignCompatibilityHandler(),
new FlowerPotCompatibilityHandler(),
new NoteBlockCompatibilityHandler(),
new SkullBlockCompatibilityHandler(),
new BannerBlockCompatibilityHandler(),
new BedBlockCompatibilityHandler()
};
private static final EntityNBTCompatibilityHandler[] ENTITY_COMPATIBILITY_HANDLERS = {
new Pre13HangingCompatibilityHandler()
};
private NBTInputStream inputStream;
private InputStream rootStream;
// private final DataFixer fixer; TODO
private FastByteArrayOutputStream idOut = new FastByteArrayOutputStream();
private FastByteArrayOutputStream dataOut = new FastByteArrayOutputStream();
private FastByteArrayOutputStream addOut;
private FastByteArrayOutputStream biomesOut;
private FaweOutputStream ids;
private FaweOutputStream datas;
private FaweOutputStream adds;
private FaweOutputStream biomes;
private List<Map<String, Object>> tiles;
private List<Map<String, Object>> entities;
private int width;
private int height;
private int length;
private int offsetX;
private int offsetY;
private int offsetZ;
private int originX;
private int originY;
private int originZ;
/**
* Create a new instance.
*
* @param inputStream the input stream to read from
*/
public SchematicReader(NBTInputStream inputStream) {
checkNotNull(inputStream);
this.inputStream = inputStream;
}
public void setUnderlyingStream(InputStream in) {
this.rootStream = in;
}
public StreamDelegate createDelegate() {
StreamDelegate root = new StreamDelegate();
StreamDelegate schematic = root.add("Schematic");
schematic.add("Width").withInt((i, v) -> width = v);
schematic.add("Height").withInt((i, v) -> height = v);
schematic.add("Length").withInt((i, v) -> length = v);
schematic.add("WEOriginX").withInt((i, v) -> originX = v);
schematic.add("WEOriginY").withInt((i, v) -> originY = v);
schematic.add("WEOriginZ").withInt((i, v) -> originZ = v);
StreamDelegate metadata = schematic.add("Metadata");
metadata.add("WEOffsetX").withInt((i, v) -> offsetX = v);
metadata.add("WEOffsetY").withInt((i, v) -> offsetY = v);
metadata.add("WEOffsetZ").withInt((i, v) -> offsetZ = v);
StreamDelegate blocksDelegate = schematic.add("Blocks");
blocksDelegate.withInfo((length, type) -> ids = new FaweOutputStream(new LZ4BlockOutputStream(idOut)));
blocksDelegate.withInt((index, value) -> ids.write(value));
StreamDelegate dataDelegate = schematic.add("Data");
dataDelegate.withInfo((length, type) -> datas = new FaweOutputStream(new LZ4BlockOutputStream(dataOut)));
dataDelegate.withInt((index, value) -> datas.write(value));
StreamDelegate addDelegate = schematic.add("AddBlocks");
addDelegate.withInfo((length, type) -> {
addOut = new FastByteArrayOutputStream();
adds = new FaweOutputStream(new LZ4BlockOutputStream(addOut));
});
addDelegate.withInt((index, value) -> {
if (value != 0) {
int first = value & 0x0F;
int second = (value & 0xF0) >> 4;
adds.write(first);
adds.write(second);
} else {
adds.write(0);
adds.write(0);
}
});
StreamDelegate tilesDelegate = schematic.add("TileEntities");
tilesDelegate.withInfo((length, type) -> tiles = new ArrayList<>(length));
tilesDelegate.withElem((ValueReader<Map<String, Object>>) (index, tile) -> tiles.add(tile));
StreamDelegate entitiesDelegate = schematic.add("Entities");
entitiesDelegate.withInfo((length, type) -> entities = new ArrayList<>(length));
entitiesDelegate.withElem(
(ValueReader<Map<String, Object>>) (index, entity) -> entities.add(entity));
return root;
}
private int readCombined(InputStream idIn, InputStream dataIn) throws IOException {
return ((idIn.read() & 0xFF) << 4) + (dataIn.read() & 0xF);
}
private int readCombined(InputStream idIn, InputStream dataIn, InputStream addIn) throws IOException {
return ((addIn.read() & 0xFF) << 8) + readCombined(idIn, dataIn);
}
private BlockState getBlock(int combined) {
BlockState state = LegacyMapper.getInstance().getBlockFromLegacyCombinedId(combined);
return state;
}
private void write(int index, BlockState block, LinearClipboard clipboard) {
clipboard.setBlock(index, block);
}
private void write(int x, int y, int z, BlockState block, Clipboard clipboard) {
clipboard.setBlock(x, y, z, block);
}
private void readwrite(int index, InputStream idIn, InputStream dataIn, LinearClipboard out) throws IOException {
readwrite(index, readCombined(idIn, dataIn), out);
}
private void readwrite(int x, int y, int z, InputStream idIn, InputStream dataIn, Clipboard out) throws IOException {
readwrite(x, y, z, readCombined(idIn, dataIn), out);
}
private void readwrite(int index, InputStream idIn, InputStream dataIn, InputStream addIn, LinearClipboard out) throws IOException {
readwrite(index, readCombined(idIn, dataIn, addIn), out);
}
private void readwrite(int x, int y, int z, InputStream idIn, InputStream dataIn, InputStream addIn, Clipboard out) throws IOException {
readwrite(x, y, z, readCombined(idIn, dataIn, addIn), out);
}
private void readwrite(int index, int combined, LinearClipboard out) throws IOException {
write(index, getBlock(combined), out);
}
private void readwrite(int x, int y, int z, int combined, Clipboard out) throws IOException {
write(x, y, z, getBlock(combined), out);
}
@Override
public Clipboard read(UUID uuid, Function<BlockVector3, Clipboard> createOutput) throws IOException {
try {
return readInternal(uuid, createOutput);
} catch (EOFException e) {
log.error("EOFException read in schematic. Did you give the schematic the wrong extension?");
log.error("We will attempt to rectify your mistake for you and load the schematic assuming it is named .schem not .schematic");
e.printStackTrace();
final InputStream stream;
if (rootStream instanceof FileInputStream) {
stream = new ResettableFileInputStream((FileInputStream) rootStream);
} else {
stream = rootStream;
}
BufferedInputStream buffered = new BufferedInputStream(stream);
NBTInputStream nbtStream = new NBTInputStream(new BufferedInputStream(new GZIPInputStream(buffered)));
return (new FastSchematicReader(nbtStream)).read(uuid, createOutput);
}
}
private Clipboard readInternal(UUID uuid, Function<BlockVector3, Clipboard> createOutput) throws IOException {
StreamDelegate root = createDelegate();
inputStream.readNamedTagLazy(root);
if (ids != null) {
ids.close();
}
if (datas != null) {
datas.close();
}
if (adds != null) {
adds.close();
}
if (biomes != null) {
biomes.close();
}
ids = null;
datas = null;
adds = null;
biomes = null;
BlockVector3 dimensions = BlockVector3.at(width, height, length);
BlockVector3 origin = BlockVector3.ZERO;
if (offsetX != Integer.MIN_VALUE && offsetY != Integer.MIN_VALUE && offsetZ != Integer.MIN_VALUE) {
origin = BlockVector3.at(-offsetX, -offsetY, -offsetZ);
}
Clipboard clipboard = createOutput.apply(dimensions);
try (InputStream dataIn = new LZ4BlockInputStream(new FastByteArraysInputStream(dataOut.toByteArrays())); InputStream idIn = new LZ4BlockInputStream(new FastByteArraysInputStream(idOut.toByteArrays()))) {
if (addOut != null) {
try (FaweInputStream addIn = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(addOut.toByteArrays())))) {
if (clipboard instanceof LinearClipboard) {
LinearClipboard linear = (LinearClipboard) clipboard;
for (int y = 0, index = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++, index++) {
readwrite(index, idIn, dataIn, addIn, linear);
}
}
}
} else {
for (int y = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
readwrite(x, y, z, idIn, dataIn, addIn, clipboard);
}
}
}
}
}
} else {
if (clipboard instanceof LinearClipboard) {
LinearClipboard linear = (LinearClipboard) clipboard;
for (int y = 0, index = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++, index++) {
readwrite(index, idIn, dataIn, linear);
}
}
}
} else {
for (int y = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
readwrite(x, y, z, idIn, dataIn, clipboard);
}
}
}
}
}
}
// tiles
if (tiles != null && !tiles.isEmpty()) {
outer:
for (Map<String, Object> tileRaw : tiles) {
CompoundTag tile = FaweCache.IMP.asTag(tileRaw);
int x = (int) tileRaw.get("x");
int y = (int) tileRaw.get("y");
int z = (int) tileRaw.get("z");
BlockState block = clipboard.getBlock(x, y, z);
for (NBTCompatibilityHandler compat : COMPATIBILITY_HANDLERS) {
if (compat.isAffectedBlock(block)) {
block = compat.updateNBT(block, tile.getValue());
BaseBlock baseBlock = block.toBaseBlock(tile);
clipboard.setBlock(x, y, z, baseBlock);
continue outer;
}
}
clipboard.setTile(x, y, z, tile);
}
}
// entities
if (entities != null && !entities.isEmpty()) {
for (Map<String, Object> entRaw : entities) {
String id = (String) entRaw.get("id");
if (id == null) {
continue;
}
entRaw.put("Id", id);
EntityType type = EntityTypes.parse(id);
if (type != null) {
CompoundTag ent = FaweCache.IMP.asTag(entRaw);
for (EntityNBTCompatibilityHandler compat : ENTITY_COMPATIBILITY_HANDLERS) {
if (compat.isAffectedEntity(type, ent)) {
ent = compat.updateNBT(type, ent);
}
}
BaseEntity state = new BaseEntity(type, ent);
Location loc = ent.getEntityLocation(clipboard);
clipboard.createEntity(loc, state);
} else {
getLogger(SchematicReader.class).debug("Invalid entity: " + id);
}
}
}
fixStates(clipboard);
clipboard.setOrigin(origin);
BlockVector3 min = BlockVector3.at(originX, originY, originZ);
if (!min.equals(BlockVector3.ZERO)) {
new BlockArrayClipboard(clipboard, min);
}
return clipboard;
}
private void fixStates(Clipboard fc) {
for (BlockVector3 pos : fc) {
BlockState block = pos.getBlock(fc);
if (block.getMaterial().isAir()) {
continue;
}
int x = pos.getX();
int y = pos.getY();
int z = pos.getZ();
BlockType type = block.getBlockType();
if (BlockCategories.STAIRS.contains(type)) {
Direction facing = block.getState(PropertyKey.FACING);
BlockVector3 forward = facing.toBlockVector();
Direction left = facing.getLeft();
Direction right = facing.getRight();
BlockState forwardBlock = fc.getBlock(x + forward.getBlockX(), y + forward.getBlockY(), z + forward.getBlockZ());
BlockType forwardType = forwardBlock.getBlockType();
if (forwardType.hasProperty(PropertyKey.SHAPE) && forwardType.hasProperty(PropertyKey.FACING)) {
Direction forwardFacing = forwardBlock.getState(PropertyKey.FACING);
if (forwardFacing == left) {
BlockState rightBlock = fc.getBlock(x + right.toBlockVector().getBlockX(), y + right.toBlockVector().getBlockY(), z + right.toBlockVector().getBlockZ());
BlockType rightType = rightBlock.getBlockType();
if (!rightType.hasProperty(PropertyKey.SHAPE) || rightBlock.getState(PropertyKey.FACING) != facing) {
pos.setBlock(fc, block.with(PropertyKey.SHAPE, "inner_left"));
}
return;
} else if (forwardFacing == right) {
BlockState leftBlock = fc.getBlock(x + left.toBlockVector().getBlockX(), y + left.toBlockVector().getBlockY(), z + left.toBlockVector().getBlockZ());
BlockType leftType = leftBlock.getBlockType();
if (!leftType.hasProperty(PropertyKey.SHAPE) || leftBlock.getState(PropertyKey.FACING) != facing) {
fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "inner_right"));
}
return;
}
}
BlockState backwardsBlock = fc.getBlock(x - forward.getBlockX(), y - forward.getBlockY(), z - forward.getBlockZ());
BlockType backwardsType = backwardsBlock.getBlockType();
if (backwardsType.hasProperty(PropertyKey.SHAPE) && backwardsType.hasProperty(PropertyKey.FACING)) {
Direction backwardsFacing = (Direction) backwardsBlock.getState(PropertyKey.FACING);
if (backwardsFacing == left) {
BlockState rightBlock = fc.getBlock(x + right.toBlockVector().getBlockX(), y + right.toBlockVector().getBlockY(), z + right.toBlockVector().getBlockZ());
BlockType rightType = rightBlock.getBlockType();
if (!rightType.hasProperty(PropertyKey.SHAPE) || rightBlock.getState(PropertyKey.FACING) != facing) {
pos.setBlock(fc, block.with(PropertyKey.SHAPE, "outer_left"));
}
return;
} else if (backwardsFacing == right) {
BlockState leftBlock = fc.getBlock(x + left.toBlockVector().getBlockX(), y + left.toBlockVector().getBlockY(), z + left.toBlockVector().getBlockZ());
BlockType leftType = leftBlock.getBlockType();
if (!leftType.hasProperty(PropertyKey.SHAPE) || leftBlock.getState(PropertyKey.FACING) != facing) {
pos.setBlock(fc, block.with(PropertyKey.SHAPE, "outer_right"));
}
return;
}
}
} else {
int group = group(type);
if (group == -1) {
return;
}
BlockState set = block;
if (set.getState(PropertyKey.NORTH) == Boolean.FALSE && merge(fc, group, x, y, z - 1)) {
set = set.with(PropertyKey.NORTH, true);
}
if (set.getState(PropertyKey.EAST) == Boolean.FALSE && merge(fc, group, x + 1, y, z)) {
set = set.with(PropertyKey.EAST, true);
}
if (set.getState(PropertyKey.SOUTH) == Boolean.FALSE && merge(fc, group, x, y, z + 1)) {
set = set.with(PropertyKey.SOUTH, true);
}
if (set.getState(PropertyKey.WEST) == Boolean.FALSE && merge(fc, group, x - 1, y, z)) {
set = set.with(PropertyKey.WEST, true);
}
if (group == 2) {
int ns = (set.getState(PropertyKey.NORTH) ? 1 : 0) + ((Boolean) set.getState(PropertyKey.SOUTH) ? 1 : 0);
int ew = (set.getState(PropertyKey.EAST) ? 1 : 0) + ((Boolean) set.getState(PropertyKey.WEST) ? 1 : 0);
if (Math.abs(ns - ew) != 2 || fc.getBlock(x, y + 1, z).getBlockType().getMaterial().isSolid()) {
set = set.with(PropertyKey.UP, true);
}
}
if (set != block) {
pos.setBlock(fc, set);
}
}
}
}
private BlockTypeSwitch<Boolean> fullCube = new BlockTypeSwitchBuilder<>(false).add(type -> {
BlockMaterial mat = type.getMaterial();
return (mat.isFullCube() && !mat.isFragileWhenPushed() && mat.getLightValue() == 0 && mat.isOpaque() && mat.isSolid() && !mat.isTranslucent());
}, true).build();
private boolean merge(Clipboard fc, int group, int x, int y, int z) {
BlockState block = fc.getBlock(x, y, z);
BlockType type = block.getBlockType();
return group(type) == group || fullCube.apply(type);
}
private int group(BlockType type) {
switch (type.getInternalId()) {
case BlockID.ACACIA_FENCE:
case BlockID.BIRCH_FENCE:
case BlockID.DARK_OAK_FENCE:
case BlockID.JUNGLE_FENCE:
case BlockID.OAK_FENCE:
case BlockID.SPRUCE_FENCE:
return 0;
case BlockID.NETHER_BRICK_FENCE:
return 1;
case BlockID.COBBLESTONE_WALL:
case BlockID.MOSSY_COBBLESTONE_WALL:
return 2;
case BlockID.IRON_BARS:
case BlockID.BLACK_STAINED_GLASS_PANE:
case BlockID.BLUE_STAINED_GLASS_PANE:
case BlockID.BROWN_MUSHROOM_BLOCK:
case BlockID.BROWN_STAINED_GLASS_PANE:
case BlockID.CYAN_STAINED_GLASS_PANE:
case BlockID.GLASS_PANE:
case BlockID.GRAY_STAINED_GLASS_PANE:
case BlockID.GREEN_STAINED_GLASS_PANE:
case BlockID.LIGHT_BLUE_STAINED_GLASS_PANE:
case BlockID.LIGHT_GRAY_STAINED_GLASS_PANE:
case BlockID.LIME_STAINED_GLASS_PANE:
case BlockID.MAGENTA_STAINED_GLASS_PANE:
case BlockID.ORANGE_STAINED_GLASS_PANE:
case BlockID.PINK_STAINED_GLASS_PANE:
case BlockID.PURPLE_STAINED_GLASS_PANE:
case BlockID.RED_STAINED_GLASS_PANE:
case BlockID.WHITE_STAINED_GLASS_PANE:
case BlockID.YELLOW_STAINED_GLASS_PANE:
return 3;
default:
return -1;
}
}
@Override
public void close() throws IOException {
inputStream.close();
}
}

View File

@ -68,7 +68,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* Reads schematic files using the Sponge Schematic Specification.
*/
@Deprecated // High mem usage + slow
public class SpongeSchematicReader extends NBTSchematicReader {
private static final Logger log = LoggerFactory.getLogger(SpongeSchematicReader.class);
@ -93,7 +92,7 @@ public class SpongeSchematicReader extends NBTSchematicReader {
Map<String, Tag> schematic = schematicTag.getValue();
final Platform platform = WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.WORLD_EDITING);
.queryCapability(Capability.WORLD_EDITING);
int liveDataVersion = platform.getDataVersion();
if (schematicVersion == 1) {
@ -102,17 +101,23 @@ public class SpongeSchematicReader extends NBTSchematicReader {
return readVersion1(schematicTag);
} else if (schematicVersion == 2) {
dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue();
if (dataVersion < 0) {
log.warn("Schematic has an unknown data version ({}). Data may be incompatible.",
dataVersion);
// Do not DFU unknown data
dataVersion = liveDataVersion;
}
if (dataVersion > liveDataVersion) {
log.warn("Schematic was made in a newer Minecraft version ({} > {}). Data may be incompatible.",
dataVersion, liveDataVersion);
dataVersion, liveDataVersion);
} else if (dataVersion < liveDataVersion) {
fixer = platform.getDataFixer();
if (fixer != null) {
log.debug("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.",
dataVersion, liveDataVersion);
dataVersion, liveDataVersion);
} else {
log.info("Schematic was made in an older Minecraft version ({} < {}), but DFU is not available. Data may be incompatible.",
dataVersion, liveDataVersion);
dataVersion, liveDataVersion);
}
}
@ -130,7 +135,11 @@ public class SpongeSchematicReader extends NBTSchematicReader {
if (schematicVersion == 1) {
return OptionalInt.of(Constants.DATA_VERSION_MC_1_13_2);
} else if (schematicVersion == 2) {
return OptionalInt.of(requireTag(schematic, "DataVersion", IntTag.class).getValue());
int dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue();
if (dataVersion < 0) {
return OptionalInt.empty();
}
return OptionalInt.of(dataVersion);
}
return OptionalInt.empty();
} catch (IOException e) {
@ -140,9 +149,6 @@ public class SpongeSchematicReader extends NBTSchematicReader {
private CompoundTag getBaseTag() throws IOException {
NamedTag rootTag = inputStream.readNamedTag();
if (!rootTag.getName().equals("Schematic")) {
throw new IOException("Tag 'Schematic' does not exist or is not first");
}
CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
// Check
@ -226,9 +232,9 @@ public class SpongeSchematicReader extends NBTSchematicReader {
}
if (tileEntities != null) {
List<Map<String, Tag>> tileEntityTags = tileEntities.getValue().stream()
.map(tag -> (CompoundTag) tag)
.map(CompoundTag::getValue)
.collect(Collectors.toList());
.map(tag -> (CompoundTag) tag)
.map(CompoundTag::getValue)
.collect(Collectors.toList());
for (Map<String, Tag> tileEntity : tileEntityTags) {
int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue();
@ -321,8 +327,8 @@ public class SpongeSchematicReader extends NBTSchematicReader {
}
BiomeType biome = BiomeTypes.get(key);
if (biome == null) {
log.warn("Unknown biome type :" + key +
" in palette. Are you missing a mod or using a schematic made in a newer version of Minecraft?");
log.warn("Unknown biome type :" + key
+ " in palette. Are you missing a mod or using a schematic made in a newer version of Minecraft?");
}
Tag idTag = palettePart.getValue();
if (!(idTag instanceof IntTag)) {
@ -385,8 +391,8 @@ public class SpongeSchematicReader extends NBTSchematicReader {
EntityType entityType = EntityTypes.get(id);
if (entityType != null) {
Location location = NBTConversions.toLocation(clipboard,
requireTag(tags, "Pos", ListTag.class),
requireTag(tags, "Rotation", ListTag.class));
requireTag(tags, "Pos", ListTag.class),
requireTag(tags, "Rotation", ListTag.class));
BaseEntity state = new BaseEntity(entityType, entityTag);
clipboard.createEntity(location, state);
} else {

View File

@ -19,11 +19,10 @@
package com.sk89q.worldedit.extent.clipboard.io;
import com.boydti.fawe.Fawe;
import com.google.common.collect.Maps;
import com.sk89q.jnbt.ByteArrayTag;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.DoubleTag;
import com.sk89q.jnbt.FloatTag;
import com.sk89q.jnbt.IntArrayTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.ListTag;
@ -36,7 +35,6 @@ import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BiomeType;
@ -56,7 +54,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* Writes schematic files using the Sponge schematic format.
*/
@Deprecated // High mem usage + slow
public class SpongeSchematicWriter implements ClipboardWriter {
private static final int CURRENT_VERSION = 2;
@ -108,12 +105,13 @@ public class SpongeSchematicWriter implements ClipboardWriter {
Map<String, Tag> schematic = new HashMap<>();
schematic.put("Version", new IntTag(CURRENT_VERSION));
schematic.put("DataVersion", new IntTag(
WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion()));
WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion()));
Map<String, Tag> metadata = new HashMap<>();
metadata.put("WEOffsetX", new IntTag(offset.getBlockX()));
metadata.put("WEOffsetY", new IntTag(offset.getBlockY()));
metadata.put("WEOffsetZ", new IntTag(offset.getBlockZ()));
metadata.put("FAWEVersion", new IntTag(Fawe.get().getVersion().build));
schematic.put("Metadata", new CompoundTag(metadata));
@ -123,9 +121,9 @@ public class SpongeSchematicWriter implements ClipboardWriter {
// The Sponge format Offset refers to the 'min' points location in the world. That's our 'Origin'
schematic.put("Offset", new IntArrayTag(new int[]{
min.getBlockX(),
min.getBlockY(),
min.getBlockZ(),
min.getBlockX(),
min.getBlockY(),
min.getBlockZ(),
}));
int paletteMax = 0;
@ -268,21 +266,6 @@ public class SpongeSchematicWriter implements ClipboardWriter {
schematic.put("Entities", new ListTag(CompoundTag.class, entities));
}
public Tag writeVector(Vector3 vector) {
List<DoubleTag> list = new ArrayList<>();
list.add(new DoubleTag(vector.getX()));
list.add(new DoubleTag(vector.getY()));
list.add(new DoubleTag(vector.getZ()));
return new ListTag(DoubleTag.class, list);
}
public Tag writeRotation(Location location) {
List<FloatTag> list = new ArrayList<>();
list.add(new FloatTag(location.getYaw()));
list.add(new FloatTag(location.getPitch()));
return new ListTag(FloatTag.class, list);
}
@Override
public void close() throws IOException {
outputStream.close();

View File

@ -24,9 +24,8 @@ import com.sk89q.jnbt.CompoundTagBuilder;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.registry.state.DirectionalProperty;
import com.sk89q.worldedit.registry.state.IntegerProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
@ -38,15 +37,15 @@ import java.util.Map;
public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler {
private static final DirectionalProperty FacingProperty;
private static final IntegerProperty RotationProperty;
private static final Property<Direction> FacingProperty;
private static final Property<Integer> RotationProperty;
static {
DirectionalProperty tempFacing;
IntegerProperty tempRotation;
Property<Direction> tempFacing;
Property<Integer> tempRotation;
try {
tempFacing = (DirectionalProperty) (Property<?>) BlockTypes.WHITE_WALL_BANNER.getProperty("facing");
tempRotation = (IntegerProperty) (Property<?>) BlockTypes.WHITE_BANNER.getProperty("rotation");
tempFacing = BlockTypes.WHITE_WALL_BANNER.getProperty("facing");
tempRotation = BlockTypes.WHITE_BANNER.getProperty("rotation");
} catch (NullPointerException | IllegalArgumentException | ClassCastException e) {
tempFacing = null;
tempRotation = null;
@ -62,7 +61,7 @@ public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler
}
@Override
public <B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values) {
public <B extends BlockStateHolder<B>> BlockStateHolder<?> updateNBT(B block, Map<String, Tag> values) {
Tag typeTag = values.get("Base");
if (typeTag instanceof IntTag) {
boolean isWall = block.getBlockType() == BlockTypes.WHITE_WALL_BANNER;
@ -73,10 +72,10 @@ public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler
BlockState state = type.getDefaultState();
if (isWall) {
Property facingProp = type.getProperty("facing");
Property<Direction> facingProp = type.getProperty("facing");
state = state.with(facingProp, block.getState(FacingProperty));
} else {
Property rotationProp = type.getProperty("rotation");
Property<Integer> rotationProp = type.getProperty("rotation");
state = state.with(rotationProp, block.getState(RotationProperty));
}
@ -102,7 +101,7 @@ public class BannerBlockCompatibilityHandler implements NBTCompatibilityHandler
}
values.put("Patterns", new ListTag(((ListTag) patternsTag).getType(), tempList));
}
return (B) state;
return state;
}
}
}

View File

@ -21,9 +21,8 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.registry.state.DirectionalProperty;
import com.sk89q.worldedit.registry.state.EnumProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
@ -31,23 +30,24 @@ import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Map;
@SuppressWarnings("")
public class BedBlockCompatibilityHandler implements NBTCompatibilityHandler {
private static final DirectionalProperty FacingProperty;
private static final EnumProperty PartProperty;
private static final Property<Direction> FACING_PROPERTY;
private static final Property<String> PART_PROPERTY;
static {
DirectionalProperty tempFacing;
EnumProperty tempPart;
Property<Direction> tempFacing;
Property<String> tempPart;
try {
tempFacing = (DirectionalProperty) (Property<?>) BlockTypes.RED_BED.getProperty("facing");
tempPart = (EnumProperty) (Property<?>) BlockTypes.RED_BED.getProperty("part");
tempFacing = BlockTypes.RED_BED.getProperty("facing");
tempPart = BlockTypes.RED_BED.getProperty("part");
} catch (NullPointerException | IllegalArgumentException | ClassCastException e) {
tempFacing = null;
tempPart = null;
}
FacingProperty = tempFacing;
PartProperty = tempPart;
FACING_PROPERTY = tempFacing;
PART_PROPERTY = tempPart;
}
@Override
@ -56,7 +56,7 @@ public class BedBlockCompatibilityHandler implements NBTCompatibilityHandler {
}
@Override
public <B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values) {
public <B extends BlockStateHolder<B>> BlockStateHolder<?> updateNBT(B block, Map<String, Tag> values) {
Tag typeTag = values.get("color");
if (typeTag instanceof IntTag) {
String bedType = convertBedType(((IntTag) typeTag).getValue());
@ -65,17 +65,17 @@ public class BedBlockCompatibilityHandler implements NBTCompatibilityHandler {
if (type != null) {
BlockState state = type.getDefaultState();
Property facingProp = type.getProperty("facing");
state = state.with(facingProp, block.getState(FacingProperty));
Property<Direction> facingProp = type.getProperty("facing");
state = state.with(facingProp, block.getState(FACING_PROPERTY));
Property occupiedProp = type.getProperty("occupied");
Property<Boolean> occupiedProp = type.getProperty("occupied");
state = state.with(occupiedProp, false);
Property partProp = type.getProperty("part");
state = state.with(partProp, block.getState(PartProperty));
Property<String> partProp = type.getProperty("part");
state = state.with(partProp, block.getState(PART_PROPERTY));
values.remove("color");
return (B) state;
return state;
}
}
}

View File

@ -37,12 +37,12 @@ public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler {
}
@Override
public <B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values) {
public <B extends BlockStateHolder<B>> BlockStateHolder<?> updateNBT(B block, Map<String, Tag> values) {
Tag item = values.get("Item");
if (item instanceof StringTag) {
String id = ((StringTag) item).getValue();
if (id.isEmpty()) {
return (B) BlockTypes.FLOWER_POT.getDefaultState();
return BlockTypes.FLOWER_POT.getDefaultState();
}
int data = 0;
Tag dataTag = values.get("Data");
@ -52,7 +52,7 @@ public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler {
BlockState newState = convertLegacyBlockType(id, data);
if (newState != null) {
values.clear();
return (B) newState; // generics pls :\
return newState;
}
}
return block;

View File

@ -26,5 +26,6 @@ import java.util.Map;
public interface NBTCompatibilityHandler {
<B extends BlockStateHolder<B>> boolean isAffectedBlock(B block);
<B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values);
<B extends BlockStateHolder<B>> BlockStateHolder<?> updateNBT(B block, Map<String, Tag> values);
}

View File

@ -47,7 +47,7 @@ public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler {
}
@Override
public <B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values) {
public <B extends BlockStateHolder<B>> BlockStateHolder<?> updateNBT(B block, Map<String, Tag> values) {
// note that instrument was not stored (in state or nbt) previously.
// it will be updated to the block below when it gets set into the world for the first time
Tag noteTag = values.get("note");
@ -55,7 +55,7 @@ public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler {
Byte note = ((ByteTag) noteTag).getValue();
if (note != null) {
values.clear();
return (B) block.with(NoteProperty, (int) note).toImmutableState();
return block.with(NoteProperty, (int) note).toImmutableState();
}
}
return block;

View File

@ -26,8 +26,8 @@ import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.internal.util.DeprecationUtil;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Map;
@ -35,11 +35,11 @@ public class SignCompatibilityHandler implements NBTCompatibilityHandler {
@Override
public <B extends BlockStateHolder<B>> boolean isAffectedBlock(B block) {
return block.getBlockType() == BlockTypes.SIGN || block.getBlockType() == BlockTypes.WALL_SIGN;
return DeprecationUtil.isSign(block.getBlockType());
}
@Override
public <B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values) {
public <B extends BlockStateHolder<B>> BlockStateHolder<?> updateNBT(B block, Map<String, Tag> values) {
for (int i = 0; i < 4; ++i) {
String key = "Text" + (i + 1);
Tag value = values.get(key);

View File

@ -21,8 +21,8 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat;
import com.sk89q.jnbt.ByteTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.registry.state.DirectionalProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
@ -32,12 +32,12 @@ import java.util.Map;
public class SkullBlockCompatibilityHandler implements NBTCompatibilityHandler {
private static final DirectionalProperty FacingProperty;
private static final Property<Direction> FacingProperty;
static {
DirectionalProperty tempFacing;
Property<Direction> tempFacing;
try {
tempFacing = (DirectionalProperty) (Property<?>) BlockTypes.SKELETON_WALL_SKULL.getProperty("facing");
tempFacing = BlockTypes.SKELETON_WALL_SKULL.getProperty("facing");
} catch (NullPointerException | IllegalArgumentException | ClassCastException e) {
tempFacing = null;
}
@ -51,7 +51,7 @@ public class SkullBlockCompatibilityHandler implements NBTCompatibilityHandler {
}
@Override
public <B extends BlockStateHolder<B>> B updateNBT(B block, Map<String, Tag> values) {
public <B extends BlockStateHolder<B>> BlockStateHolder<?> updateNBT(B block, Map<String, Tag> values) {
boolean isWall = block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL;
Tag typeTag = values.get("SkullType");
if (typeTag instanceof ByteTag) {
@ -61,18 +61,18 @@ public class SkullBlockCompatibilityHandler implements NBTCompatibilityHandler {
if (type != null) {
BlockState state = type.getDefaultState();
if (isWall) {
Property newProp = type.getProperty("facing");
Property<Direction> newProp = type.getProperty("facing");
state = state.with(newProp, block.getState(FacingProperty));
} else {
Tag rotTag = values.get("Rot");
if (rotTag instanceof ByteTag) {
Property newProp = type.getProperty("rotation");
Property<Integer> newProp = type.getProperty("rotation");
state = state.with(newProp, (int) ((ByteTag) rotTag).getValue());
}
}
values.remove("SkullType");
values.remove("Rot");
return (B) state;
return state;
}
}
}

View File

@ -22,6 +22,7 @@ package com.sk89q.worldedit.function.mask;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BlockCategory;
import com.sk89q.worldedit.world.block.BlockTypes;
import javax.annotation.Nullable;
@ -61,4 +62,9 @@ public class BlockCategoryMask extends AbstractExtentMask {
public Mask copy() {
return new BlockCategoryMask(getExtent(), category);
}
@Override
public boolean replacesAir() {
return category.contains(BlockTypes.AIR);
}
}

View File

@ -29,12 +29,12 @@ import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import com.sk89q.worldedit.world.block.ImmutableBaseBlock;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
@ -185,7 +185,7 @@ public class BlockMask extends ABlockMask {
@Override
public boolean test(BlockState state) {
return ordinals[state.getOrdinal()] || replacesAir() && state.getOrdinal() <= 3;
return ordinals[state.getOrdinal()] || replacesAir() && state.getOrdinal() == 0;
}
@Override
@ -259,19 +259,16 @@ public class BlockMask extends ABlockMask {
int setTypes = 0;
BlockType setType = null;
BlockType unsetType = null;
int totalTypes = 0;
for (BlockType type : BlockTypesCache.values) {
if (type != null) {
totalTypes++;
boolean hasAll = true;
boolean hasAny = false;
List<BlockState> all = type.getAllStates();
for (BlockState state : all) {
totalStates++;
hasAll &= test(state);
hasAny = true;
}
if (hasAll) {
setTypes++;
@ -326,6 +323,7 @@ public class BlockMask extends ABlockMask {
cloned[BlockTypes.AIR.getDefaultState().getOrdinal()] = false;
cloned[BlockTypes.CAVE_AIR.getDefaultState().getOrdinal()] = false;
cloned[BlockTypes.VOID_AIR.getDefaultState().getOrdinal()] = false;
cloned[0] = false;
}
return new BlockMask(getExtent(), cloned);
}

Some files were not shown because too many files have changed in this diff Show More