This commit is contained in:
Jesse Boyd 2016-07-10 23:37:18 +10:00
parent f202a563fc
commit 9ed6880d1d
23 changed files with 759 additions and 84 deletions

View File

@ -204,6 +204,8 @@ public class FaweBukkit implements IFawe, Listener {
debug("NMS label: " + plugin.getClass().getSimpleName().split("_")[1]);
debug("Fallback placer: " + BukkitQueue_All.class);
debug("=======================================");
debug("Download the version of FAWE for your platform");
debug("=======================================");
hasNMS = false;
}
return new BukkitQueue_All(world);

View File

@ -6,14 +6,15 @@ import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@ -21,10 +22,12 @@ import java.util.concurrent.ConcurrentLinkedDeque;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.WorldInitEvent;
public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMappedFaweQueue<World, CHUNK, CHUNKSECTIONS, SECTION> implements Listener {
@ -62,8 +65,8 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
long pair = MathMan.pairInt(chunk.getX(), chunk.getZ());
for (FaweQueue queue : queues) {
if (queue.getWorldName().equals(world)) {
HashSet<Long> relighting = ((NMSMappedFaweQueue) queue).relighting;
if (!relighting.isEmpty() && relighting.contains(pair)) {
Map<Long, Long> relighting = ((NMSMappedFaweQueue) queue).relighting;
if (!relighting.isEmpty() && relighting.containsKey(pair)) {
event.setCancelled(true);
return;
}
@ -71,6 +74,28 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
}
}
private static boolean disableChunkLoad = false;
@EventHandler
public static void onWorldLoad(WorldInitEvent event) {
if (disableChunkLoad) {
World world = event.getWorld();
world.setKeepSpawnInMemory(false);
}
}
public World createWorld(final WorldCreator creator) {
World world = TaskManager.IMP.sync(new RunnableVal<World>() {
@Override
public void run(World value) {
disableChunkLoad = true;
this.value = creator.createWorld();
disableChunkLoad = false;
}
});
return world;
}
public void setupAdapter(BukkitImplAdapter adapter) {
try {
WorldEditPlugin instance = (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit");

View File

@ -4,6 +4,7 @@ import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
@ -27,6 +28,7 @@ import org.bukkit.Sound;
import org.bukkit.TreeType;
import org.bukkit.World;
import org.bukkit.WorldBorder;
import org.bukkit.WorldCreator;
import org.bukkit.WorldType;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
@ -47,21 +49,36 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.util.Vector;
/**
* Modify the world from an async thread <br>
* - Any Chunk/Block/BlockState objects returned should also be thread safe <br>
* - Use world.commit() to execute the changes <br>
* - Don't rely on autoQueue as behavior is determined by the settings.yml <br>
* Modify the world from an async thread<br>
* - Use world.commit() to execute all the changes<br>
* - Any Chunk/Block/BlockState objects returned should also be safe to use from the same async thread<br>
* - Only block read,write and biome write are fast, other methods will perform slower async<br>
* -
* @see #wrap(org.bukkit.World)
* @see #create(org.bukkit.WorldCreator)
*/
public class AsyncWorld implements World {
public final World parent;
public final FaweQueue queue;
private final World parent;
private final FaweQueue queue;
private BukkitImplAdapter adapter;
/**
* @deprecated use {@link #wrap(org.bukkit.World)} instead
* @param parent Parent world
* @param autoQueue
*/
@Deprecated
public AsyncWorld(World parent, boolean autoQueue) {
this(parent, FaweAPI.createQueue(parent.getName(), autoQueue));
}
/**
* @deprecated use {@link #wrap(org.bukkit.World)} instead
* @param parent
* @param queue
*/
@Deprecated
public AsyncWorld(World parent, FaweQueue queue) {
this.parent = parent;
this.queue = queue;
@ -79,6 +96,11 @@ public class AsyncWorld implements World {
}
}
/**
* Wrap a world for async usage
* @param world
* @return
*/
public static AsyncWorld wrap(World world) {
if (world instanceof AsyncWorld) {
return (AsyncWorld) world;
@ -86,6 +108,28 @@ public class AsyncWorld implements World {
return new AsyncWorld(world, false);
}
public World getParent() {
return parent;
}
public FaweQueue getQueue() {
return queue;
}
/**
* Create a world async (untested)
* - Only optimized for 1.10
* @param creator
* @return
*/
public static AsyncWorld create(final WorldCreator creator) {
long start = System.currentTimeMillis();
BukkitQueue_0 queue = (BukkitQueue_0) SetQueue.IMP.getNewQueue(creator.name(), true, false);
World world = queue.createWorld(creator);
System.out.println(System.currentTimeMillis() - start);
return wrap(world);
}
public void enqueue() {
queue.enqueue();
}

View File

@ -18,6 +18,7 @@ import com.sk89q.jnbt.LongTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.internal.Constants;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
@ -44,22 +45,37 @@ import net.minecraft.server.v1_10_R1.EntityPlayer;
import net.minecraft.server.v1_10_R1.EntityTracker;
import net.minecraft.server.v1_10_R1.EntityTrackerEntry;
import net.minecraft.server.v1_10_R1.EntityTypes;
import net.minecraft.server.v1_10_R1.EnumDifficulty;
import net.minecraft.server.v1_10_R1.EnumGamemode;
import net.minecraft.server.v1_10_R1.IBlockData;
import net.minecraft.server.v1_10_R1.IDataManager;
import net.minecraft.server.v1_10_R1.MinecraftServer;
import net.minecraft.server.v1_10_R1.NBTTagCompound;
import net.minecraft.server.v1_10_R1.NibbleArray;
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_10_R1.PacketPlayOutMapChunk;
import net.minecraft.server.v1_10_R1.PlayerChunk;
import net.minecraft.server.v1_10_R1.PlayerChunkMap;
import net.minecraft.server.v1_10_R1.ServerNBTManager;
import net.minecraft.server.v1_10_R1.TileEntity;
import net.minecraft.server.v1_10_R1.WorldData;
import net.minecraft.server.v1_10_R1.WorldManager;
import net.minecraft.server.v1_10_R1.WorldServer;
import net.minecraft.server.v1_10_R1.WorldSettings;
import net.minecraft.server.v1_10_R1.WorldType;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.WorldCreator;
import org.bukkit.block.Biome;
import org.bukkit.craftbukkit.v1_10_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_10_R1.CraftServer;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.generator.ChunkGenerator;
public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], DataPaletteBlock> {
@ -82,6 +98,69 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], DataP
}
}
@Override
public World createWorld(final WorldCreator creator) {
final String name = creator.name();
ChunkGenerator generator = creator.generator();
final CraftServer server = (CraftServer) Bukkit.getServer();
final MinecraftServer console = server.getServer();
final File folder = new File(server.getWorldContainer(), name);
final World world = server.getWorld(name);
final WorldType type = WorldType.getType(creator.type().getName());
final boolean generateStructures = creator.generateStructures();
if (world != null) {
return world;
}
if (folder.exists() && !folder.isDirectory()) {
throw new IllegalArgumentException("File exists with the name '" + name + "' and isn't a folder");
}
if (generator == null) {
generator = server.getGenerator(name);
}
int dimension = 10 + console.worlds.size();
boolean used = false;
do {
for (final WorldServer ws : console.worlds) {
used = (ws.dimension == dimension);
if (used) {
++dimension;
break;
}
}
} while (used);
final boolean hardcore = false;
final IDataManager sdm = new ServerNBTManager(server.getWorldContainer(), name, true, server.getHandle().getServer().getDataConverterManager());
WorldData worlddata = sdm.getWorldData();
WorldSettings worldSettings = null;
if (worlddata == null) {
worldSettings = new WorldSettings(creator.seed(), EnumGamemode.getById(server.getDefaultGameMode().getValue()), generateStructures, hardcore, type);
worldSettings.setGeneratorSettings(creator.generatorSettings());
worlddata = new WorldData(worldSettings, name);
}
worlddata.checkName(name);
final WorldServer internal = (WorldServer)new WorldServer(console, sdm, worlddata, dimension, console.methodProfiler, creator.environment(), generator).b();
if (worldSettings != null) {
internal.a(worldSettings);
}
internal.scoreboard = server.getScoreboardManager().getMainScoreboard().getHandle();
internal.tracker = new EntityTracker(internal);
internal.addIWorldAccess(new WorldManager(console, internal));
internal.worldData.setDifficulty(EnumDifficulty.EASY);
internal.setSpawnFlags(true, true);
console.worlds.add(internal);
if (generator != null) {
internal.getWorld().getPopulators().addAll(generator.getDefaultPopulators(internal.getWorld()));
}
return TaskManager.IMP.sync(new RunnableVal<World>() {
@Override
public void run(World value) {
server.getPluginManager().callEvent(new WorldInitEvent(internal.getWorld()));
server.getPluginManager().callEvent(new WorldLoadEvent(internal.getWorld()));
this.value = internal.getWorld();
}
});
}
@Override
public ChunkSection[] getCachedSections(World world, int cx, int cz) {
CraftChunk chunk = (CraftChunk) world.getChunkAt(cx, cz);

View File

@ -26,6 +26,7 @@ import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.BlockData;
import com.sk89q.worldedit.command.BrushCommands;
import com.sk89q.worldedit.command.ClipboardCommands;
import com.sk89q.worldedit.command.FlattenedClipboardTransform;
import com.sk89q.worldedit.command.HistoryCommands;
import com.sk89q.worldedit.command.NavigationCommands;
import com.sk89q.worldedit.command.RegionCommands;
@ -295,6 +296,8 @@ public class Fawe {
RecursiveVisitor.inject(); // Optimizations
RegionVisitor.inject(); // Translations + Optimizations
ExtentEntityCopy.inject(); // Async entity create fix
// Transforms
FlattenedClipboardTransform.inject(); // public access
// Entity create/remove
EntityCreate.inject(); // Optimizations
EntityRemove.inject(); // Optimizations

View File

@ -1,6 +1,7 @@
package com.boydti.fawe.config;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.configuration.MemorySection;
import com.boydti.fawe.configuration.file.YamlConfiguration;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.util.MainUtil;
@ -255,24 +256,21 @@ public enum BBC {
final HashSet<BBC> captions = new HashSet<>();
boolean changed = false;
for (final String key : keys) {
if (!yml.isString(key)) {
if (!allCats.contains(key)) {
toRemove.add(key);
}
final Object value = yml.get(key);
if (value instanceof MemorySection) {
continue;
}
final String[] split = key.split("\\.");
final String node = split[split.length - 1].toUpperCase();
final BBC caption = allNames.contains(node) ? valueOf(node) : null;
if (caption != null) {
final String value = yml.getString(key);
if (!split[0].equalsIgnoreCase(caption.cat)) {
changed = true;
yml.set(key, null);
yml.set(caption.cat + "." + caption.name().toLowerCase(), value);
}
captions.add(caption);
caption.s = value;
caption.s = (String) value;
} else {
toRemove.add(key);
}

View File

@ -241,4 +241,4 @@ public class Settings extends Config {
}
return limit;
}
}
}

View File

@ -182,7 +182,46 @@ public abstract class CharFaweChunk<T> extends FaweChunk<T> {
}
@Override
public void setBlock(final int x, final int y, final int z, final int id, byte data) {
public void setBlock(int x, int y, int z, int id) {
final int i = FaweCache.CACHE_I[y][x][z];
final int j = FaweCache.CACHE_J[y][x][z];
char[] vs = this.ids[i];
if (vs == null) {
vs = this.ids[i] = new char[4096];
this.count[i]++;
} else if (vs[j] == 0) {
this.count[i]++;
}
switch (id) {
case 0:
this.air[i]++;
vs[j] = (char) 1;
return;
case 11:
case 39:
case 40:
case 51:
case 74:
case 89:
case 122:
case 124:
case 138:
case 169:
case 213:
case 130:
case 76:
case 62:
case 50:
case 10:
this.relight[i]++;
default:
vs[j] = (char) (id << 4);
return;
}
}
@Override
public void setBlock(final int x, final int y, final int z, final int id, int data) {
final int i = FaweCache.CACHE_I[y][x][z];
final int j = FaweCache.CACHE_J[y][x][z];
char[] vs = this.ids[i];

View File

@ -126,10 +126,7 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
private int lastZ = Integer.MIN_VALUE;
@Override
public boolean setBlock(int x, int y, int z, short id, byte data) {
if ((y > 255) || (y < 0)) {
return false;
}
public boolean setBlock(int x, int y, int z, int id, int data) {
int cx = x >> 4;
int cz = z >> 4;
if (cx != lastX || cz != lastZ) {
@ -153,6 +150,31 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
return true;
}
@Override
public boolean setBlock(int x, int y, int z, int id) {
int cx = x >> 4;
int cz = z >> 4;
if (cx != lastX || cz != lastZ) {
lastX = cx;
lastZ = cz;
long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL;
lastWrappedChunk = this.blocks.get(pair);
if (lastWrappedChunk == null) {
lastWrappedChunk = this.getFaweChunk(x >> 4, z >> 4);
lastWrappedChunk.setBlock(x & 15, y, z & 15, id);
FaweChunk previous = this.blocks.put(pair, lastWrappedChunk);
if (previous == null) {
chunks.add(lastWrappedChunk);
return true;
}
this.blocks.put(pair, previous);
lastWrappedChunk = previous;
}
}
lastWrappedChunk.setBlock(x & 15, y, z & 15, id);
return true;
}
@Override
public void setTile(int x, int y, int z, CompoundTag tag) {
if ((y > 255) || (y < 0)) {

View File

@ -9,10 +9,10 @@ import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.jnbt.CompoundTag;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> extends MappedFaweQueue<WORLD, CHUNKSECTION, SECTION> {
public NMSMappedFaweQueue(String world) {
@ -24,7 +24,7 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
return relighting.contains(pair) || blocks.contains(pair);
}
public final HashSet<Long> relighting = new HashSet<>();
public final ConcurrentHashMap<Long, Long> relighting = new ConcurrentHashMap<>();
@Override
public void sendChunk(final FaweChunk fc, RelightMode mode) {
@ -36,7 +36,7 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
@Override
public void run() {
final long pair = fc.longHash();
relighting.add(pair);
relighting.put(pair, pair);
final boolean result = finalMode == RelightMode.NONE || fixLighting(fc, finalMode);
TaskManager.IMP.taskSyncNow(new Runnable() {
@Override
@ -47,7 +47,7 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
CHUNK chunk = (CHUNK) fc.getChunk();
refreshChunk(getWorld(), chunk);
relighting.remove(pair);
if (relighting.isEmpty()) {
if (relighting.isEmpty() && chunks.isEmpty()) {
runTasks();
}
}

View File

@ -23,7 +23,7 @@ public class ChangeSetFaweQueue extends DelegateFaweQueue {
}
@Override
public boolean setBlock(int x, int y, int z, short id, byte data) {
public boolean setBlock(int x, int y, int z, int id, int data) {
if (super.setBlock(x, y, z, id, data)) {
int combinedFrom = getParent().getCombinedId4Data(x, y, z);
if (FaweCache.hasNBT(combinedFrom >> 4)) {

View File

@ -185,7 +185,11 @@ public abstract class FaweChunk<T> {
public abstract void removeEntity(UUID uuid);
public abstract void setBlock(final int x, final int y, final int z, final int id, final byte data);
public void setBlock(int x, int y, int z, int id) {
setBlock(x, y, z, id, 0);
}
public abstract void setBlock(final int x, final int y, final int z, final int id, final int data);
public abstract Set<CompoundTag> getEntities();

View File

@ -103,7 +103,19 @@ public abstract class FaweQueue {
public void optimize() {}
public abstract boolean setBlock(final int x, final int y, final int z, final short id, final byte data);
public abstract boolean setBlock(final int x, final int y, final int z, final int id, final int data);
public boolean setBlock(int x, int y, int z, int id) {
return setBlock(x, y, z, id, 0);
}
public boolean setBlock(int x, int y, int z, int id, int data, CompoundTag nbt) {
if (nbt != null) {
MainUtil.setPosition(nbt, x, y, z);
setTile(x, y, z, nbt);
}
return setBlock(x, y, z, id, data);
}
public abstract void setTile(int x, int y, int z, CompoundTag tag);
@ -195,6 +207,13 @@ public abstract class FaweQueue {
* Lock the thread until the queue is empty
*/
public void flush() {
flush(Integer.MAX_VALUE);
}
/**
* Lock the thread until the queue is empty
*/
public void flush(int time) {
if (size() > 0) {
if (Fawe.get().isMainThread()) {
SetQueue.IMP.flush(this);
@ -207,7 +226,7 @@ public abstract class FaweQueue {
TaskManager.IMP.notify(running);
}
});
TaskManager.IMP.wait(running, 10000);
TaskManager.IMP.wait(running, time);
}
}
}

View File

@ -32,7 +32,7 @@ public class MaskedFaweQueue extends DelegateFaweQueue {
}
@Override
public boolean setBlock(int x, int y, int z, short id, byte data) {
public boolean setBlock(int x, int y, int z, int id, int data) {
if (WEManager.IMP.maskContains(mask, x, z)) {
return super.setBlock(x, y, z, id, data);
}

View File

@ -252,9 +252,10 @@ public abstract class FaweChangeSet implements ChangeSet {
} catch (Throwable e) {
MainUtil.handleError(e);
} finally {
waiting.decrementAndGet();
synchronized (lock) {
lock.notifyAll();
if (waiting.decrementAndGet() <= 0) {
synchronized (lock) {
lock.notifyAll();
}
}
}
}

View File

@ -103,7 +103,7 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
stream.write((combinedTo) & 0xff);
stream.write(((combinedTo) >> 8) & 0xff);
}
catch (IOException e) {
catch (Throwable e) {
MainUtil.handleError(e);
}
}

View File

@ -1,6 +1,5 @@
package com.boydti.fawe.object.extent;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.ReflectionUtils;
@ -107,30 +106,286 @@ public class FastWorldEditExtent extends AbstractDelegateExtent {
@Override
public boolean setBlock(final Vector location, final BaseBlock block) throws WorldEditException {
final short id = (short) block.getId();
byte data = (byte) block.getData();
final int x = location.getBlockX();
final int y = location.getBlockY();
final int z = location.getBlockZ();
switch (id) {
case 68: {
if (data == 0) {
data = 2;
}
}
final int y = (int) location.y;
switch (y) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25:
case 26:
case 27:
case 28:
case 29:
case 30:
case 31:
case 32:
case 33:
case 34:
case 35:
case 36:
case 37:
case 38:
case 39:
case 40:
case 41:
case 42:
case 43:
case 44:
case 45:
case 46:
case 47:
case 48:
case 49:
case 50:
case 51:
case 52:
case 53:
case 54:
case 55:
case 56:
case 57:
case 58:
case 59:
case 60:
case 61:
case 62:
case 63:
if (block.hasNbtData() && !MainUtil.isValidSign(block.getNbtData())) {
queue.setBlock(x, y, z, id, FaweCache.hasData(id) ? (byte) block.getData() : 0);
return true;
}
case 64:
case 65:
case 66:
case 67:
case 68:
case 69:
case 70:
case 71:
case 72:
case 73:
case 74:
case 75:
case 76:
case 77:
case 78:
case 79:
case 80:
case 81:
case 82:
case 83:
case 84:
case 85:
case 86:
case 87:
case 88:
case 89:
case 90:
case 91:
case 92:
case 93:
case 94:
case 95:
case 96:
case 97:
case 98:
case 99:
case 100:
case 101:
case 102:
case 103:
case 104:
case 105:
case 106:
case 107:
case 108:
case 109:
case 110:
case 111:
case 112:
case 113:
case 114:
case 115:
case 116:
case 117:
case 118:
case 119:
case 120:
case 121:
case 122:
case 123:
case 124:
case 125:
case 126:
case 127:
case 128:
case 129:
case 130:
case 131:
case 132:
case 133:
case 134:
case 135:
case 136:
case 137:
case 138:
case 139:
case 140:
case 141:
case 142:
case 143:
case 144:
case 145:
case 146:
case 147:
case 148:
case 149:
case 150:
case 151:
case 152:
case 153:
case 154:
case 155:
case 156:
case 157:
case 158:
case 159:
case 160:
case 161:
case 162:
case 163:
case 164:
case 165:
case 166:
case 167:
case 168:
case 169:
case 170:
case 171:
case 172:
case 173:
case 174:
case 175:
case 176:
case 177:
case 178:
case 179:
case 180:
case 181:
case 182:
case 183:
case 184:
case 185:
case 186:
case 187:
case 188:
case 189:
case 190:
case 191:
case 192:
case 193:
case 194:
case 195:
case 196:
case 197:
case 198:
case 199:
case 200:
case 201:
case 202:
case 203:
case 204:
case 205:
case 206:
case 207:
case 208:
case 209:
case 210:
case 211:
case 212:
case 213:
case 214:
case 215:
case 216:
case 217:
case 218:
case 219:
case 220:
case 221:
case 222:
case 223:
case 224:
case 225:
case 226:
case 227:
case 228:
case 229:
case 230:
case 231:
case 232:
case 233:
case 234:
case 235:
case 236:
case 237:
case 238:
case 239:
case 240:
case 241:
case 242:
case 243:
case 244:
case 245:
case 246:
case 247:
case 248:
case 249:
case 250:
case 251:
case 252:
case 253:
case 254:
case 255:
break;
default:
return false;
}
final int x = (int) location.x;
final int z = (int) location.z;
final short id = (short) block.getId();
switch (id) {
case 63:
// Fix for signs
return queue.setBlock(x, y, z, id, (byte) block.getData(), block.hasNbtData() && !MainUtil.isValidSign(block.getNbtData()) ? null : block.getNbtData());
case 65:
case 68:
case 54:
case 146:
case 61:
{
// Fix for default block rotation
byte data = (byte) block.getData();
if (data == 0) {
data = 2;
}
}
return queue.setBlock(x, y, z, id, data, block.getNbtData());
case 130:
case 142:
case 27:
@ -161,23 +416,73 @@ public class FastWorldEditExtent extends AbstractDelegateExtent {
case 29:
case 33:
case 151:
case 178: {
if (block.hasNbtData()) {
CompoundTag nbt = block.getNbtData();
MainUtil.setPosition(nbt, x, y, z);
queue.setTile(x, y, z, nbt);
}
queue.setBlock(x, y, z, id, data);
return true;
}
case 65: {
if (data == 0) {
data = 2;
}
}
case 178:
// Tile
return queue.setBlock(x, y, z, id, (byte) block.getData(), block.getNbtData());
case 0:
case 2:
case 4:
case 13:
case 14:
case 15:
case 20:
case 21:
case 22:
case 30:
case 32:
case 37:
case 39:
case 40:
case 41:
case 42:
case 45:
case 46:
case 47:
case 48:
case 49:
case 51:
case 56:
case 57:
case 58:
case 60:
case 7:
case 11:
case 73:
case 74:
case 79:
case 80:
case 81:
case 82:
case 83:
case 85:
case 87:
case 88:
case 101:
case 102:
case 103:
case 110:
case 112:
case 113:
case 121:
case 122:
case 129:
case 133:
case 165:
case 166:
case 169:
case 170:
case 172:
case 173:
case 174:
case 188:
case 189:
case 190:
case 191:
case 192:
// No data
return queue.setBlock(x, y, z, id);
default: {
queue.setBlock(x, y, z, id, data);
return true;
return queue.setBlock(x, y, z, id, (byte) block.getData());
}
}
}

View File

@ -93,7 +93,7 @@ public class DelegateFaweQueue extends FaweQueue {
}
@Override
public boolean setBlock(int x, int y, int z, short id, byte data) {
public boolean setBlock(int x, int y, int z, int id, int data) {
return parent.setBlock(x, y, z, id, data);
}

View File

@ -127,7 +127,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -1028,20 +1027,14 @@ public class EditSession implements Extent {
queue.enqueue();
} else {
queue.dequeue();
return;
}
if (getChangeSet() != null) {
if (Settings.HISTORY.COMBINE_STAGES && queue.size() > 0) {
if (Fawe.get().isMainThread()) {
SetQueue.IMP.flush(queue);
} else {
final AtomicBoolean running = new AtomicBoolean(true);
queue.addNotifyTask(new Runnable() {
@Override
public void run() {
TaskManager.IMP.notify(running);
}
});
TaskManager.IMP.wait(running, Settings.QUEUE.DISCARD_AFTER_MS);
queue.flush();
}
}
((FaweChangeSet) getChangeSet()).flush();

View File

@ -288,7 +288,6 @@ public class BrushCommands {
public void command(Player player, LocalSession session, EditSession editSession, @Optional("5") double radius, CommandContext args) throws WorldEditException {
BrushTool tool = session.getBrushTool(player.getItemInHand());
String cmd = args.getJoinedStrings(1);
System.out.println(cmd);
tool.setBrush(new CommandBrush(player, cmd, radius), "worldedit.brush.copy");
BBC.BRUSH_COMMAND.send(player, cmd);
}

View File

@ -0,0 +1,146 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.math.transform.CombinedTransform;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.registry.WorldData;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Helper class to 'bake' a transform into a clipboard.
*
* <p>This class needs a better name and may need to be made more generic.</p>
*
* @see Clipboard
* @see Transform
*/
public class FlattenedClipboardTransform {
private final Clipboard original;
private final Transform transform;
private final WorldData worldData;
/**
* Create a new instance.
*
* @param original the original clipboard
* @param transform the transform
* @param worldData the world data instance
*/
private FlattenedClipboardTransform(Clipboard original, Transform transform, WorldData worldData) {
checkNotNull(original);
checkNotNull(transform);
checkNotNull(worldData);
this.original = original;
this.transform = transform;
this.worldData = worldData;
}
/**
* Get the transformed region.
*
* @return the transformed region
*/
public Region getTransformedRegion() {
Region region = original.getRegion();
Vector minimum = region.getMinimumPoint();
Vector maximum = region.getMaximumPoint();
Transform transformAround =
new CombinedTransform(
new AffineTransform().translate(original.getOrigin().multiply(-1)),
transform,
new AffineTransform().translate(original.getOrigin()));
Vector[] corners = new Vector[] {
minimum,
maximum,
minimum.setX(maximum.getX()),
minimum.setY(maximum.getY()),
minimum.setZ(maximum.getZ()),
maximum.setX(minimum.getX()),
maximum.setY(minimum.getY()),
maximum.setZ(minimum.getZ()) };
for (int i = 0; i < corners.length; i++) {
corners[i] = transformAround.apply(corners[i]);
}
Vector newMinimum = corners[0];
Vector newMaximum = corners[0];
for (int i = 1; i < corners.length; i++) {
newMinimum = Vector.getMinimum(newMinimum, corners[i]);
newMaximum = Vector.getMaximum(newMaximum, corners[i]);
}
// After transformation, the points may not really sit on a block,
// so we should expand the region for edge cases
newMinimum = newMinimum.setX(Math.floor(newMinimum.getX()));
newMinimum = newMinimum.setY(Math.floor(newMinimum.getY()));
newMinimum = newMinimum.setZ(Math.floor(newMinimum.getZ()));
newMaximum = newMaximum.setX(Math.ceil(newMaximum.getX()));
newMaximum = newMaximum.setY(Math.ceil(newMaximum.getY()));
newMaximum = newMaximum.setZ(Math.ceil(newMaximum.getZ()));
return new CuboidRegion(newMinimum, newMaximum);
}
/**
* Create an operation to copy from the original clipboard to the given extent.
*
* @param target the target
* @return the operation
*/
public Operation copyTo(Extent target) {
BlockTransformExtent extent = new BlockTransformExtent(original, transform, worldData.getBlockRegistry());
ForwardExtentCopy copy = new ForwardExtentCopy(extent, original.getRegion(), original.getOrigin(), target, original.getOrigin());
copy.setTransform(transform);
return copy;
}
/**
* Create a new instance to bake the transform with.
*
* @param original the original clipboard
* @param transform the transform
* @param worldData the world data instance
* @return a builder
*/
public static FlattenedClipboardTransform transform(Clipboard original, Transform transform, WorldData worldData) {
return new FlattenedClipboardTransform(original, transform, worldData);
}
public static Class<?> inject() {
return FlattenedClipboardTransform.class;
}
}

View File

@ -129,13 +129,9 @@ public class SchematicWriter implements ClipboardWriter {
throw new IllegalArgumentException("Length of region too large for a .schematic");
}
System.out.println(clipboard.getMinimumPoint());
System.out.println(clipboard.getMaximumPoint());
// ====================================================================
// Metadata
// ====================================================================
HashMap<String, Tag> schematic = new HashMap<String, Tag>();
schematic.put("Width", new ShortTag((short) width));
schematic.put("Length", new ShortTag((short) length));

View File

@ -34,7 +34,7 @@ public class ForgeChunk_All extends CharFaweChunk<Chunk> {
}
@Override
public void setBlock(int x, int y, int z, int id, byte data) {
public void setBlock(int x, int y, int z, int id, int data) {
int i = FaweCache.CACHE_I[y][x][z];
int j = FaweCache.CACHE_J[y][x][z];
byte[] vs = this.byteIds[i];