fix pom
combine stages
work on efficient handling tiles / entities in changeset
other minor restructuring
(Currently only stable for bukkit 1.8 with
Settings.COMBINE_HISTORY_STAGE=true)
This commit is contained in:
Jesse Boyd 2016-05-06 08:59:21 +10:00
parent 71da20c6c4
commit 1d5765e8cc
45 changed files with 1673 additions and 1257 deletions

View File

@ -12,6 +12,7 @@ dependencies {
compile 'com.palmergames.bukkit:towny:0.84.0.9'
compile 'com.worldcretornica:plotme_core:0.16.3'
compile 'junit:junit:4.11'
compile 'com.sk89q.worldedit:worldedit-bukkit:6.1.1-SNAPSHOT'
}
processResources {

View File

@ -5,7 +5,7 @@ import com.boydti.fawe.util.FaweQueue;
import com.sk89q.worldedit.EditSession;
import org.bukkit.plugin.java.JavaPlugin;
public abstract class BukkitMain extends JavaPlugin {
public abstract class ABukkitMain extends JavaPlugin {
@Override
public void onEnable() {

View File

@ -43,7 +43,7 @@ import org.bukkit.plugin.Plugin;
public class FaweBukkit implements IFawe, Listener {
private final BukkitMain plugin;
private final ABukkitMain plugin;
private VaultUtil vault;
private WorldEditPlugin worldedit;
@ -58,7 +58,7 @@ public class FaweBukkit implements IFawe, Listener {
return this.worldedit;
}
public FaweBukkit(BukkitMain plugin) {
public FaweBukkit(ABukkitMain plugin) {
this.plugin = plugin;
try {
Bukkit.getPluginManager().registerEvents(this, plugin);
@ -203,7 +203,7 @@ public class FaweBukkit implements IFawe, Listener {
return new BukkitQueue_All(world);
}
public BukkitMain getPlugin() {
public ABukkitMain getPlugin() {
return plugin;
}

View File

@ -2,8 +2,7 @@ package com.boydti.fawe.bukkit.logging;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.history.change.Change;
import java.util.Iterator;
import org.PrimeSoft.blocksHub.IBlocksHubApi;
@ -11,7 +10,7 @@ import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
public class LoggingChangeSet implements FaweChangeSet {
public class LoggingChangeSet extends FaweChangeSet {
private final FaweChangeSet parent;
private final IBlocksHubApi api;
@ -32,29 +31,6 @@ public class LoggingChangeSet implements FaweChangeSet {
return parent.flush();
}
@Override
public int getCompressedSize() {
return parent.getCompressedSize();
}
@Override
public void add(Vector location, BaseBlock from, BaseBlock to) {
loc.setX(location.getX());
loc.setY(location.getY());
loc.setZ(location.getZ());
api.logBlock(name, world, loc, from.getId(), (byte) from.getData(), to.getId(), (byte) to.getData());
parent.add(location, from, to);
}
@Override
public void add(int x, int y, int z, int combinedId4DataFrom, BaseBlock to) {
loc.setX(x);
loc.setY(y);
loc.setZ(z);
api.logBlock(name, world, loc, combinedId4DataFrom >> 4, (byte) (combinedId4DataFrom & 0xF), to.getId(), (byte) to.getData());
parent.add(x, y, z, combinedId4DataFrom, to);
}
@Override
public void add(int x, int y, int z, int combinedId4DataFrom, int combinedId4DataTo) {
loc.setX(x);
@ -65,18 +41,28 @@ public class LoggingChangeSet implements FaweChangeSet {
}
@Override
public void add(Change change) {
parent.add(change);
public void addTileCreate(CompoundTag tag) {
parent.addTileCreate(tag);
}
@Override
public Iterator<Change> backwardIterator() {
return parent.backwardIterator();
public void addTileRemove(CompoundTag tag) {
parent.addTileRemove(tag);
}
@Override
public Iterator<Change> forwardIterator() {
return parent.forwardIterator();
public void addEntityRemove(CompoundTag tag) {
parent.addEntityRemove(tag);
}
@Override
public void addEntityCreate(CompoundTag tag) {
parent.addEntityCreate(tag);
}
@Override
public Iterator<Change> getIterator(boolean undo) {
return parent.getIterator(undo);
}
@Override

View File

@ -4,9 +4,12 @@ import com.boydti.fawe.FaweCache;
import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.RunnableVal;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.bukkit.BukkitUtil;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@ -18,8 +21,32 @@ import org.bukkit.block.Block;
public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMappedFaweQueue<World, CHUNK, CHUNKSECTIONS, SECTION> {
public final BukkitImplAdapter adapter;
public Method methodToNative;
public Method methodFromNative;
public BukkitQueue_0(final String world) {
super(world);
try {
WorldEditPlugin instance = (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit");
Field fieldAdapter = WorldEditPlugin.class.getDeclaredField("bukkitAdapter");
fieldAdapter.setAccessible(true);
this.adapter = (BukkitImplAdapter) fieldAdapter.get(instance);
for (Method method : adapter.getClass().getDeclaredMethods()) {
switch (method.getName()) {
case "toNative":
methodToNative = method;
methodToNative.setAccessible(true);
break;
case "fromNative":
methodFromNative = method;
methodFromNative.setAccessible(true);
break;
}
}
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@Override
@ -85,8 +112,11 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
}
@Override
public boolean setComponents(FaweChunk fc) {
public boolean setComponents(FaweChunk fc, RunnableVal<FaweChunk> changeTask) {
try {
// TODO track stage
// TODO set task
final CharFaweChunk<Chunk> fs = ((CharFaweChunk<Chunk>) fc);
final Chunk chunk = fs.getChunk();
chunk.load(true);

View File

@ -24,15 +24,15 @@ public class ChunkListener implements Listener {
}, 1);
}
private int physicsLimit = Settings.PHYSICS_PER_TICK;
private int itemLimit = Settings.ITEMS_PER_TICK;
private int physicsLimit = Integer.MAX_VALUE;
private int itemLimit = Integer.MAX_VALUE;
public static boolean physicsFreeze = false;
@EventHandler(priority = EventPriority.LOWEST)
public void onPhysics(BlockPhysicsEvent event) {
if (physicsFreeze) {
event.setCancelled(true);
} else if (--physicsLimit < 0) {
} else if (physicsLimit-- < 0) {
physicsFreeze = true;
}
}
@ -41,7 +41,7 @@ public class ChunkListener implements Listener {
public void onItemSpawn(ItemSpawnEvent event) {
if (physicsFreeze) {
event.setCancelled(true);
} else if (--itemLimit < 0) {
} else if (itemLimit-- < 0) {
physicsFreeze = true;
}
}

View File

@ -1,43 +0,0 @@
name: FastAsyncWorldEdit
main: com.boydti.fawe.bukkit.FaweBukkit
version: 3.4.3
description: Fast Async WorldEdit plugin
authors: [Empire92]
loadbefore: [WorldEdit]
load: STARTUP
database: false
#softdepend: [WorldGuard, PlotSquared, MCore, Factions, GriefPrevention, Residence, Towny, PlotMe, PreciousStones]
commands:
wea:
description: (FAWE) Bypass WorldEdit processing and area restrictions
aliases: [weanywhere,worldeditanywhere,/wea,/weanywhere,/worldeditanywhere]
usage: "Vault is required for the toggle. Optionally, you can set the permission fawe.bypass"
fixlighting:
description: (FAWE) Fix the lighting in your current chunk
aliases: [/fixlighting]
stream:
description: (FAWE) Stream a schematic into the world
aliases: [/stream]
fawe:
description: (FAWE) Reload the plugin
aliases: [/fawe,/fawereload]
wrg:
description: (FAWE) Select your current WorldEdit Region.
aliases: [/wrg,wer,/wer,worldeditregion,/worldeditregion,/region]
frb:
description: (FAWE) Rollback an edit
aliases: [fawerollback,fawerb,/uu,/rb,/frb,/fawerollback,/fawerb]
fcancel:
description: (FAWE) Cancel your edit
aliases: [fawecancel,/fcancel,/cancel,/fawecancel]
permissions:
fawe.bypass:
default: false
fawe.admin:
default: false
fawe.stream:
default: false
fawe.fixlighting:
default: false
fawe.reload:
default: false

View File

@ -1,11 +1,12 @@
package com.boydti.fawe.bukkit.v1_8;
import com.boydti.fawe.bukkit.BukkitMain;
import com.boydti.fawe.bukkit.ABukkitMain;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
import com.boydti.fawe.bukkit.v1_8.BukkitQueue18R3;
import com.boydti.fawe.object.EditSessionWrapper;
import com.sk89q.worldedit.EditSession;
public class BukkitMain_1_8 extends BukkitMain {
public class BukkitMain_18 extends ABukkitMain {
@Override
public BukkitQueue_0 getQueue(String world) {
return new BukkitQueue18R3(world);

View File

@ -5,11 +5,21 @@ import com.boydti.fawe.FaweCache;
import com.boydti.fawe.bukkit.BukkitPlayer;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.object.BytePair;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FaweLocation;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.internal.Constants;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
@ -17,6 +27,10 @@ import java.util.Set;
import net.minecraft.server.v1_8_R3.BlockPosition;
import net.minecraft.server.v1_8_R3.ChunkCoordIntPair;
import net.minecraft.server.v1_8_R3.ChunkSection;
import net.minecraft.server.v1_8_R3.Entity;
import net.minecraft.server.v1_8_R3.EntityTypes;
import net.minecraft.server.v1_8_R3.NBTTagCompound;
import net.minecraft.server.v1_8_R3.NBTTagInt;
import net.minecraft.server.v1_8_R3.PacketPlayOutMapChunk;
import net.minecraft.server.v1_8_R3.PlayerConnection;
import net.minecraft.server.v1_8_R3.TileEntity;
@ -26,6 +40,7 @@ import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_8_R3.CraftChunk;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.event.entity.CreatureSpawnEvent;
public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]> {
@ -81,7 +96,7 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
}
@Override
public boolean setComponents(FaweChunk fc) {
public boolean setComponents(FaweChunk fc, RunnableVal<FaweChunk> changeTask) {
CharFaweChunk<Chunk> fs = (CharFaweChunk<Chunk>) fc;
CraftChunk chunk = (CraftChunk) fs.getChunk();
net.minecraft.server.v1_8_R3.Chunk nmsChunk = chunk.getHandle();
@ -92,6 +107,55 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
ChunkSection[] sections = nmsChunk.getSections();
Map<BlockPosition, TileEntity> tiles = nmsChunk.getTileEntities();
Collection<net.minecraft.server.v1_8_R3.Entity>[] entities = nmsChunk.getEntitySlices();
// Run change task if applicable
if (changeTask != null) {
CharFaweChunk previous = (CharFaweChunk) getChunk(fc.getX(), fc.getZ());
char[][] idPrevious = new char[16][];
for (int layer = 0; layer < sections.length; layer++) {
if (fs.getCount(layer) != 0) {
ChunkSection section = sections[layer];
if (section != null) {
idPrevious[layer] = section.getIdArray().clone();
}
}
}
previous.ids = idPrevious;
for (Map.Entry<BlockPosition, TileEntity> entry : tiles.entrySet()) {
TileEntity tile = entry.getValue();
NBTTagCompound tag = new NBTTagCompound();
tile.b(tag); // ReadTileIntoTag
BlockPosition pos = entry.getKey();
CompoundTag nativeTag = (CompoundTag) methodToNative.invoke(adapter, tag);
previous.setTile(pos.getX(), pos.getY(), pos.getZ(), nativeTag);
}
for (Collection<Entity> entityList : entities) {
for (Entity ent : entityList) {
int x = ((int) Math.round(ent.locX) & 15);
int z = ((int) Math.round(ent.locZ) & 15);
int y = (int) Math.round(ent.locY);
int i = FaweCache.CACHE_I[y][x][z];
char[] array = fs.getIdArray(i);
if (array == null) {
continue;
}
int j = FaweCache.CACHE_J[y][x][z];
if (array[j] != 0) {
String id = EntityTypes.b(ent);
if (id != null) {
NBTTagCompound tag = new NBTTagCompound();
ent.e(tag);
CompoundTag nativeTag = (CompoundTag) methodToNative.invoke(adapter, tag);
Map<String, Tag> map = ReflectionUtils.getMap(nativeTag.getValue());
map.put("Id", new StringTag(id));
previous.setEntity(nativeTag);
}
}
}
}
changeTask.run(previous);
}
// Trim tiles
Set<Map.Entry<BlockPosition, TileEntity>> entryset = tiles.entrySet();
Iterator<Map.Entry<BlockPosition, TileEntity>> iterator = entryset.iterator();
@ -102,22 +166,41 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
int ly = pos.getY();
int lz = pos.getZ() & 15;
int j = FaweCache.CACHE_I[ly][lx][lz];
int k = FaweCache.CACHE_J[ly][lx][lz];
char[] array = fs.getIdArray(j);
if (array == null) {
continue;
}
int k = FaweCache.CACHE_J[ly][lx][lz];
if (array[k] != 0) {
iterator.remove();
}
}
// Trim entities
// Remove entities
for (int i = 0; i < 16; i++) {
if ((entities[i] != null) && (fs.getCount(i) >= 4096)) {
int count = fs.getCount(i);
if (count == 0) {
continue;
} else if (count >= 4096) {
entities[i].clear();
} else {
char[] array = fs.getIdArray(i);
Collection<Entity> ents = new ArrayList<>(entities[i]);
for (Entity entity : ents) {
int x = ((int) Math.round(entity.locX) & 15);
int z = ((int) Math.round(entity.locZ) & 15);
int y = (int) Math.round(entity.locY);
if (array == null) {
continue;
}
int j = FaweCache.CACHE_J[y][x][z];
if (array[j] != 0) {
nmsWorld.removeEntity(entity);
}
}
}
}
// Efficiently merge sections
// Set blocks
for (int j = 0; j < sections.length; j++) {
if (fs.getCount(j) == 0) {
continue;
@ -142,8 +225,8 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
case 1:
if (currentArray[k] > 1) {
solid++;
currentArray[k] = 0;
}
currentArray[k] = 0;
continue;
default:
solid++;
@ -153,25 +236,75 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
}
setCount(0, solid, section);
}
// // Clear
} catch (Throwable e) {
e.printStackTrace();
}
int[][] biomes = fs.biomes;
if (biomes != null) {
for (int x = 0; x < 16; x++) {
int[] array = biomes[x];
if (array == null) {
continue;
}
for (int z = 0; z < 16; z++) {
int biome = array[z];
if (biome == 0) {
// Set biomes
int[][] biomes = fs.biomes;
if (biomes != null) {
for (int x = 0; x < 16; x++) {
int[] array = biomes[x];
if (array == null) {
continue;
}
nmsChunk.getBiomeIndex()[((z & 0xF) << 4 | x & 0xF)] = (byte) biome;
for (int z = 0; z < 16; z++) {
int biome = array[z];
if (biome == 0) {
continue;
}
nmsChunk.getBiomeIndex()[((z & 0xF) << 4 | x & 0xF)] = (byte) biome;
}
}
}
// Set tiles
Map<BytePair, CompoundTag> tilesToSpawn = fs.getTiles();
BlockPosition.MutableBlockPosition mutablePos = new BlockPosition.MutableBlockPosition(0, 0, 0);
int bx = fs.getX() << 4;
int bz = fs.getZ() << 4;
for (Map.Entry<BytePair, CompoundTag> entry : tilesToSpawn.entrySet()) {
CompoundTag nativeTag = entry.getValue();
BytePair pair = entry.getKey();
mutablePos.c(MathMan.unpair16x(pair.pair[0]) + bx, pair.pair[1] & 0xFF, MathMan.unpair16y(pair.pair[0]) + bz); // Set pos
TileEntity tileEntity = nmsWorld.getTileEntity(mutablePos);
if (tileEntity != null) {
NBTTagCompound tag = (NBTTagCompound) methodFromNative.invoke(adapter, nativeTag);
tag.set("x", new NBTTagInt(mutablePos.getX()));
tag.set("y", new NBTTagInt(mutablePos.getY()));
tag.set("z", new NBTTagInt(mutablePos.getZ()));
tileEntity.a(tag); // ReadTagIntoTile
}
}
// Set entities
Set<CompoundTag> entitiesToSpawn = fs.getEntities();
for (CompoundTag nativeTag : entitiesToSpawn) {
Map<String, Tag> entityTagMap = nativeTag.getValue();
StringTag idTag = (StringTag) entityTagMap.get("Id");
ListTag posTag = (ListTag) entityTagMap.get("Pos");
ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
if (idTag == null || posTag == null || rotTag == null) {
Fawe.debug("Unknown entity tag: " + nativeTag);
continue;
}
double x = posTag.getDouble(0);
double y = posTag.getDouble(1);
double z = posTag.getDouble(2);
float yaw = rotTag.getFloat(0);
float pitch = rotTag.getFloat(1);
String id = idTag.getValue();
Entity entity = EntityTypes.createEntityByName(id, nmsWorld);
if (entity != null) {
if (nativeTag != null) {
NBTTagCompound tag = (NBTTagCompound)methodFromNative.invoke(adapter, nativeTag);
for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
tag.remove(name);
}
entity.f(tag);
}
entity.setLocation(x, y, z, yaw, pitch);
nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
}
}
} catch (Throwable e) {
e.printStackTrace();
}
sendChunk(fc);
return true;

View File

@ -1,5 +1,5 @@
name: FastAsyncWorldEdit
main: com.boydti.fawe.bukkit.v1_8.BukkitMain_1_8
main: com.boydti.fawe.bukkit.v1_8.BukkitMain_18
version: 3.4.3
description: Fast Async WorldEdit plugin
authors: [Empire92]

View File

@ -1,11 +1,12 @@
package com.boydti.fawe.bukkit.v1_9;
import com.boydti.fawe.bukkit.BukkitMain;
import com.boydti.fawe.bukkit.ABukkitMain;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
import com.boydti.fawe.bukkit.v1_9.BukkitQueue_1_9_R1;
import com.boydti.fawe.object.EditSessionWrapper;
import com.sk89q.worldedit.EditSession;
public class BukkitMain_1_9 extends BukkitMain {
public class BukkitMain_19 extends ABukkitMain {
@Override
public BukkitQueue_0 getQueue(String world) {
return new BukkitQueue_1_9_R1(world);

View File

@ -8,6 +8,7 @@ import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.IntegerPair;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.MemUtil;
import com.sk89q.worldedit.LocalSession;
import java.lang.reflect.Constructor;
@ -248,7 +249,12 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
}
@Override
public boolean setComponents(final FaweChunk pc) {
public boolean setComponents(final FaweChunk pc, RunnableVal<FaweChunk> changeTask) {
// TODO change task
{
// blah, stuff
}
final BukkitChunk_1_9 fs = (BukkitChunk_1_9) pc;
final Chunk chunk = (Chunk) fs.getChunk();
final World world = chunk.getWorld();

View File

@ -1,5 +1,5 @@
name: FastAsyncWorldEdit
main: com.boydti.fawe.bukkit.v1_9.BukkitMain_1_9
main: com.boydti.fawe.bukkit.v1_9.BukkitMain_19
version: 3.4.3
description: Fast Async WorldEdit plugin
authors: [Empire92]

View File

@ -11,7 +11,6 @@ import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.regions.general.PlotSquaredFeature;
import com.boydti.fawe.util.Lag;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MemUtil;
import com.boydti.fawe.util.TaskManager;
@ -191,10 +190,6 @@ public class Fawe {
*/
this.setupInjector();
this.setupMemoryListener();
// Lag
final Lag lag = new Lag();
TaskManager.IMP.repeat(lag, 100);
}
private void setupEvents() {
@ -336,28 +331,38 @@ public class Fawe {
if (Settings.MEM_FREE < 1) {
return;
}
final MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
final NotificationEmitter ne = (NotificationEmitter) memBean;
try {
final MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
final NotificationEmitter ne = (NotificationEmitter) memBean;
ne.addNotificationListener(new NotificationListener() {
@Override
public void handleNotification(final Notification notification, final Object handback) {
MemUtil.memoryLimitedTask();
}
}, null, null);
final List<MemoryPoolMXBean> memPools = ManagementFactory.getMemoryPoolMXBeans();
for (final MemoryPoolMXBean mp : memPools) {
if (mp.isUsageThresholdSupported()) {
final MemoryUsage mu = mp.getUsage();
final long max = mu.getMax();
if (max < 0) {
continue;
ne.addNotificationListener(new NotificationListener() {
@Override
public void handleNotification(final Notification notification, final Object handback) {
MemUtil.memoryLimitedTask();
}
final long alert = (max * Settings.MEM_FREE) / 100;
mp.setUsageThreshold(alert);
}, null, null);
final List<MemoryPoolMXBean> memPools = ManagementFactory.getMemoryPoolMXBeans();
for (final MemoryPoolMXBean mp : memPools) {
if (mp.isUsageThresholdSupported()) {
final MemoryUsage mu = mp.getUsage();
final long max = mu.getMax();
if (max < 0) {
continue;
}
final long alert = (max * Settings.MEM_FREE) / 100;
mp.setUsageThreshold(alert);
}
}
} catch (Throwable e) {
debug("====== MEMORY LISTENER ERROR ======");
e.printStackTrace();
debug("===================================");
debug("FAWE needs access to the JVM memory system:");
debug(" - Change your Java security settings");
debug(" - Disable this with `max-memory-percent: -1`");
debug("===================================");
}
}

View File

@ -37,8 +37,10 @@ public class Settings {
public static int UNSAFE_PARALLEL_THREADS = 1;
public static boolean FIX_ALL_LIGHTING = true;
public static boolean ASYNC_LIGHTING = true;
public static int PHYSICS_PER_TICK = 1337;
public static int ITEMS_PER_TICK = 1337;
public static int PHYSICS_PER_TICK = 500000;
public static int ITEMS_PER_TICK = 50000;
public static boolean COMBINE_HISTORY_STAGE = true;
public static HashMap<String, FaweLimit> limits;
@ -103,6 +105,9 @@ public class Settings {
options.put("extent.debug", EXTENT_DEBUG);
options.put("metrics", METRICS);
if (config.getInt("tick-limiter.physics") == 1337) {
config.set("tick-limiter.physics", PHYSICS_PER_TICK);
}
options.put("tick-limiter.physics", PHYSICS_PER_TICK);
options.put("tick-limiter.items", ITEMS_PER_TICK);

View File

@ -1,11 +1,18 @@
package com.boydti.fawe.example;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.BytePair;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public abstract class CharFaweChunk<T> extends FaweChunk<T> {
@ -112,6 +119,50 @@ public abstract class CharFaweChunk<T> extends FaweChunk<T> {
return this.biomes;
}
public HashMap<BytePair, CompoundTag> tiles;
@Override
public void setTile(int x, int y, int z, CompoundTag tile) {
if (tiles == null) {
tiles = new HashMap<>();
}
byte i = MathMan.pair16((byte) x, (byte) z);
byte j = (byte) y;
BytePair pair = new BytePair(i, j);
tiles.put(pair, tile);
}
@Override
public CompoundTag getTile(int x, int y, int z) {
if (tiles == null) {
return null;
}
byte i = MathMan.pair16((byte) x, (byte) z);
byte j = (byte) y;
BytePair pair = new BytePair(i, j);
return tiles.get(pair);
}
@Override
public Map<BytePair, CompoundTag> getTiles() {
return tiles == null ? new HashMap<BytePair, CompoundTag>() : tiles;
}
@Override
public Set<CompoundTag> getEntities() {
return entities == null ? new HashSet<CompoundTag>() : entities;
}
public HashSet<CompoundTag> entities;
@Override
public void setEntity(CompoundTag tag) {
if (entities == null) {
entities = new HashSet<>();
}
entities.add(tag);
}
@Override
public void setBlock(final int x, final int y, final int z, final int id, byte data) {
final int i = FaweCache.CACHE_I[y][x][z];

View File

@ -1,254 +0,0 @@
package com.boydti.fawe.example;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.MainUtil;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.Arrays;
public abstract class IntFaweChunk<T> extends FaweChunk<T> {
private int[][] ids;
private short[] count;
private short[] air;
private short[] relight;
private int[][] biomes;
private T chunk;
/**
* A FaweSections object represents a chunk and the blocks that you wish to change in it.
*
* @param parent
* @param x
* @param z
*/
public IntFaweChunk(FaweQueue parent, int x, int z) {
super(parent, x, z);
this.ids = new int[16][];
this.count = new short[16];
this.air = new short[16];
this.relight = new short[16];
}
@Override
public T getChunk() {
if (this.chunk == null) {
this.chunk = getNewChunk();
}
return this.chunk;
}
public abstract T getNewChunk();
@Override
public void setLoc(final FaweQueue parent, int x, int z) {
super.setLoc(parent, x, z);
this.chunk = null;
}
/**
* Get the number of block changes in a specified section
* @param i
* @return
*/
public int getCount(final int i) {
return this.count[i];
}
public int getAir(final int i) {
return this.air[i];
}
public void setCount(final int i, final short value) {
this.count[i] = value;
}
/**
* Get the number of block changes in a specified section
* @param i
* @return
*/
public int getRelight(final int i) {
return this.relight[i];
}
public int getTotalCount() {
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.count[i];
}
return total;
}
public int getTotalRelight() {
if ((this.getTotalCount() == 0) && (this.biomes == null)) {
Arrays.fill(this.count, (short) 1);
Arrays.fill(this.relight, Short.MAX_VALUE);
return Short.MAX_VALUE;
}
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.relight[i];
}
return total;
}
/**
* Get the raw data for a section
* @param i
* @return
*/
public int[] getIdArray(final int i) {
return this.ids[i];
}
public int[][] getIdArrays() {
return this.ids;
}
public int[][] getBiomeArray() {
return this.biomes;
}
@Override
public void setBlock(final int x, final int y, final int z, final int id, byte data) {
final int i = FaweCache.CACHE_I[y][x][z];
final int j = FaweCache.CACHE_J[y][x][z];
int[] vs = this.ids[i];
if (vs == null) {
vs = this.ids[i] = new int[4096];
this.count[i]++;
} else if (vs[j] == 0) {
this.count[i]++;
}
switch (id) {
case 0:
this.air[i]++;
vs[j] = -1;
return;
case 10:
case 11:
case 39:
case 40:
case 51:
case 74:
case 89:
case 122:
case 124:
case 138:
case 169:
this.relight[i]++;
case 2:
case 4:
case 13:
case 14:
case 15:
case 20:
case 21:
case 22:
case 30:
case 32:
case 37:
case 41:
case 42:
case 45:
case 46:
case 47:
case 48:
case 49:
case 56:
case 57:
case 58:
case 60:
case 7:
case 8:
case 9:
case 73:
case 78:
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 129:
case 133:
case 165:
case 166:
case 170:
case 172:
case 173:
case 174:
case 181:
case 182:
case 188:
case 189:
case 190:
case 191:
case 192:
vs[j] = (id);
return;
case 130:
case 50:
case 76:
case 62:
this.relight[i]++;
case 54:
case 146:
case 61:
case 65:
case 68:
// if (data < 2) {
// data = 2;
// }
default:
vs[j] = id + (data << 12);
return;
}
}
@Override
public void setBiome(final int x, final int z, final BaseBiome biome) {
if (this.biomes == null) {
this.biomes = new int[16][];
}
int[] index = this.biomes[x];
if (index == null) {
index = this.biomes[x] = new int[16];
}
index[z] = biome.getId();
}
@Override
public IntFaweChunk<T> copy(boolean shallow) {
IntFaweChunk<T> copy = (IntFaweChunk<T>) getParent().getChunk(getX(), getZ());
if (shallow) {
copy.ids = ids;
copy.air = air;
copy.biomes = biomes;
copy.chunk = chunk;
copy.count = count;
copy.relight = relight;
} else {
copy.ids = (int[][]) MainUtil.copyNd(ids);
copy.air = air.clone();
copy.biomes = biomes.clone();
copy.chunk = chunk;
copy.count = count.clone();
copy.relight = relight.clone();
}
return copy;
}
}

View File

@ -7,8 +7,11 @@ import com.boydti.fawe.object.IntegerPair;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
@ -23,6 +26,7 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
*/
private ConcurrentHashMap<Long, FaweChunk> blocks = new ConcurrentHashMap<>();
private LinkedBlockingDeque<FaweChunk> chunks = new LinkedBlockingDeque<>();
private ArrayDeque<Runnable> tasks = new ArrayDeque<>();
@Override
public void optimize() {
@ -46,6 +50,11 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
}
}
@Override
public void addNotifyTask(Runnable runnable) {
this.tasks.add(runnable);
}
public MappedFaweQueue(final String world) {
super(world);
}
@ -58,7 +67,7 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
public abstract void sendChunk(FaweChunk chunk);
public abstract boolean setComponents(FaweChunk fc);
public abstract boolean setComponents(FaweChunk fc, RunnableVal<FaweChunk> changeTask);
@Override
public abstract FaweChunk getChunk(int x, int z);
@ -88,12 +97,12 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
}
@Override
public void addTask(int x, int z, Runnable runnable) {
public void addNotifyTask(int x, int z, Runnable runnable) {
long pair = (long) (x) << 32 | (z) & 0xFFFFFFFFL;
FaweChunk result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x, z);
result.addTask(runnable);
result.addNotifyTask(runnable);
FaweChunk previous = this.blocks.put(pair, result);
if (previous == null) {
chunks.add(result);
@ -102,9 +111,11 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
this.blocks.put(pair, previous);
result = previous;
}
result.addTask(runnable);
result.addNotifyTask(runnable);
}
private FaweChunk lastWrappedChunk;
private int lastX = Integer.MIN_VALUE;
private int lastZ = Integer.MIN_VALUE;
@ -137,6 +148,60 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
return true;
}
@Override
public void setTile(int x, int y, int z, CompoundTag tag) {
if ((y > 255) || (y < 0)) {
return;
}
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.getChunk(x >> 4, z >> 4);
lastWrappedChunk.setTile(x & 15, y, z & 15, tag);
FaweChunk previous = this.blocks.put(pair, lastWrappedChunk);
if (previous == null) {
chunks.add(lastWrappedChunk);
return;
}
this.blocks.put(pair, previous);
lastWrappedChunk = previous;
}
}
lastWrappedChunk.setTile(x & 15, y, z & 15, tag);
}
@Override
public void setEntity(int x, int y, int z, CompoundTag tag) {
if ((y > 255) || (y < 0)) {
return;
}
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.getChunk(x >> 4, z >> 4);
lastWrappedChunk.setEntity(tag);
FaweChunk previous = this.blocks.put(pair, lastWrappedChunk);
if (previous == null) {
chunks.add(lastWrappedChunk);
return;
}
this.blocks.put(pair, previous);
lastWrappedChunk = previous;
}
}
lastWrappedChunk.setEntity(tag);
}
@Override
public boolean setBiome(int x, int z, BaseBiome biome) {
long pair = (long) (x >> 4) << 32 | (z >> 4) & 0xFFFFFFFFL;
@ -177,22 +242,41 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
return null;
}
public void runTasks() {
for (Runnable run : tasks) {
run.run();
}
tasks.clear();
}
@Override
public int size() {
if (chunks.size() == 0 && SetQueue.IMP.isStage(this, SetQueue.QueueStage.ACTIVE)) {
runTasks();
}
return chunks.size();
}
private LinkedBlockingDeque<FaweChunk> toUpdate = new LinkedBlockingDeque<>();
public boolean execute(FaweChunk fc) {
public boolean execute(final FaweChunk fc) {
if (fc == null) {
return false;
}
// Set blocks / entities / biome
if (!this.setComponents(fc)) {
if (getChangeTask() != null) {
if (!this.setComponents(fc, new RunnableVal<FaweChunk>() {
@Override
public void run(FaweChunk before) {
getChangeTask().run(before, fc);
}
})) {
return false;
}
} else if (!this.setComponents(fc, null)) {
return false;
}
fc.executeTasks();
fc.executeNotifyTasks();
return true;
}

View File

@ -31,9 +31,6 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
public abstract void refreshChunk(WORLD world, CHUNK chunk);
@Override
public abstract boolean setComponents(FaweChunk fc);
@Override
public abstract boolean fixLighting(FaweChunk fc, boolean fixAll);
}

View File

@ -0,0 +1,33 @@
package com.boydti.fawe.object;
public class BytePair {
public byte[] pair;
public BytePair(final byte x, final byte z) {
this.pair = new byte[] { x, z};
}
int hash;
@Override
public int hashCode() {
return pair[0] + (pair[1] << 8);
}
@Override
public String toString() {
return pair[0] + "," + pair[1];
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if ((obj == null) || (this.hashCode() != obj.hashCode()) || (this.getClass() != obj.getClass())) {
return false;
}
final BytePair other = (BytePair) obj;
return pair[0] == other.pair[0] && pair[1] == other.pair[1];
}
}

View File

@ -2,8 +2,11 @@ package com.boydti.fawe.object;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.util.FaweQueue;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.ArrayDeque;
import java.util.Map;
import java.util.Set;
public abstract class FaweChunk<T> {
@ -56,6 +59,8 @@ public abstract class FaweChunk<T> {
parent.fixLighting(this, Settings.FIX_ALL_LIGHTING);
}
public abstract char[][] getIdArrays();
/**
* Fill this chunk with a block
* @param id
@ -86,13 +91,17 @@ public abstract class FaweChunk<T> {
}
}
public void addTask(Runnable run) {
public void addNotifyTask(Runnable run) {
if (run != null) {
tasks.add(run);
}
}
public void executeTasks() {
public boolean hasNotifyTasks() {
return tasks.size() > 0;
}
public void executeNotifyTasks() {
for (Runnable task : tasks) {
task.run();
}
@ -101,8 +110,18 @@ public abstract class FaweChunk<T> {
public abstract T getChunk();
public abstract void setTile(int x, int y, int z, CompoundTag tile);
public abstract void setEntity(CompoundTag entity);
public abstract void setBlock(final int x, final int y, final int z, final int id, final byte data);
public abstract CompoundTag getTile(int x, int y, int z);
public abstract Set<CompoundTag> getEntities();
public abstract Map<BytePair, CompoundTag> getTiles();
public abstract void setBiome(final int x, final int z, final BaseBiome biome);
public void optimize() {}

View File

@ -5,6 +5,7 @@ import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.changeset.DiskStorageHistory;
import com.boydti.fawe.object.changeset.FaweStreamChangeSet;
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.WEManager;
@ -169,7 +170,7 @@ public abstract class FawePlayer<T> {
Collections.sort(editIds);
for (int i = editIds.size() - 1; i >= 0; i--) {
int index = editIds.get(i);
DiskStorageHistory set = new DiskStorageHistory(world, uuid, index);
FaweStreamChangeSet set = new DiskStorageHistory(world, uuid, index);
EditSession edit = set.toEditSession(getPlayer());
if (world.equals(getWorld())) {
session.remember(edit, false);

View File

@ -41,9 +41,9 @@ public class HistoryExtent extends AbstractDelegateExtent {
*/
public HistoryExtent(final EditSession session, FaweLimit limit, final Extent extent, final FaweChangeSet changeSet, FaweQueue queue) {
super(extent);
checkNotNull(changeSet);
this.limit = limit;
this.queue = queue;
checkNotNull(changeSet);
this.changeSet = changeSet;
this.session = session;
}

View File

@ -1,48 +1,49 @@
package com.boydti.fawe.object;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.history.change.Change;
import java.util.ArrayList;
import java.util.Iterator;
public class NullChangeSet implements FaweChangeSet {
@Override
public void add(Change change) {}
@Override
public Iterator<Change> backwardIterator() {
return new ArrayList<Change>().iterator();
}
@Override
public Iterator<Change> forwardIterator() {
return new ArrayList<Change>().iterator();
}
@Override
public int size() {
return 0;
}
public class NullChangeSet extends FaweChangeSet {
@Override
public boolean flush() {
return false;
}
@Override
public int getCompressedSize() {
return 0;
public void add(int x, int y, int z, int combinedFrom, int combinedTo) {
}
@Override
public void add(Vector location, BaseBlock from, BaseBlock to) {}
public void addTileCreate(CompoundTag tag) {
}
@Override
public void add(int x, int y, int z, int combinedId4DataFrom, BaseBlock to) {}
public void addTileRemove(CompoundTag tag) {
}
@Override
public void add(int x, int y, int z, int combinedId4DataFrom, int combinedId4DataTo) {}
public void addEntityRemove(CompoundTag tag) {
}
@Override
public void addEntityCreate(CompoundTag tag) {
}
@Override
public Iterator<Change> getIterator(boolean undo) {
return new ArrayList<Change>().iterator();
}
@Override
public int size() {
return 0;
}
}

View File

@ -0,0 +1,46 @@
package com.boydti.fawe.object.change;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.extent.FastWorldEditExtent;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.history.UndoContext;
import com.sk89q.worldedit.history.change.Change;
public class MutableBlockChange implements Change {
public int z;
public int y;
public int x;
public short id;
public byte data;
public MutableBlockChange(int x, int y, int z, short id, byte data) {
this.x = x;
this.y = y;
this.z = z;
this.id = id;
this.data = data;
}
@Override
public void undo(UndoContext context) throws WorldEditException {
create(context);
}
@Override
public void redo(UndoContext context) throws WorldEditException {
create(context);
}
public void create(UndoContext context) {
Extent extent = context.getExtent();
if (extent.getClass() == FastWorldEditExtent.class) {
FastWorldEditExtent fwee = (FastWorldEditExtent) extent;
fwee.getQueue().setBlock(x, y, z, id, data);
} else {
Fawe.debug("FAWE doesn't support: " + extent + " for " + getClass() + " (bug Empire92)");
}
}
}

View File

@ -0,0 +1,53 @@
package com.boydti.fawe.object.change;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.extent.FastWorldEditExtent;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.DoubleTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.history.UndoContext;
import com.sk89q.worldedit.history.change.Change;
import java.util.List;
import java.util.Map;
public class MutableEntityChange implements Change {
public CompoundTag tag;
public boolean create;
public MutableEntityChange(CompoundTag tag, boolean create) {
this.tag = tag;
this.create = create;
}
@Override
public void undo(UndoContext context) throws WorldEditException {
if (!create) {
create(context);
}
}
@Override
public void redo(UndoContext context) throws WorldEditException {
if (create) {
create(context);
}
}
public void create(UndoContext context) {
Extent extent = context.getExtent();
if (extent.getClass() == FastWorldEditExtent.class) {
FastWorldEditExtent fwee = (FastWorldEditExtent) extent;
Map<String, Tag> map = tag.getValue();
List<DoubleTag> pos = (List<DoubleTag>) map.get("Pos").getValue();
int x = (int) Math.round(pos.get(0).getValue());
int y = (int) Math.round(pos.get(1).getValue());
int z = (int) Math.round(pos.get(2).getValue());
fwee.getQueue().setEntity(x, y, z, tag);
} else {
Fawe.debug("FAWE doesn't support: " + context + " for " + getClass() + " (bug Empire92)");
}
}
}

View File

@ -0,0 +1,51 @@
package com.boydti.fawe.object.change;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.extent.FastWorldEditExtent;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.history.UndoContext;
import com.sk89q.worldedit.history.change.Change;
import java.util.Map;
public class MutableTileChange implements Change {
public CompoundTag tag;
public boolean create;
public MutableTileChange(CompoundTag tag, boolean create) {
this.tag = tag;
this.create = create;
}
@Override
public void undo(UndoContext context) throws WorldEditException {
if (!create) {
create(context);
}
}
@Override
public void redo(UndoContext context) throws WorldEditException {
if (create) {
create(context);
}
}
public void create(UndoContext context) {
Extent extent = context.getExtent();
if (extent.getClass() == FastWorldEditExtent.class) {
FastWorldEditExtent fwee = (FastWorldEditExtent) extent;
Map<String, Tag> map = tag.getValue();
int x = ((IntTag) map.get("x")).getValue();
int y = ((IntTag) map.get("y")).getValue();
int z = ((IntTag) map.get("z")).getValue();
fwee.getQueue().setTile(x, y, z, tag);
} else {
Fawe.debug("FAWE doesn't support: " + context + " for " + getClass());
}
}
}

View File

@ -1,30 +1,11 @@
package com.boydti.fawe.object.changeset;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.IntegerPair;
import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.EditSessionFactory;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.history.change.BlockChange;
import com.sk89q.worldedit.history.change.Change;
import com.sk89q.worldedit.history.change.EntityCreate;
import com.sk89q.worldedit.history.change.EntityRemove;
import com.sk89q.worldedit.history.changeset.ChangeSet;
import com.sk89q.worldedit.world.World;
import java.io.File;
import java.io.FileInputStream;
@ -32,18 +13,14 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4InputStream;
import net.jpountz.lz4.LZ4OutputStream;
/**
* Store the change on disk
@ -52,7 +29,7 @@ import net.jpountz.lz4.LZ4OutputStream;
* - Minimal memory usage
* - Slow
*/
public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
public class DiskStorageHistory extends FaweStreamChangeSet {
private UUID uuid;
private File bdFile;
@ -60,7 +37,12 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
private File nbttFile;
private File entfFile;
private File enttFile;
/**
* Summary of this change (not accurate for larger edits)
*/
private DiskStorageSummary summary;
/*
* Block data
*
@ -80,22 +62,15 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
// NBT To
private NBTOutputStream osNBTT;
private GZIPOutputStream osNBTTG;
private AtomicInteger osNBTTI;
// Entity From
private NBTOutputStream osENTF;
private GZIPOutputStream osENTFG;
private AtomicInteger osENTFI;
// Entity To
private NBTOutputStream osENTT;
private GZIPOutputStream osENTTG;
private AtomicInteger osENTTI;
private int ox;
private int oz;
// Entity Create From
private NBTOutputStream osENTCF;
private GZIPOutputStream osENTCFG;
// Entity Create To
private NBTOutputStream osENTCT;
private GZIPOutputStream osENTCTG;
private int size;
private World world;
public void deleteFiles() {
@ -148,23 +123,6 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
return bdFile;
}
public EditSession toEditSession(Player player) {
EditSessionFactory factory = WorldEdit.getInstance().getEditSessionFactory();
EditSession edit = factory.getEditSession(world, -1, null, player);
edit.setChangeSet(this);
edit.dequeue();
return edit;
}
@Override
public void add(Change change) {
if ((change instanceof BlockChange)) {
add((BlockChange) change);
} else {
Fawe.debug("Does not support " + change + " yet! (Please bug Empire92)");
}
}
@Override
public boolean flush() {
boolean flushed = false;
@ -201,123 +159,63 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
}
@Override
public void add(int x, int y, int z, int combinedFrom, int combinedTo) {
size++;
try {
OutputStream stream = getBAOS(x, y, z);
//x
x-=ox;
stream.write((x) & 0xff);
stream.write(((x) >> 8) & 0xff);
//z
z-=oz;
stream.write((z) & 0xff);
stream.write(((z) >> 8) & 0xff);
//y
stream.write((byte) y);
//from
stream.write((combinedFrom) & 0xff);
stream.write(((combinedFrom) >> 8) & 0xff);
//to
stream.write((combinedTo) & 0xff);
stream.write(((combinedTo) >> 8) & 0xff);
}
catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void add(int x, int y, int z, int combinedId4DataFrom, BaseBlock to) {
int idTo = to.getId();
int combinedTo = (FaweCache.hasData(idTo) ? ((idTo << 4) + to.getData()) : (idTo << 4));
CompoundTag nbtTo = FaweCache.hasNBT(idTo) ? to.getNbtData() : null;
add(x, y, z, combinedId4DataFrom, combinedTo);
if (nbtTo != null && MainUtil.isValidTag(nbtTo)) {
try {
Map<String, Tag> value = ReflectionUtils.getMap(nbtTo.getValue());
value.put("x", new IntTag(x));
value.put("y", new IntTag(y));
value.put("z", new IntTag(z));
NBTOutputStream nbtos = getNBTTOS(x, y, z);
nbtos.writeNamedTag(osNBTTI.getAndIncrement() + "", nbtTo);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void add(Vector loc, BaseBlock from, BaseBlock to) {
int x = loc.getBlockX();
int y = loc.getBlockY();
int z = loc.getBlockZ();
try {
int idfrom = from.getId();
int combinedFrom = (FaweCache.hasData(idfrom) ? ((idfrom << 4) + from.getData()) : (idfrom << 4));
CompoundTag nbtFrom = FaweCache.hasNBT(idfrom) ? from.getNbtData() : null;
if (nbtFrom != null && MainUtil.isValidTag(nbtFrom)) {
Map<String, Tag> value = ReflectionUtils.getMap(nbtFrom.getValue());
value.put("x", new IntTag(x));
value.put("y", new IntTag(y));
value.put("z", new IntTag(z));
NBTOutputStream nbtos = getNBTFOS(x, y, z);
nbtos.writeNamedTag(osNBTFI.getAndIncrement() + "", nbtFrom);
}
add(x, y, z, combinedFrom, to);
} catch (Exception e) {
e.printStackTrace();
}
}
public void add(EntityCreate change) {
// TODO
}
public void add(EntityRemove change) {
// TODO
}
public void add(BlockChange change) {
try {
BlockVector loc = change.getPosition();
BaseBlock from = change.getPrevious();
BaseBlock to = change.getCurrent();
add(loc, from, to);
} catch (Exception e) {
e.printStackTrace();
}
}
private OutputStream getBAOS(int x, int y, int z) throws IOException {
public OutputStream getBlockOS(int x, int y, int z) throws IOException {
if (osBD != null) {
return osBD;
}
bdFile.getParentFile().mkdirs();
bdFile.createNewFile();
FileOutputStream stream = new FileOutputStream(bdFile);
LZ4Factory factory = LZ4Factory.fastestInstance();
LZ4Compressor compressor = factory.fastCompressor();
osBD = new LZ4OutputStream(stream, Settings.BUFFER_SIZE, factory.fastCompressor());
if (Settings.COMPRESSION_LEVEL > 0) {
osBD = new LZ4OutputStream(osBD, Settings.BUFFER_SIZE, factory.highCompressor());
}
ox = x;
oz = z;
osBD.write((byte) (ox >> 24));
osBD.write((byte) (ox >> 16));
osBD.write((byte) (ox >> 8));
osBD.write((byte) (ox));
osBD.write((byte) (oz >> 24));
osBD.write((byte) (oz >> 16));
osBD.write((byte) (oz >> 8));
osBD.write((byte) (oz));
osBD = getCompressedOS(new FileOutputStream(bdFile));
setOrigin(x, z);
osBD.write((byte) (x >> 24));
osBD.write((byte) (x >> 16));
osBD.write((byte) (x >> 8));
osBD.write((byte) (x));
osBD.write((byte) (z >> 24));
osBD.write((byte) (z >> 16));
osBD.write((byte) (z >> 8));
osBD.write((byte) (z));
return osBD;
}
private NBTOutputStream getNBTFOS(int x, int y, int z) throws IOException {
@Override
public NBTOutputStream getEntityCreateOS() throws IOException {
if (osENTCT != null) {
return osENTCT;
}
enttFile.getParentFile().mkdirs();
enttFile.createNewFile();
osENTCTG = new GZIPOutputStream(new FileOutputStream(enttFile), true);
osENTCT = new NBTOutputStream(osENTCTG);
return osENTCT;
}
@Override
public NBTOutputStream getEntityRemoveOS() throws IOException {
if (osENTCF != null) {
return osENTCF;
}
entfFile.getParentFile().mkdirs();
entfFile.createNewFile();
osENTCFG = new GZIPOutputStream(new FileOutputStream(entfFile), true);
osENTCF = new NBTOutputStream(osENTCFG);
return osENTCF;
}
@Override
public NBTOutputStream getTileCreateOS() throws IOException {
if (osNBTT != null) {
return osNBTT;
}
nbttFile.getParentFile().mkdirs();
nbttFile.createNewFile();
osNBTTG = new GZIPOutputStream(new FileOutputStream(nbttFile), true);
osNBTT = new NBTOutputStream(osNBTTG);
return osNBTT;
}
@Override
public NBTOutputStream getTileRemoveOS() throws IOException {
if (osNBTF != null) {
return osNBTF;
}
@ -328,51 +226,58 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
osNBTFI = new AtomicInteger();
return osNBTF;
}
private NBTOutputStream getNBTTOS(int x, int y, int z) throws IOException {
if (osNBTT != null) {
return osNBTT;
@Override
public InputStream getBlockIS() throws IOException {
if (!bdFile.exists()) {
return null;
}
nbttFile.getParentFile().mkdirs();
nbttFile.createNewFile();
osNBTTG = new GZIPOutputStream(new FileOutputStream(nbttFile), true);
osNBTT = new NBTOutputStream(osNBTTG);
osNBTTI = new AtomicInteger();
return osNBTT;
InputStream is = getCompressedIS(new FileInputStream(bdFile));
int x = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + (is.read() << 0));
int z = ((is.read() << 24) + (is.read() << 16) + (is.read() << 8) + (is.read() << 0));
setOrigin(x, z);
return is;
}
private NBTOutputStream getENTFOS(int x, int y, int z) throws IOException {
if (osNBTF != null) {
return osNBTF;
@Override
public NBTInputStream getEntityCreateIS() throws IOException {
if (!enttFile.exists()) {
return null;
}
entfFile.getParentFile().mkdirs();
entfFile.createNewFile();
osENTFG = new GZIPOutputStream(new FileOutputStream(entfFile), true);
osENTF = new NBTOutputStream(osENTFG);
osENTFI = new AtomicInteger();
return osENTF;
}
private NBTOutputStream getENTTOS(int x, int y, int z) throws IOException {
if (osENTT != null) {
return osENTT;
}
enttFile.getParentFile().mkdirs();
enttFile.createNewFile();
osENTTG = new GZIPOutputStream(new FileOutputStream(enttFile), true);
osENTT = new NBTOutputStream(osENTTG);
osENTTI = new AtomicInteger();
return osENTT;
return new NBTInputStream(getCompressedIS(new FileInputStream(enttFile)));
}
@Override
public NBTInputStream getEntityRemoveIS() throws IOException {
if (!entfFile.exists()) {
return null;
}
return new NBTInputStream(getCompressedIS(new FileInputStream(entfFile)));
}
private DiskStorageSummary summary;
@Override
public NBTInputStream getTileCreateIS() throws IOException {
if (!nbttFile.exists()) {
return null;
}
return new NBTInputStream(getCompressedIS(new FileInputStream(nbttFile)));
}
@Override
public NBTInputStream getTileRemoveIS() throws IOException {
if (!nbtfFile.exists()) {
return null;
}
return new NBTInputStream(getCompressedIS(new FileInputStream(nbtfFile)));
}
public DiskStorageSummary summarize(RegionWrapper requiredRegion, boolean shallow) {
if (summary != null) {
return summary;
}
if (bdFile.exists()) {
int ox = getOriginX();
int oz = getOriginZ();
if ((ox != 0 || oz != 0) && !requiredRegion.isIn(ox, oz)) {
return summary = new DiskStorageSummary(ox, oz);
}
@ -387,6 +292,7 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
}
ox = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
oz = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
setOrigin(ox, oz);
summary = new DiskStorageSummary(ox, oz);
if (!requiredRegion.isIn(ox, oz)) {
fis.close();
@ -415,6 +321,8 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
}
public IntegerPair readHeader() {
int ox = getOriginX();
int oz = getOriginZ();
if (ox == 0 && oz == 0 && bdFile.exists()) {
try {
FileInputStream fis = new FileInputStream(bdFile);
@ -428,6 +336,7 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
}
ox = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
oz = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
setOrigin(ox, oz);
fis.close();
gis.close();
} catch (IOException e) {
@ -437,129 +346,6 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
return new IntegerPair(ox, oz);
}
@SuppressWarnings("resource")
public Iterator<Change> getIterator(final boolean dir) {
flush();
try {
if (bdFile.exists()) {
final NBTInputStream nbtf = nbtfFile.exists() ? new NBTInputStream(new GZIPInputStream(new FileInputStream(nbtfFile))) : null;
final NBTInputStream nbtt = nbttFile.exists() ? new NBTInputStream(new GZIPInputStream(new FileInputStream(nbttFile))) : null;
FileInputStream fis = new FileInputStream(bdFile);
LZ4Factory factory = LZ4Factory.fastestInstance();
LZ4Compressor compressor = factory.fastCompressor();
final InputStream gis;
if (Settings.COMPRESSION_LEVEL > 0) {
gis = new LZ4InputStream(new LZ4InputStream(fis));
} else {
gis = new LZ4InputStream(fis);
}
ox = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
oz = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
return new Iterator<Change>() {
private CompoundTag lastFrom = read(nbtf);
private CompoundTag lastTo = read(nbtt);
private Change last = read();
public CompoundTag read(NBTInputStream stream) {
if (stream != null) {
try {
NamedTag nt = stream.readNamedTag();
return nt != null ? ((CompoundTag) nt.getTag()) : null;
} catch (IOException ignore) {}
}
return null;
}
public Change read() {
try {
int x = ((byte) gis.read() & 0xFF) + ((byte) gis.read() << 8) + ox;
int z = ((byte) gis.read() & 0xFF) + ((byte) gis.read() << 8) + oz;
int y = gis.read() & 0xff;
int from1 = gis.read();
int from2 = gis.read();
BaseBlock from = FaweCache.getBlock(((from2 << 4) + (from1 >> 4)), (from1 & 0xf));
if (lastFrom != null && FaweCache.hasNBT(from.getId())) {
Map<String, Tag> t = lastFrom.getValue();
if (((IntTag) t.get("x")).getValue() == x && ((IntTag) t.get("z")).getValue() == z && ((IntTag) t.get("y")).getValue() == y) {
from = new BaseBlock(from.getId(), from.getData());
from.setNbtData(lastFrom);
lastFrom = read(nbtf);
}
}
int to1 = gis.read();
int to2 = gis.read();
BaseBlock to = FaweCache.getBlock(((to2 << 4) + (to1 >> 4)), (to1 & 0xf));
if (lastTo != null && FaweCache.hasNBT(to.getId())) {
Map<String, Tag> t = lastTo.getValue();
if (((IntTag) t.get("x")).getValue() == x && ((IntTag) t.get("z")).getValue() == z && ((IntTag) t.get("y")).getValue() == y) {
to = new BaseBlock(to.getId(), to.getData());
to.setNbtData(lastTo);
lastTo = read(nbtt);
}
}
BlockVector position = new BlockVector(x, y, z);
return dir ? new BlockChange(position, to, from) : new BlockChange(position, from, to);
} catch (Exception e) {
return null;
}
}
@Override
public boolean hasNext() {
if (last != null) {
return true;
}
try {
gis.close();
if (nbtf != null) {
nbtf.close();
}
if (nbtt != null) {
nbtt.close();
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
@Override
public Change next() {
Change tmp = last;
last = read();
return tmp;
}
@Override
public void remove() {
throw new IllegalArgumentException("CANNOT REMOVE");
}
};
}
} catch (Exception e) {
e.printStackTrace();
}
return new ArrayList<Change>().iterator();
}
@Override
public Iterator<Change> backwardIterator() {
return getIterator(false);
}
@Override
public Iterator<Change> forwardIterator() {
return getIterator(false);
}
@Override
public int size() {
flush();
return size;
}
public static class DiskStorageSummary {
private final int z;

View File

@ -1,17 +1,222 @@
package com.boydti.fawe.object.changeset;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.BytePair;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.MainUtil;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.EditSessionFactory;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.history.change.BlockChange;
import com.sk89q.worldedit.history.change.Change;
import com.sk89q.worldedit.history.change.EntityCreate;
import com.sk89q.worldedit.history.change.EntityRemove;
import com.sk89q.worldedit.history.changeset.ChangeSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public interface FaweChangeSet extends ChangeSet {
boolean flush();
public abstract class FaweChangeSet implements ChangeSet {
public abstract boolean flush();
int getCompressedSize();
public abstract void add(int x, int y, int z, int combinedFrom, int combinedTo);
void add(Vector location, BaseBlock from, BaseBlock to);
@Override
public Iterator<Change> backwardIterator() {
return getIterator(false);
}
void add(int x, int y, int z, int combinedId4DataFrom, BaseBlock to);
@Override
public Iterator<Change> forwardIterator() {
return getIterator(true);
}
void add(int x, int y, int z, int combinedId4DataFrom, int combinedId4DataTo);
public abstract void addTileCreate(CompoundTag tag);
public abstract void addTileRemove(CompoundTag tag);
public abstract void addEntityRemove(CompoundTag tag);
public abstract void addEntityCreate(CompoundTag tag);
public abstract Iterator<Change> getIterator(boolean redo);
public EditSession toEditSession(Player player) {
EditSessionFactory factory = WorldEdit.getInstance().getEditSessionFactory();
EditSession edit = factory.getEditSession(player.getWorld(), -1, null, player);
edit.setChangeSet(this);
edit.dequeue();
return edit;
}
public void add(EntityCreate change) {
CompoundTag tag = change.state.getNbtData();
MainUtil.setEntityInfo(tag, change.entity);
addEntityCreate(tag);
}
public void add(EntityRemove change) {
CompoundTag tag = change.state.getNbtData();
MainUtil.setEntityInfo(tag, change.entity);
addEntityRemove(tag);
}
public void add(Change change) {
if (change.getClass() == BlockChange.class) {
add((BlockChange) change);
} else if (change.getClass() == EntityCreate.class) {
add((EntityCreate) change);
} else if (change.getClass() == EntityRemove.class) {
add((EntityRemove) change);
} else {
Fawe.debug("Unknown change: " + change.getClass());
}
}
public void add(BlockChange change) {
try {
BlockVector loc = change.getPosition();
BaseBlock from = change.getPrevious();
BaseBlock to = change.getCurrent();
add(loc, from, to);
} catch (Exception e) {
e.printStackTrace();
}
}
public void add(Vector loc, BaseBlock from, BaseBlock to) {
int x = loc.getBlockX();
int y = loc.getBlockY();
int z = loc.getBlockZ();
add(x, y, z, from, to);
}
public void add(int x, int y, int z, BaseBlock from, BaseBlock to) {
try {
if (from.hasNbtData()) {
CompoundTag nbt = from.getNbtData();
MainUtil.setPosition(nbt, x, y, z);
addTileRemove(nbt);
}
if (to.hasNbtData()) {
CompoundTag nbt = to.getNbtData();
MainUtil.setPosition(nbt, x, y, z);
addTileRemove(nbt);
}
int combinedFrom = (from.getId() << 4) + from.getData();
int combinedTo = (to.getId() << 4) + to.getData();
add(x, y, z, combinedFrom, combinedTo);
} catch (Exception e) {
e.printStackTrace();
}
}
public void add(int x, int y, int z, int combinedFrom, BaseBlock to) {
try {
if (to.hasNbtData()) {
CompoundTag nbt = to.getNbtData();
MainUtil.setPosition(nbt, x, y, z);
addTileRemove(nbt);
}
int combinedTo = (to.getId() << 4) + to.getData();
add(x, y, z, combinedFrom, combinedTo);
} catch (Exception e) {
e.printStackTrace();
}
}
public void addChangeTask(FaweQueue queue) {
queue.setChangeTask(new RunnableVal2<FaweChunk, FaweChunk>() {
@Override
public void run(final FaweChunk previous, FaweChunk next) {
/**
* TODO cache NBT
* - Counter variable for nbt changes
* - Record biome changes
*/
int cx = previous.getX();
int cz = previous.getZ();
int bx = cx << 4;
int bz = cz << 4;
// Biome changes
{
// TODO
}
// Block changes
{
// Current blocks
char[][] currentIds = next.getIdArrays();
// Previous blocks in modified sections (i.e. we skip sections that weren't modified)
char[][] previousIds = previous.getIdArrays();
for (int layer = 0; layer < currentIds.length; layer++) {
char[] currentLayer = currentIds[layer];
char[] previousLayer = previousIds[layer];
if (currentLayer == null) {
continue;
}
int startY = layer << 4;
for (int y = 0; y < 16; y++) {
short[][] i1 = FaweCache.CACHE_J[y];
int yy = y + startY;
for (int x = 0; x < 16; x++) {
int xx = x + bx;
short[] i2 = i1[x];
for (int z = 0; z < 16; z++) {
int zz = z + bz;
int index = i2[z];
int combinedIdCurrent = currentLayer[index];
switch (combinedIdCurrent) {
case 0:
continue;
case 1:
combinedIdCurrent = 0;
default:
char combinedIdPrevious = previousLayer != null ? previousLayer[index] : 0;
if (combinedIdCurrent != combinedIdPrevious) {
add(xx, yy, zz, combinedIdPrevious, combinedIdCurrent);
}
}
}
}
}
}
}
// Tile changes
{
// Tiles created
Map<BytePair, CompoundTag> tiles = next.getTiles();
for (Map.Entry<BytePair, CompoundTag> entry : tiles.entrySet()) {
addTileCreate(entry.getValue());
}
// Tiles removed
tiles = previous.getTiles();
for (Map.Entry<BytePair, CompoundTag> entry : tiles.entrySet()) {
addTileRemove(entry.getValue());
}
}
// Entity changes
{
// Entities created
Set<CompoundTag> entities = next.getEntities();
for (CompoundTag entityTag : entities) {
addEntityCreate(entityTag);
}
// Entities removed
entities = previous.getEntities();
for (CompoundTag entityTag : entities) {
addEntityRemove(entityTag);
}
}
}
});
}
}

View File

@ -0,0 +1,363 @@
package com.boydti.fawe.object.changeset;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.change.MutableBlockChange;
import com.boydti.fawe.object.change.MutableEntityChange;
import com.boydti.fawe.object.change.MutableTileChange;
import com.google.common.collect.Iterators;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.worldedit.history.change.Change;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4InputStream;
import net.jpountz.lz4.LZ4OutputStream;
public abstract class FaweStreamChangeSet extends FaweChangeSet {
@Override
public int size() {
System.out.println("SIZE: " + blockSize);
// Flush so we can accurately get the size
flush();
return blockSize;
}
public abstract int getCompressedSize();
public abstract OutputStream getBlockOS(int x, int y, int z) throws IOException;
public abstract NBTOutputStream getEntityCreateOS() throws IOException;
public abstract NBTOutputStream getEntityRemoveOS() throws IOException;
public abstract NBTOutputStream getTileCreateOS() throws IOException;
public abstract NBTOutputStream getTileRemoveOS() throws IOException;
public abstract InputStream getBlockIS() throws IOException;
public abstract NBTInputStream getEntityCreateIS() throws IOException;
public abstract NBTInputStream getEntityRemoveIS() throws IOException;
public abstract NBTInputStream getTileCreateIS() throws IOException;
public abstract NBTInputStream getTileRemoveIS() throws IOException;
public int blockSize;
public int entityCreateSize;
public int entityRemoveSize;
public int tileCreateSize;
public int tileRemoveSize;
private int originX;
private int originZ;
public void setOrigin(int x, int z) {
originX = x;
originZ = z;
}
public int getOriginX() {
return originX;
}
public int getOriginZ() {
return originZ;
}
public InputStream getCompressedIS(InputStream is) {
if (Settings.COMPRESSION_LEVEL > 0) {
is = new LZ4InputStream(new LZ4InputStream(is));
} else {
is = new LZ4InputStream(is);
}
return is;
}
public OutputStream getCompressedOS(OutputStream os) throws IOException {
LZ4Factory factory = LZ4Factory.fastestInstance();
LZ4Compressor compressor = factory.fastCompressor();
os = new LZ4OutputStream(os, Settings.BUFFER_SIZE, factory.fastCompressor());
if (Settings.COMPRESSION_LEVEL > 0) {
os = new LZ4OutputStream(os, Settings.BUFFER_SIZE, factory.highCompressor());
}
return os;
}
public void add(int x, int y, int z, int combinedFrom, int combinedTo) {
blockSize++;
try {
OutputStream stream = getBlockOS(x, y, z);
//x
x-=originX;
stream.write((x) & 0xff);
stream.write(((x) >> 8) & 0xff);
//z
z-=originZ;
stream.write((z) & 0xff);
stream.write(((z) >> 8) & 0xff);
//y
stream.write((byte) y);
//from
stream.write((combinedFrom) & 0xff);
stream.write(((combinedFrom) >> 8) & 0xff);
//to
stream.write((combinedTo) & 0xff);
stream.write(((combinedTo) >> 8) & 0xff);
}
catch (IOException e) {
e.printStackTrace();
}
}
public void addTileCreate(CompoundTag tag) {
if (tag == null) {
return;
}
try {
NBTOutputStream nbtos = getTileCreateOS();
nbtos.writeNamedTag(tileCreateSize++ + "", tag);
} catch (IOException e) {
e.printStackTrace();
}
}
public void addTileRemove(CompoundTag tag) {
if (tag == null) {
return;
}
try {
NBTOutputStream nbtos = getTileRemoveOS();
nbtos.writeNamedTag(tileRemoveSize++ + "", tag);
} catch (IOException e) {
e.printStackTrace();
}
}
public void addEntityRemove(CompoundTag tag) {
if (tag == null) {
return;
}
try {
NBTOutputStream nbtos = getEntityRemoveOS();
nbtos.writeNamedTag(entityRemoveSize++ + "", tag);
} catch (IOException e) {
e.printStackTrace();
}
}
public void addEntityCreate(CompoundTag tag) {
if (tag == null) {
return;
}
try {
NBTOutputStream nbtos = getEntityCreateOS();
nbtos.writeNamedTag(entityCreateSize++ + "", tag);
} catch (IOException e) {
e.printStackTrace();
}
}
public Iterator<MutableBlockChange> getBlockIterator(final boolean dir) throws IOException {
final InputStream is = getBlockIS();
if (is == null) {
return new ArrayList<MutableBlockChange>().iterator();
}
final MutableBlockChange change = new MutableBlockChange(0, 0, 0, (short) 0, (byte) 0);
return new Iterator<MutableBlockChange>() {
private MutableBlockChange last = read();
public MutableBlockChange read() {
try {
int read0 = is.read();
if (read0 == -1) {
return null;
}
System.out.println("r0: " + read0);
int x = ((byte) read0 & 0xFF) + ((byte) is.read() << 8) + originX;
int z = ((byte) is.read() & 0xFF) + ((byte) is.read() << 8) + originZ;
int y = is.read() & 0xff;
change.x = x;
change.y = y;
change.z = z;
if (dir) {
is.skip(2);
int to1 = is.read();
int to2 = is.read();
change.id = (short) ((to2 << 4) + (to1 >> 4));
change.data = (byte) (to1 & 0xf);
} else {
int from1 = is.read();
int from2 = is.read();
is.skip(2);
change.id = (short) ((from2 << 4) + (from1 >> 4));
change.data = (byte) (from1 & 0xf);
}
System.out.println("CHANGE: " + change.id);
return change;
} catch (Exception ignoreEOF) {
ignoreEOF.printStackTrace();
}
return null;
}
@Override
public boolean hasNext() {
if (last == null) {
last = read();
}
if (last != null) {
System.out.println("HAS NEXT!");
return true;
}
System.out.println("NO NEXT");
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
@Override
public MutableBlockChange next() {
MutableBlockChange tmp = last;
last = null;
return tmp;
}
@Override
public void remove() {
throw new IllegalArgumentException("CANNOT REMOVE");
}
};
}
public Iterator<MutableEntityChange> getEntityIterator(final NBTInputStream is, final boolean create, final boolean dir) {
if (is == null) {
return new ArrayList<MutableEntityChange>().iterator();
}
final MutableEntityChange change = new MutableEntityChange(null, create);
try {
return new Iterator<MutableEntityChange>() {
private CompoundTag last = read();
public CompoundTag read() {
try {
return (CompoundTag) is.readNamedTag().getTag();
} catch (Exception ignoreEOS) {}
return null;
}
@Override
public boolean hasNext() {
if (last == null) {
last = read();
}
if (last != null) {
return true;
}
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
@Override
public MutableEntityChange next() {
change.tag = last;
last = null;
return change;
}
@Override
public void remove() {
throw new IllegalArgumentException("CANNOT REMOVE");
}
};
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public Iterator<MutableTileChange> getTileIterator(final NBTInputStream is, final boolean create, final boolean dir) {
if (is == null) {
return new ArrayList<MutableTileChange>().iterator();
}
final MutableTileChange change = new MutableTileChange(null, create);
try {
return new Iterator<MutableTileChange>() {
private CompoundTag last = read();
public CompoundTag read() {
try {
return (CompoundTag) is.readNamedTag().getTag();
} catch (Exception ignoreEOS) {}
return null;
}
@Override
public boolean hasNext() {
if (last == null) {
last = read();
}
if (last != null) {
return true;
}
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
@Override
public MutableTileChange next() {
change.tag = last;
last = null;
return change;
}
@Override
public void remove() {
throw new IllegalArgumentException("CANNOT REMOVE");
}
};
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public Iterator<Change> getIterator(final boolean dir) {
System.out.println("GET ITERATOR: " + dir);
flush();
try {
Iterator<MutableTileChange> tileCreate = getTileIterator(getTileCreateIS(), true, dir);
Iterator<MutableTileChange> tileRemove = getTileIterator(getTileRemoveIS(), false, dir);
Iterator<MutableEntityChange> entityCreate = getEntityIterator(getEntityCreateIS(), true, dir);
Iterator<MutableEntityChange> entityRemove = getEntityIterator(getEntityRemoveIS(), false, dir);
Iterator<MutableBlockChange> blockChange = getBlockIterator(dir);
return Iterators.concat(tileCreate, tileRemove, entityCreate, entityRemove, blockChange);
} catch (Exception e) {
e.printStackTrace();
}
return new ArrayList<Change>().iterator();
}
@Override
public Iterator<Change> backwardIterator() {
return getIterator(false);
}
@Override
public Iterator<Change> forwardIterator() {
return getIterator(true);
}
}

View File

@ -1,29 +1,14 @@
package com.boydti.fawe.object.changeset;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.ReflectionUtils;
import com.google.common.collect.Iterators;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.history.change.BlockChange;
import com.sk89q.worldedit.history.change.Change;
import com.sk89q.worldedit.history.changeset.ChangeSet;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4InputStream;
import net.jpountz.lz4.LZ4OutputStream;
@ -34,250 +19,14 @@ import net.jpountz.lz4.LZ4OutputStream;
* - High CPU usage
* - Low memory usage
*/
public class MemoryOptimizedHistory implements ChangeSet, FaweChangeSet {
public class MemoryOptimizedHistory extends FaweStreamChangeSet {
private final Actor actor;
private ArrayDeque<CompoundTag> fromTags;
private ArrayDeque<CompoundTag> toTags;
private byte[] ids;
private Object lock;
private int decompressedLength;
private FastByteArrayOutputStream idsStream;
private OutputStream idsStreamZip;
private ArrayDeque<Change> entities;
int ox;
int oz;
private int size;
public MemoryOptimizedHistory(Actor actor) {
this.actor = actor;
}
@Override
public void add(int x, int y, int z, int combinedFrom, int combinedTo) {
size++;
try {
OutputStream stream = getBAOS(x, y, z);
//x
x -= ox;
z -= oz;
stream.write((x & 0xff));
stream.write(((x >> 8) & 0xff));
//z
stream.write((z & 0xff));
stream.write( ((z >> 8) & 0xff));
//y
stream.write((byte) y);
//from
stream.write((combinedFrom) & 0xff);
stream.write(((combinedFrom) >> 8) & 0xff);
//to
stream.write((combinedTo) & 0xff);
stream.write(((combinedTo) >> 8) & 0xff);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void add(int x, int y, int z, int combinedId4DataFrom, BaseBlock to) {
int idTo = to.getId();
int combinedTo = (FaweCache.hasData(idTo) ? ((idTo << 4) + to.getData()) : (idTo << 4));
CompoundTag nbtTo = FaweCache.hasNBT(idTo) ? to.getNbtData() : null;
add(x, y, z, combinedId4DataFrom, combinedTo);
if (nbtTo != null && MainUtil.isValidTag(nbtTo)) {
Map<String, Tag> value = ReflectionUtils.getMap(nbtTo.getValue());
value.put("x", new IntTag(x));
value.put("y", new IntTag(y));
value.put("z", new IntTag(z));
if (toTags == null) {
toTags = new ArrayDeque<>();
}
toTags.add(nbtTo);
}
}
@Override
public void add(Vector loc, BaseBlock from, BaseBlock to) {
try {
int x = loc.getBlockX();
int y = loc.getBlockY();
int z = loc.getBlockZ();
int idfrom = from.getId();
int combinedFrom = (FaweCache.hasData(idfrom) ? ((idfrom << 4) + from.getData()) : (idfrom << 4));
CompoundTag nbtFrom = FaweCache.hasNBT(idfrom) ? from.getNbtData() : null;
if (nbtFrom != null && MainUtil.isValidTag(nbtFrom)) {
Map<String, Tag> value = ReflectionUtils.getMap(nbtFrom.getValue());
value.put("x", new IntTag(x));
value.put("y", new IntTag(y));
value.put("z", new IntTag(z));
if (fromTags == null) {
fromTags = new ArrayDeque<>();
}
fromTags.add(nbtFrom);
}
add(x, y, z, combinedFrom, to);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void add(Change arg) {
if ((arg instanceof BlockChange)) {
BlockChange change = (BlockChange) arg;
BlockVector loc = change.getPosition();
BaseBlock from = change.getPrevious();
BaseBlock to = change.getCurrent();
add(loc, from, to);
} else {
if (entities == null) {
entities = new ArrayDeque<>();
}
entities.add(arg);
}
}
private OutputStream getBAOS(int x, int y, int z) throws IOException {
if (idsStreamZip != null) {
return idsStreamZip;
}
LZ4Factory factory = LZ4Factory.fastestInstance();
idsStream = new FastByteArrayOutputStream(Settings.BUFFER_SIZE);
idsStreamZip = new LZ4OutputStream(idsStream, Settings.BUFFER_SIZE, factory.fastCompressor());
if (Settings.COMPRESSION_LEVEL > 0) {
idsStreamZip = new LZ4OutputStream(idsStreamZip, Settings.BUFFER_SIZE, factory.highCompressor());
}
ox = x;
oz = z;
return idsStreamZip;
}
@SuppressWarnings("resource")
public Iterator<Change> getIterator(final boolean dir) {
flush();
if (lock != null) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Iterator<Change> idsIterator;
Iterator<Change> entsIterator = entities != null ? entities.iterator() : new ArrayList().iterator();
if (ids == null) {
idsIterator = new ArrayList().iterator();
} else {
ByteArrayInputStream bais = new ByteArrayInputStream(ids);
final InputStream gis;
if (Settings.COMPRESSION_LEVEL > 0) {
gis = new LZ4InputStream(new LZ4InputStream(bais));
} else {
gis = new LZ4InputStream(bais);
}
idsIterator = new Iterator<Change>() {
private final Iterator<CompoundTag> lastFromIter = fromTags != null ? fromTags.iterator() : null;
private final Iterator<CompoundTag> lastToIter = toTags != null ? toTags.iterator() : null;
private CompoundTag lastFrom = read(lastFromIter);
private CompoundTag lastTo = read(lastToIter);
private Change last = read();
public CompoundTag read(Iterator<CompoundTag> tags) {
if (tags != null && tags.hasNext()) {
return tags.next();
}
return null;
}
public Change read() {
try {
int x = ((byte) gis.read() & 0xFF) + ((byte) gis.read() << 8) + ox;
int z = ((byte) gis.read() & 0xFF) + ((byte) gis.read() << 8) + oz;
int y = gis.read() & 0xff;
int from1 = gis.read();
int from2 = gis.read();
BaseBlock from = FaweCache.getBlock(((from2 << 4) + (from1 >> 4)), (from1 & 0xf));
if (lastFrom != null && FaweCache.hasNBT(from.getId())) {
Map<String, Tag> t = lastFrom.getValue();
if (((IntTag) t.get("x")).getValue() == x && ((IntTag) t.get("z")).getValue() == z && ((IntTag) t.get("y")).getValue() == y) {
from = new BaseBlock(from.getId(), from.getData());
from.setNbtData(lastFrom);
lastFrom = read(lastFromIter);
}
}
int to1 = gis.read();
int to2 = gis.read();
BaseBlock to = FaweCache.getBlock(((to2 << 4) + (to1 >> 4)), (to1 & 0xf));
if (lastTo != null && FaweCache.hasNBT(to.getId())) {
Map<String, Tag> t = lastTo.getValue();
if (((IntTag) t.get("x")).getValue() == x && ((IntTag) t.get("z")).getValue() == z && ((IntTag) t.get("y")).getValue() == y) {
to = new BaseBlock(to.getId(), to.getData());
to.setNbtData(lastTo);
lastTo = read(lastToIter);
}
}
BlockVector position = new BlockVector(x, y, z);
return dir ? new BlockChange(position, to, from) : new BlockChange(position, from, to);
} catch (Exception ignore) {}
return null;
}
@Override
public boolean hasNext() {
if (last != null) {
return true;
}
try {
gis.close();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
@Override
public Change next() {
Change tmp = last;
last = read();
return tmp;
}
@Override
public void remove() {
throw new IllegalArgumentException("CANNOT REMOVE");
}
};
}
return Iterators.concat(idsIterator, entsIterator);
} catch (Exception e) {
e.printStackTrace();
}
return new ArrayList<Change>().iterator();
}
@Override
public Iterator<Change> backwardIterator() {
return getIterator(false);
}
@Override
public Iterator<Change> forwardIterator() {
return getIterator(false);
}
@Override
public int size() {
return size;
}
@Override
public boolean flush() {
if (idsStreamZip != null) {
@ -285,7 +34,7 @@ public class MemoryOptimizedHistory implements ChangeSet, FaweChangeSet {
idsStream.flush();
idsStreamZip.flush();
idsStreamZip.close();
ids = idsStream.toByteArray();
ids = idsStream.toByteArray(true);
idsStream = null;
idsStreamZip = null;
} catch (IOException e) {
@ -301,4 +50,75 @@ public class MemoryOptimizedHistory implements ChangeSet, FaweChangeSet {
return ids == null ? 0 : ids.length;
}
private byte[] ids;
private FastByteArrayOutputStream idsStream;
private OutputStream idsStreamZip;
@Override
public OutputStream getBlockOS(int x, int y, int z) throws IOException {
if (idsStreamZip != null) {
return idsStreamZip;
}
LZ4Factory factory = LZ4Factory.fastestInstance();
idsStream = new FastByteArrayOutputStream(Settings.BUFFER_SIZE);
idsStreamZip = new LZ4OutputStream(idsStream, Settings.BUFFER_SIZE, factory.fastCompressor());
if (Settings.COMPRESSION_LEVEL > 0) {
idsStreamZip = new LZ4OutputStream(idsStreamZip, Settings.BUFFER_SIZE, factory.highCompressor());
}
setOrigin(x, z);
return idsStreamZip;
}
@Override
public NBTOutputStream getEntityCreateOS() throws IOException {
return null;
}
@Override
public NBTOutputStream getEntityRemoveOS() throws IOException {
return null;
}
@Override
public NBTOutputStream getTileCreateOS() throws IOException {
return null;
}
@Override
public NBTOutputStream getTileRemoveOS() throws IOException {
return null;
}
@Override
public InputStream getBlockIS() {
if (ids == null) {
return null;
}
InputStream is = new ByteArrayInputStream(ids);
is = new LZ4InputStream(is);
if (Settings.COMPRESSION_LEVEL > 0) {
is = new LZ4InputStream(is);
}
return is;
}
@Override
public NBTInputStream getEntityCreateIS() throws IOException {
return null;
}
@Override
public NBTInputStream getEntityRemoveIS() throws IOException {
return null;
}
@Override
public NBTInputStream getTileCreateIS() throws IOException {
return null;
}
@Override
public NBTInputStream getTileRemoveIS() throws IOException {
return null;
}
}

View File

@ -3,7 +3,12 @@ package com.boydti.fawe.object.extent;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.DoubleTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector;
@ -18,6 +23,7 @@ import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.List;
import java.util.Map;
public class FastWorldEditExtent extends AbstractDelegateExtent {
@ -28,15 +34,24 @@ public class FastWorldEditExtent extends AbstractDelegateExtent {
this.queue = queue;
}
public FaweQueue getQueue() {
return queue;
}
@Override
public Entity createEntity(final Location location, final BaseEntity entity) {
public Entity createEntity(final Location loc, final BaseEntity entity) {
if (entity != null) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
FastWorldEditExtent.super.createEntity(location, entity);
}
});
CompoundTag tag = entity.getNbtData();
Map<String, Tag> map = ReflectionUtils.getMap(tag.getValue());
map.put("Id", new StringTag(entity.getTypeId()));
ListTag pos = (ListTag) map.get("Pos");
if (pos != null) {
List<Tag> posList = ReflectionUtils.getList(pos.getValue());
posList.set(0, new DoubleTag(loc.getX()));
posList.set(1, new DoubleTag(loc.getY()));
posList.set(2, new DoubleTag(loc.getZ()));
}
queue.setEntity(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), tag);
}
return null;
}
@ -138,89 +153,10 @@ public class FastWorldEditExtent extends AbstractDelegateExtent {
case 151:
case 178: {
if (block.hasNbtData()) {
final Vector loc = new Vector(location.x, location.y, location.z);
queue.addTask(x >> 4, z >> 4, new Runnable() {
@Override
public void run() {
try {
FastWorldEditExtent.super.setBlock(loc, block);
} catch (WorldEditException e) {
e.printStackTrace();
}
}
});
return true;
CompoundTag nbt = block.getNbtData();
queue.setTile(x, y, z, nbt);
}
queue.setBlock(x, y, z, id, FaweCache.hasData(id) ? (byte) block.getData() : 0);
return true;
}
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 8:
case 9:
case 10:
case 11:
case 73:
case 74:
case 78:
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 181:
case 182:
case 188:
case 189:
case 190:
case 191:
case 192: {
queue.setBlock(x, y, z, id, (byte) 0);
queue.setBlock(x, y, z, id, (byte) block.getData());
return true;
}
default: {

View File

@ -73,16 +73,23 @@ public class FastByteArrayOutputStream extends OutputStream {
}
public byte[] toByteArray() {
return toByteArray(false);
}
public byte[] toByteArray(boolean delete) {
byte[] data = new byte[getSize()];
// Check if we have a list of buffers
int pos = 0;
buffer = null;
if (buffers != null) {
Iterator iter = buffers.iterator();
while (iter.hasNext()) {
byte[] bytes = (byte[])iter.next();
if (delete) {
iter.remove();
}
System.arraycopy(bytes, 0, data, pos, blockSize);
pos += blockSize;
}

View File

@ -3,7 +3,9 @@ package com.boydti.fawe.util;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.object.exception.FaweException;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.HashSet;
@ -15,6 +17,7 @@ public abstract class FaweQueue {
public final String world;
public LinkedBlockingDeque<EditSession> sessions;
public long modified = System.currentTimeMillis();
public RunnableVal2<FaweChunk, FaweChunk> changeTask;
public FaweQueue(String world) {
this.world = world;
@ -34,10 +37,22 @@ public abstract class FaweQueue {
return sessions == null ? new HashSet<EditSession>() : new HashSet<>(sessions);
}
public void setChangeTask(RunnableVal2<FaweChunk, FaweChunk> changeTask) {
this.changeTask = changeTask;
}
public RunnableVal2<FaweChunk, FaweChunk> getChangeTask() {
return changeTask;
}
public void optimize() {}
public abstract boolean setBlock(final int x, final int y, final int z, final short id, final byte data);
public abstract void setTile(int x, int y, int z, CompoundTag tag);
public abstract void setEntity(int x, int y, int z, CompoundTag tag);
public abstract boolean setBiome(final int x, final int z, final BaseBiome biome);
public abstract FaweChunk<?> getChunk(int x, int z);
@ -88,7 +103,9 @@ public abstract class FaweQueue {
*/
public abstract void clear();
public abstract void addTask(int x, int z, Runnable runnable);
public abstract void addNotifyTask(int x, int z, Runnable runnable);
public abstract void addNotifyTask(Runnable runnable);
public abstract int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException;

View File

@ -1,81 +0,0 @@
package com.boydti.fawe.util;
/**
* TPS and Lag Checker.
*/
public class Lag implements Runnable {
/**
* Ticks
*/
public static final long[] T = new long[600];
/**
* Tick count
*/
public static int TC = 0;
/**
* something :_:
*/
@SuppressWarnings("unused")
public static long LT = 0L;
/**
* Get the server TPS
*
* @return server tick per second
*/
public static double getTPS() {
return Math.round(getTPS(100)) > 20.0D ? 20.0D : Math.round(getTPS(100));
}
/**
* Return the tick per second (measured in $ticks)
*
* @param ticks Ticks
*
* @return ticks per second
*/
public static double getTPS(final int ticks) {
if (TC < ticks) {
return 20.0D;
}
final int t = (TC - 1 - ticks) % T.length;
final long e = System.currentTimeMillis() - T[t];
return ticks / (e / 1000.0D);
}
/**
* Get number of ticks since
*
* @param tI Ticks <
*
* @return number of ticks since $tI
*/
public static long getElapsed(final int tI) {
final long t = T[tI % T.length];
return System.currentTimeMillis() - t;
}
/**
* Get lag percentage
*
* @return lag percentage
*/
public static double getPercentage() {
return Math.round((1.0D - (Lag.getTPS() / 20.0D)) * 100.0D);
}
/**
* Get TPS percentage (of 20)
*
* @return TPS percentage
*/
public static double getFullPercentage() {
return getTPS() * 5.0D;
}
@Override
public void run() {
T[TC % T.length] = System.currentTimeMillis();
TC++;
}
}

View File

@ -5,14 +5,20 @@ import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.object.changeset.FaweStreamChangeSet;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.DoubleTag;
import com.sk89q.jnbt.EndTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.Location;
import java.io.File;
import java.lang.reflect.Array;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@ -39,7 +45,27 @@ public class MainUtil {
Fawe.debug(s);
}
public static void sendCompressedMessage(FaweChangeSet set, Actor actor)
public static void setPosition(CompoundTag tag, int x, int y, int z) {
Map<String, Tag> value = ReflectionUtils.getMap(tag.getValue());
value.put("x", new IntTag(x));
value.put("y", new IntTag(y));
value.put("z", new IntTag(z));
}
public static void setEntityInfo(CompoundTag tag, Entity entity) {
Map<String, Tag> map = ReflectionUtils.getMap(tag.getValue());
map.put("Id", new StringTag(entity.getState().getTypeId()));
ListTag pos = (ListTag) map.get("Pos");
if (pos != null) {
Location loc = entity.getLocation();
List<Tag> posList = ReflectionUtils.getList(pos.getValue());
posList.set(0, new DoubleTag(loc.getX()));
posList.set(1, new DoubleTag(loc.getY()));
posList.set(2, new DoubleTag(loc.getZ()));
}
}
public static void sendCompressedMessage(FaweStreamChangeSet set, Actor actor)
{
try {
int elements = set.size();

View File

@ -43,6 +43,18 @@ public class MathMan {
253, 254, 254, 255
};
public static byte pair16(byte x, byte y) {
return (byte) (x + (y << 4));
}
public static byte unpair16x(byte value) {
return (byte) (value & 0xF);
}
public static byte unpair16y(byte value) {
return (byte) ((value >> 4) & 0xF);
}
public static int sqrt(int x) {
int xn;

View File

@ -57,18 +57,30 @@ public class ReflectionUtils {
}
}
}
public static <T, V> Map<T, V> getMap(Map<T, V> map) {
try {
Class<? extends Map> clazz = map.getClass();
Field m = clazz.getDeclaredField("m");
m.setAccessible(true);
return (Map<T, V>) m.get(map);
} catch (Throwable e) {
e.printStackTrace();
return map;
}
public static <T, V> Map<T, V> getMap(Map<T, V> map) {
try {
Class<? extends Map> clazz = map.getClass();
Field m = clazz.getDeclaredField("m");
m.setAccessible(true);
return (Map<T, V>) m.get(map);
} catch (Throwable e) {
e.printStackTrace();
return map;
}
}
public static <T> List<T> getList(List<T> list) {
try {
Class<? extends List> clazz = (Class<? extends List>) Class.forName("java.util.Collections$UnmodifiableList");
Field m = clazz.getDeclaredField("list");
m.setAccessible(true);
return (List<T>) m.get(list);
} catch (Throwable e) {
e.printStackTrace();
return list;
}
}
public static Class<?> getNmsClass(final String name) {
final String className = "net.minecraft.server." + getVersion() + "." + name;

View File

@ -15,6 +15,10 @@ public class SetQueue {
*/
public static final SetQueue IMP = new SetQueue();
public static enum QueueStage {
INACTIVE, ACTIVE, NONE;
}
public final LinkedBlockingDeque<FaweQueue> activeQueues;
public final LinkedBlockingDeque<FaweQueue> inactiveQueues;
@ -113,6 +117,27 @@ public class SetQueue {
}, 1);
}
public QueueStage getStage(FaweQueue queue) {
if (activeQueues.contains(queue)) {
return QueueStage.ACTIVE;
} else if (inactiveQueues.contains(queue)) {
return QueueStage.INACTIVE;
}
return QueueStage.NONE;
}
public boolean isStage(FaweQueue queue, QueueStage stage) {
switch (stage) {
case ACTIVE:
return activeQueues.contains(queue);
case INACTIVE:
return inactiveQueues.contains(queue);
case NONE:
return !activeQueues.contains(queue) && !inactiveQueues.contains(queue);
}
return false;
}
public void enqueue(FaweQueue queue) {
inactiveQueues.remove(queue);
if (queue.size() > 0 && !activeQueues.contains(queue)) {

View File

@ -304,7 +304,7 @@ public class WorldWrapper extends AbstractWorld {
try {
final BaseBlock block = getBlock(loc);
final Vector v = new Vector(loc.x, loc.y, loc.z);
queue.addTask(cx, cz, new Runnable() {
queue.addNotifyTask(cx, cz, new Runnable() {
@Override
public void run() {
try {

View File

@ -327,7 +327,11 @@ public class EditSession implements Extent {
// History
this.changeSet = Settings.STORE_HISTORY_ON_DISK ? new DiskStorageHistory(world, actor.getUniqueId()) : new MemoryOptimizedHistory(actor);
extent = this.wrapper.getHistoryExtent(this, limit, extent, this.changeSet, queue, fp);
if (Settings.COMBINE_HISTORY_STAGE) {
changeSet.addChangeTask(queue);
} else {
extent = this.wrapper.getHistoryExtent(this, limit, extent, this.changeSet, queue, fp);
}
// Region restrictions if mask is not null
if (mask != null) {
@ -875,7 +879,7 @@ public class EditSession implements Extent {
editSession.flushQueue();
}
}, true);
editSession.changes = changes;
editSession.changes = 1;
}
/**
@ -892,7 +896,7 @@ public class EditSession implements Extent {
editSession.flushQueue();
}
}, true);
editSession.changes = changes;
editSession.changes = 1;
}
/**

View File

@ -19,7 +19,9 @@
package com.sk89q.worldedit;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.object.changeset.FaweStreamChangeSet;
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.MainUtil;
@ -80,7 +82,7 @@ public class LocalSession {
private transient RegionSelector selector = new CuboidRegionSelector();
private transient boolean placeAtPos1 = false;
private transient List<EditSession> history = Collections.synchronizedList(new LinkedList<EditSession>());
private transient int historyPointer = 0;
private transient volatile int historyPointer = 0;
private transient ClipboardHolder clipboard;
private transient boolean toolControl = true;
private transient boolean superPickaxe = false;
@ -200,7 +202,7 @@ public class LocalSession {
remember(editSession, true);
}
public void remember(EditSession editSession, boolean append) {
public void remember(final EditSession editSession, final boolean append) {
// Enqueue it
if (editSession.getQueue() != null) {
FaweQueue queue = editSession.getQueue();
@ -217,12 +219,25 @@ public class LocalSession {
history.remove(historyPointer);
}
ChangeSet set = editSession.getChangeSet();
if (set instanceof FaweChangeSet) {
FaweChangeSet fcs = (FaweChangeSet) set;
if (fcs.flush() && append) {
MainUtil.sendCompressedMessage(fcs, editSession.actor);
if (set instanceof FaweStreamChangeSet) {
final FaweStreamChangeSet fcs = (FaweStreamChangeSet) set;
if (Settings.COMBINE_HISTORY_STAGE) {
editSession.getQueue().addNotifyTask(new Runnable() {
@Override
public void run() {
if (fcs.flush() && append) {
MainUtil.sendCompressedMessage(fcs, editSession.actor);
}
}
});
} else {
if (fcs.flush() && append) {
MainUtil.sendCompressedMessage(fcs, editSession.actor);
}
}
} else if (set instanceof FaweChangeSet) {
((FaweChangeSet) set).flush();
}
if (append) {
history.add(editSession);
@ -232,7 +247,7 @@ public class LocalSession {
while (history.size() > MAX_HISTORY_SIZE) {
history.remove(0);
}
historyPointer = history.size();
historyPointer = append ? history.size() : historyPointer + 1;
}
/**
@ -263,6 +278,7 @@ public class LocalSession {
newEditSession.enableQueue();
newEditSession.setFastMode(fastMode);
editSession.undo(newEditSession);
System.out.println("UNDO: " + historyPointer + " | " + history.size());
return editSession;
} else {
historyPointer = 0;
@ -290,6 +306,7 @@ public class LocalSession {
*/
public EditSession redo(@Nullable BlockBag newBlockBag, Player player) {
checkNotNull(player);
System.out.println("CHECK REDO: " + historyPointer + " | " + history.size());
if (historyPointer < history.size()) {
EditSession editSession = history.get(historyPointer);
EditSession newEditSession = WorldEdit.getInstance().getEditSessionFactory()
@ -298,7 +315,10 @@ public class LocalSession {
newEditSession.setFastMode(fastMode);
editSession.redo(newEditSession);
++historyPointer;
System.out.println("CAN REDO");
return editSession;
} else {
System.out.println("POINTER");
}
return null;

View File

@ -224,6 +224,7 @@ public final class CommandManager {
TaskManager.IMP.async(new Runnable() {
@Override
public void run() {
System.out.println("COMMAND START!");
final Actor actor = platformManager.createProxyActor(event.getActor());
String[] split = commandDetection(event.getArguments().split(" "));
@ -284,6 +285,7 @@ public final class CommandManager {
log.log(Level.SEVERE, "An unknown error occurred", e);
}
} finally {
System.out.println("DONE!");
if (fp != null) {
fp.deleteMeta("fawe_action");
}

View File

@ -62,7 +62,6 @@ public class ChangeSetExecutor implements Operation {
@Override
public Operation resume(RunContext run) throws WorldEditException {
int size = 0;
if (type == Type.UNDO) {
while (iterator.hasNext()) {
iterator.next().undo(context);

144
pom.xml
View File

@ -12,53 +12,94 @@
<name>FastAsyncWorldEdit</name>
<packaging>jar</packaging>
<build>
<finalName>FastAsyncWorldEdit-Bukkit-${project.version}</finalName>
<sourceDirectory>Bukkit/src/main/java</sourceDirectory>
<finalName>FastAsyncWorldEdit-UBER-${project.version}</finalName>
<sourceDirectory>core/src/main/java</sourceDirectory>
<resources>
<resource>
<filtering>true</filtering>
<includes>
<include>**/*.*</include>
</includes>
<directory>bukkit/src/main/resources/</directory>
</resource>
<resource>
<filtering>false</filtering>
<includes>
<include>**/*.*</include>
</includes>
<directory>core/src/main/resources/</directory>
</resource>
<resource>
<filtering>false</filtering>
<includes>
<include>**/*.*</include>
</includes>
<directory>bukkit19/src/main/resources/</directory>
</resource>
<resource>
<filtering>false</filtering>
<includes>
<include>**/*.*</include>
</includes>
<directory>bukkit18/src/main/resources/</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<excludes>
<exclude>**/forge/src/main/**/*.*</exclude>
</excludes>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>core/src/main/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
<id>Bukkit19</id>
<configuration>
<finalName>FastAsyncWorldEdit-Bukkit19-${project.version}</finalName>
<excludes>
<exclude>**/forge180/src/main/**/*.*</exclude>
<exclude>**/forge1710/src/main/**/*.*</exclude>
<exclude>com/boydti/fawe/bukkit/v1_8/**/*.*</exclude>
</excludes>
</configuration>
</execution>
<execution>
<goals>
<goal>jar</goal>
</goals>
<id>Bukkit18</id>
<configuration>
<finalName>FastAsyncWorldEdit-Bukkit18-${project.version}</finalName>
<excludes>
<exclude>**/forge180/src/main/**/*.*</exclude>
<exclude>**/forge1710/src/main/**/*.*</exclude>
<exclude>com/boydti/fawe/bukkit/v1_9/**/*.*</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<excludes>
<exclude>**/forge180/src/main/**/*.*</exclude>
<exclude>**/forge1710/src/main/**/*.*</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>bukkit0/src/main/java</source>
<source>bukkit18/src/main/java</source>
<source>bukkit19/src/main/java</source>
</sources>
<compilerArgument>-proc:none</compilerArgument>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
@ -114,6 +155,16 @@
<artifactId>bukkit</artifactId>
<version>1.9-R0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.bukkit.craftbukkit.v1_8</groupId>
<artifactId>craftbukkitv1_8</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.bukkit.craftbukkit</groupId>
<artifactId>CraftBukkit</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.PrimeSoft</groupId>
<artifactId>blockshub</artifactId>
@ -129,6 +180,11 @@
<artifactId>factions</artifactId>
<version>1.6.9.5</version>
</dependency>
<dependency>
<groupId>com.factionsone</groupId>
<artifactId>FactionsOne</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>me.ryanhamshire</groupId>
<artifactId>GriefPrevention</artifactId>