mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-11-28 13:45:36 +01:00
Various
update to 1.9.4 progress notifications lighting fixes optimizations Only stable for bukkit 1.8/1.9
This commit is contained in:
parent
947ff54a4c
commit
b5a8eb2176
@ -3,14 +3,18 @@ package com.boydti.fawe.bukkit;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.FaweLocation;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class BukkitPlayer extends FawePlayer<Player> {
|
||||
|
||||
private static ConsoleCommandSender console;
|
||||
|
||||
public BukkitPlayer(final Player parent) {
|
||||
super(parent);
|
||||
}
|
||||
@ -49,6 +53,27 @@ public class BukkitPlayer extends FawePlayer<Player> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void resetTitle() {
|
||||
sendTitle("","");
|
||||
}
|
||||
|
||||
public void sendTitle(String title, String sub) {
|
||||
try {
|
||||
Method methodSendTitle = Player.class.getDeclaredMethod("sendTitle", String.class, String.class);
|
||||
methodSendTitle.invoke(parent, ChatColor.GOLD + title, ChatColor.GOLD + sub);
|
||||
return;
|
||||
} catch (Throwable ignore) {}
|
||||
if (console == null) {
|
||||
console = Bukkit.getConsoleSender();
|
||||
Bukkit.getServer().dispatchCommand(console, "gamerule sendCommandFeedback false");
|
||||
Bukkit.getServer().dispatchCommand(console, "title " + getName() + " times 0 60 20");
|
||||
}
|
||||
Bukkit.getServer().dispatchCommand(console, "title " + getName() + " subtitle [{\"text\":\"" + sub + "\",\"color\":\"gold\"}]");
|
||||
Bukkit.getServer().dispatchCommand(console, "title " + getName() + " title [{\"text\":\"" + title + "\",\"color\":\"gold\"}]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(final String message) {
|
||||
this.parent.sendMessage(ChatColor.translateAlternateColorCodes('&', message));
|
||||
|
@ -195,7 +195,7 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
debug("====== NO NMS BLOCK PLACER FOUND ======");
|
||||
debug("FAWE couldn't find a fast block placer");
|
||||
debug("Bukkit version: " + Bukkit.getVersion());
|
||||
debug("Supported NMS versions: 1.8, 1.9");
|
||||
debug("Supported NMS versions: 1.8.8, 1.9.4");
|
||||
debug("Fallback placer: " + BukkitQueue_All.class);
|
||||
debug("=======================================");
|
||||
hasNMS = false;
|
||||
|
@ -19,6 +19,7 @@ public class LoggingChangeSet extends FaweChangeSet {
|
||||
private final String name;
|
||||
|
||||
public LoggingChangeSet(FawePlayer<Player> player, FaweChangeSet parent, IBlocksHubApi api) {
|
||||
super(parent.getWorld());
|
||||
this.parent = parent;
|
||||
this.name = player.getName();
|
||||
this.api = api;
|
||||
|
@ -22,12 +22,11 @@ public class BukkitEditSessionWrapper_0 extends EditSessionWrapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Extent getHistoryExtent(EditSession session, FaweLimit limit, Extent parent, FaweChangeSet set, FaweQueue queue, FawePlayer<?> player) {
|
||||
public FaweChangeSet wrapChangeSet(EditSession session, FaweLimit limit, Extent parent, FaweChangeSet set, FaweQueue queue, FawePlayer<?> player) {
|
||||
if (this.hook != null) {
|
||||
// If we are doing logging, use a custom logging ChangeSet
|
||||
set = hook.getLoggingChangeSet(session, limit, parent, set, queue, player);
|
||||
return hook.getLoggingChangeSet(session, limit, parent, set, queue, player);
|
||||
}
|
||||
// Now return the normal history extent
|
||||
return super.getHistoryExtent(session, limit, parent, set, queue, player);
|
||||
return set;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.v0;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.example.CharFaweChunk;
|
||||
import com.boydti.fawe.example.NMSMappedFaweQueue;
|
||||
@ -14,6 +15,10 @@ import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
@ -21,18 +26,26 @@ import org.bukkit.block.Block;
|
||||
|
||||
public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMappedFaweQueue<World, CHUNK, CHUNKSECTIONS, SECTION> {
|
||||
|
||||
public final BukkitImplAdapter adapter;
|
||||
public Object adapter;
|
||||
public Method methodToNative;
|
||||
public Method methodFromNative;
|
||||
|
||||
public BukkitQueue_0(final String world) {
|
||||
super(world);
|
||||
setupAdapter(null);
|
||||
}
|
||||
|
||||
public void setupAdapter(BukkitImplAdapter adapter) {
|
||||
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()) {
|
||||
if ((this.adapter = adapter) != null) {
|
||||
fieldAdapter.set(instance, adapter);
|
||||
} else {
|
||||
this.adapter = fieldAdapter.get(instance);
|
||||
}
|
||||
for (Method method : this.adapter.getClass().getDeclaredMethods()) {
|
||||
switch (method.getName()) {
|
||||
case "toNative":
|
||||
methodToNative = method;
|
||||
@ -45,7 +58,12 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
e.printStackTrace();
|
||||
Fawe.debug("====== NO NATIVE WORLDEDIT ADAPTER ======");
|
||||
Fawe.debug("Try updating WorldEdit: ");
|
||||
Fawe.debug(" - http://builds.enginehub.org/job/worldedit?branch=master");
|
||||
Fawe.debug("See also: http://wiki.sk89q.com/wiki/WorldEdit/Bukkit_adapters");
|
||||
Fawe.debug("=========================================");
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,8 +87,14 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
|
||||
return world.regenerateChunk(x, z);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean fixLighting(FaweChunk fc, boolean fixAll) {
|
||||
public CharFaweChunk getPrevious(CharFaweChunk fs, CHUNKSECTIONS sections, Map<?, ?> tiles, Collection<?>[] entities, Set<UUID> createdEntities, boolean all) throws Exception {
|
||||
return fs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fixLighting(FaweChunk fc, RelightMode mode) {
|
||||
// Not implemented
|
||||
return true;
|
||||
}
|
||||
@ -121,7 +145,7 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
|
||||
final Chunk chunk = fs.getChunk();
|
||||
chunk.load(true);
|
||||
final World world = chunk.getWorld();
|
||||
char[][] sections = fs.getIdArrays();
|
||||
char[][] sections = fs.getCombinedIdArrays();
|
||||
boolean done = false;
|
||||
boolean more = false;
|
||||
// Efficiently merge sections
|
||||
|
@ -2,11 +2,11 @@ package com.boydti.fawe.bukkit.v1_8;
|
||||
|
||||
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_18 extends ABukkitMain {
|
||||
|
||||
@Override
|
||||
public BukkitQueue_0 getQueue(String world) {
|
||||
return new BukkitQueue18R3(world);
|
||||
|
@ -21,16 +21,19 @@ import com.sk89q.worldedit.internal.Constants;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
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.EntityPlayer;
|
||||
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.NibbleArray;
|
||||
import net.minecraft.server.v1_8_R3.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_8_R3.PlayerConnection;
|
||||
import net.minecraft.server.v1_8_R3.TileEntity;
|
||||
@ -96,41 +99,44 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
net.minecraft.server.v1_8_R3.World nmsWorld = nmsChunk.getWorld();
|
||||
try {
|
||||
final boolean flag = getWorld().getEnvironment() == World.Environment.NORMAL;
|
||||
// Sections
|
||||
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());
|
||||
public CharFaweChunk getPrevious(CharFaweChunk fs, ChunkSection[] sections, Map<?, ?> tilesGeneric, Collection<?>[] entitiesGeneric, Set<UUID> createdEntities, boolean all) throws Exception {
|
||||
Map<BlockPosition, TileEntity> tiles = (Map<BlockPosition, TileEntity>) tilesGeneric;
|
||||
Collection<Entity>[] entities = (Collection<Entity>[]) entitiesGeneric;
|
||||
CharFaweChunk previous = (CharFaweChunk) getChunk(fs.getX(), fs.getZ());
|
||||
char[][] idPrevious = new char[16][];
|
||||
for (int layer = 0; layer < sections.length; layer++) {
|
||||
if (fs.getCount(layer) != 0) {
|
||||
if (fs.getCount(layer) != 0 || all) {
|
||||
ChunkSection section = sections[layer];
|
||||
if (section != null) {
|
||||
idPrevious[layer] = section.getIdArray().clone();
|
||||
short solid = 0;
|
||||
for (int combined : idPrevious[layer]) {
|
||||
if (combined > 1) {
|
||||
solid++;
|
||||
}
|
||||
}
|
||||
previous.count[layer] = solid;
|
||||
previous.air[layer] = (short) (4096 - solid);
|
||||
}
|
||||
}
|
||||
}
|
||||
previous.ids = idPrevious;
|
||||
if (tiles != null) {
|
||||
for (Map.Entry<BlockPosition, TileEntity> entry : tiles.entrySet()) {
|
||||
TileEntity tile = entry.getValue();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
tile.b(tag); // ReadTileIntoTag
|
||||
tile.b(tag); // readTileEntityIntoTag
|
||||
BlockPosition pos = entry.getKey();
|
||||
CompoundTag nativeTag = (CompoundTag) methodToNative.invoke(adapter, tag);
|
||||
previous.setTile(pos.getX(), pos.getY(), pos.getZ(), nativeTag);
|
||||
}
|
||||
}
|
||||
if (entities != null) {
|
||||
for (Collection<Entity> entityList : entities) {
|
||||
for (Entity ent : entityList) {
|
||||
if (ent instanceof EntityPlayer || (!createdEntities.isEmpty() && !createdEntities.contains(ent.getUniqueID()))) {
|
||||
continue;
|
||||
}
|
||||
int x = ((int) Math.round(ent.locX) & 15);
|
||||
int z = ((int) Math.round(ent.locZ) & 15);
|
||||
int y = (int) Math.round(ent.locY);
|
||||
@ -144,7 +150,7 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
|
||||
String id = EntityTypes.b(ent);
|
||||
if (id != null) {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
ent.e(tag);
|
||||
ent.e(tag); // readEntityIntoTag
|
||||
CompoundTag nativeTag = (CompoundTag) methodToNative.invoke(adapter, tag);
|
||||
Map<String, Tag> map = ReflectionUtils.getMap(nativeTag.getValue());
|
||||
map.put("Id", new StringTag(id));
|
||||
@ -153,9 +159,87 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
|
||||
}
|
||||
}
|
||||
}
|
||||
changeTask.run(previous);
|
||||
}
|
||||
return previous;
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
net.minecraft.server.v1_8_R3.World nmsWorld = nmsChunk.getWorld();
|
||||
try {
|
||||
final boolean flag = getWorld().getEnvironment() == World.Environment.NORMAL;
|
||||
// Sections
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
Map<BlockPosition, TileEntity> tiles = nmsChunk.getTileEntities();
|
||||
Collection<net.minecraft.server.v1_8_R3.Entity>[] entities = nmsChunk.getEntitySlices();
|
||||
|
||||
// Remove entities
|
||||
for (int i = 0; i < 16; i++) {
|
||||
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) {
|
||||
if (entity instanceof EntityPlayer) {
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set entities
|
||||
Set<UUID> createdEntities = new HashSet<>();
|
||||
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);
|
||||
createdEntities.add(entity.getUniqueID());
|
||||
}
|
||||
}
|
||||
// Run change task if applicable
|
||||
if (changeTask != null) {
|
||||
CharFaweChunk previous = getPrevious(fs, sections, tiles, entities, createdEntities, false);
|
||||
changeTask.run(previous);
|
||||
}
|
||||
// Trim tiles
|
||||
Set<Map.Entry<BlockPosition, TileEntity>> entryset = tiles.entrySet();
|
||||
Iterator<Map.Entry<BlockPosition, TileEntity>> iterator = entryset.iterator();
|
||||
@ -175,31 +259,17 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
// Remove entities
|
||||
for (int i = 0; i < 16; i++) {
|
||||
int count = fs.getCount(i);
|
||||
if (count == 0) {
|
||||
continue;
|
||||
} else if (count >= 4096) {
|
||||
entities[i].clear();
|
||||
} else {
|
||||
char[] array = fs.getIdArray(i);
|
||||
HashSet<UUID> entsToRemove = fs.getEntityRemoves();
|
||||
if (entsToRemove.size() > 0) {
|
||||
for (int i = 0; i < entities.length; 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) {
|
||||
if (entsToRemove.contains(entity.getUniqueID())) {
|
||||
nmsWorld.removeEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set blocks
|
||||
for (int j = 0; j < sections.length; j++) {
|
||||
if (fs.getCount(j) == 0) {
|
||||
@ -256,53 +326,19 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
|
||||
}
|
||||
// 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);
|
||||
BlockPosition pos = new BlockPosition(MathMan.unpair16x(pair.pair[0]) + bx, pair.pair[1] & 0xFF, MathMan.unpair16y(pair.pair[0]) + bz); // Set pos
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||
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();
|
||||
}
|
||||
@ -339,8 +375,8 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
|
||||
FaweLocation loc = fp.getLocation();
|
||||
int px = loc.x >> 4;
|
||||
int pz = loc.z >> 4;
|
||||
int dx = Math.abs(cx - (loc.x >> 4));
|
||||
int dz = Math.abs(cz - (loc.z >> 4));
|
||||
int dx = Math.abs(cx - (px));
|
||||
int dz = Math.abs(cz - (pz));
|
||||
if ((dx > view) || (dz > view)) {
|
||||
continue;
|
||||
}
|
||||
@ -350,7 +386,7 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fixLighting(FaweChunk chunk, boolean fixAll) {
|
||||
public boolean fixLighting(FaweChunk chunk, RelightMode mode) {
|
||||
try {
|
||||
CharFaweChunk<Chunk> fc = (CharFaweChunk<Chunk>) chunk;
|
||||
CraftChunk craftChunk = (CraftChunk) fc.getChunk();
|
||||
@ -358,11 +394,22 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
|
||||
if (!craftChunk.isLoaded()) {
|
||||
return false;
|
||||
}
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
if (mode != RelightMode.MINIMAL) {
|
||||
for (int i = 0; i < sections.length; i++) {
|
||||
ChunkSection section = sections[i];
|
||||
if (section != null) {
|
||||
if (mode == RelightMode.ALL) {
|
||||
section.a(new NibbleArray());
|
||||
}
|
||||
section.b(new NibbleArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
nmsChunk.initLighting();
|
||||
if (fc.getTotalRelight() == 0 && !fixAll) {
|
||||
if (fc.getTotalRelight() == 0 && mode == RelightMode.MINIMAL) {
|
||||
return true;
|
||||
}
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
net.minecraft.server.v1_8_R3.World nmsWorld = nmsChunk.getWorld();
|
||||
|
||||
int X = fc.getX() << 4;
|
||||
@ -374,7 +421,7 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
|
||||
if (section == null) {
|
||||
continue;
|
||||
}
|
||||
if ((fc.getRelight(j) == 0 && !fixAll) || fc.getCount(j) == 0 || (fc.getCount(j) >= 4096 && fc.getAir(j) == 0)) {
|
||||
if ((fc.getRelight(j) == 0 && mode == RelightMode.MINIMAL) || (fc.getCount(j) == 0 && mode != RelightMode.ALL) || (fc.getCount(j) >= 4096 && fc.getAir(j) == 0)) {
|
||||
continue;
|
||||
}
|
||||
char[] array = section.getIdArray();
|
||||
@ -387,7 +434,7 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
|
||||
short id = (short) (i >> 4);
|
||||
switch (id) { // Lighting
|
||||
default:
|
||||
if (!fixAll) {
|
||||
if (mode == RelightMode.MINIMAL) {
|
||||
continue;
|
||||
}
|
||||
if ((k & 1) == l) {
|
||||
|
@ -21,9 +21,9 @@ commands:
|
||||
fawe:
|
||||
description: (FAWE) Reload the plugin
|
||||
aliases: [/fawe,/fawereload]
|
||||
wrg:
|
||||
select:
|
||||
description: (FAWE) Select your current WorldEdit Region.
|
||||
aliases: [/wrg,wer,/wer,worldeditregion,/worldeditregion,/region]
|
||||
aliases: [/select,wer,/wer,worldeditregion,/worldeditregion,/region]
|
||||
frb:
|
||||
description: (FAWE) Rollback an edit
|
||||
aliases: [fawerollback,fawerb,/uu,/rb,/frb,/fawerollback,/fawerb]
|
||||
|
@ -1,6 +1,6 @@
|
||||
dependencies {
|
||||
compile project(':bukkit0')
|
||||
compile 'org.bukkit.craftbukkit:CraftBukkit:1.9.2'
|
||||
compile 'org.bukkit.craftbukkit.v1_9R2:craftbukkitv1_9R2:1.9.4'
|
||||
}
|
||||
|
||||
apply plugin: 'com.github.johnrengelman.shadow'
|
||||
|
@ -5,12 +5,12 @@ import com.boydti.fawe.example.CharFaweChunk;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import net.minecraft.server.v1_9_R1.Block;
|
||||
import net.minecraft.server.v1_9_R1.DataBits;
|
||||
import net.minecraft.server.v1_9_R1.DataPalette;
|
||||
import net.minecraft.server.v1_9_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_9_R1.DataPaletteGlobal;
|
||||
import net.minecraft.server.v1_9_R1.IBlockData;
|
||||
import net.minecraft.server.v1_9_R2.Block;
|
||||
import net.minecraft.server.v1_9_R2.DataBits;
|
||||
import net.minecraft.server.v1_9_R2.DataPalette;
|
||||
import net.minecraft.server.v1_9_R2.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_9_R2.DataPaletteGlobal;
|
||||
import net.minecraft.server.v1_9_R2.IBlockData;
|
||||
import org.bukkit.Chunk;
|
||||
|
||||
public class BukkitChunk_1_9 extends CharFaweChunk<Chunk> {
|
||||
@ -101,7 +101,7 @@ public class BukkitChunk_1_9 extends CharFaweChunk<Chunk> {
|
||||
if (sectionPalettes != null) {
|
||||
return;
|
||||
}
|
||||
char[][] arrays = getIdArrays();
|
||||
char[][] arrays = getCombinedIdArrays();
|
||||
IBlockData lastBlock = null;
|
||||
char lastChar = Character.MAX_VALUE;
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
|
@ -2,7 +2,6 @@ package com.boydti.fawe.bukkit.v1_9;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -4,44 +4,50 @@ import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
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.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 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.LongTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import net.minecraft.server.v1_9_R1.Block;
|
||||
import net.minecraft.server.v1_9_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_9_R1.Blocks;
|
||||
import net.minecraft.server.v1_9_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_9_R1.DataBits;
|
||||
import net.minecraft.server.v1_9_R1.DataPalette;
|
||||
import net.minecraft.server.v1_9_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_9_R1.IBlockData;
|
||||
import net.minecraft.server.v1_9_R1.TileEntity;
|
||||
import org.bukkit.Bukkit;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import net.minecraft.server.v1_9_R2.Block;
|
||||
import net.minecraft.server.v1_9_R2.BlockPosition;
|
||||
import net.minecraft.server.v1_9_R2.Blocks;
|
||||
import net.minecraft.server.v1_9_R2.ChunkSection;
|
||||
import net.minecraft.server.v1_9_R2.DataBits;
|
||||
import net.minecraft.server.v1_9_R2.DataPalette;
|
||||
import net.minecraft.server.v1_9_R2.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_9_R2.Entity;
|
||||
import net.minecraft.server.v1_9_R2.EntityPlayer;
|
||||
import net.minecraft.server.v1_9_R2.EntityTypes;
|
||||
import net.minecraft.server.v1_9_R2.IBlockData;
|
||||
import net.minecraft.server.v1_9_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_9_R2.NibbleArray;
|
||||
import net.minecraft.server.v1_9_R2.TileEntity;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.v1_9_R1.CraftChunk;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.craftbukkit.v1_9_R2.CraftChunk;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
|
||||
public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], DataPaletteBlock> {
|
||||
|
||||
@ -53,9 +59,16 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
|
||||
Field fieldAir = DataPaletteBlock.class.getDeclaredField("a");
|
||||
fieldAir.setAccessible(true);
|
||||
air = (IBlockData) fieldAir.get(null);
|
||||
if (adapter == null) {
|
||||
setupAdapter(new FaweAdapter_1_9());
|
||||
Fawe.debug("=========================================");
|
||||
Fawe.debug("Using adapter: " + adapter);
|
||||
Fawe.debug("=========================================");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Player player = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -88,37 +101,47 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fixLighting(final FaweChunk pc, final boolean fixAll) {
|
||||
public boolean fixLighting(final FaweChunk pc, RelightMode mode) {
|
||||
try {
|
||||
final CharFaweChunk bc = (CharFaweChunk) pc;
|
||||
final Chunk chunk = (Chunk) bc.getChunk();
|
||||
CharFaweChunk bc = (CharFaweChunk) pc;
|
||||
Chunk chunk = (Chunk) bc.getChunk();
|
||||
if (!chunk.isLoaded()) {
|
||||
if (Fawe.get().getMainThread() != Thread.currentThread()) {
|
||||
return false;
|
||||
}
|
||||
chunk.load(false);
|
||||
}
|
||||
// Initialize lighting
|
||||
net.minecraft.server.v1_9_R1.Chunk c = ((CraftChunk) chunk).getHandle();
|
||||
net.minecraft.server.v1_9_R2.Chunk c = ((CraftChunk) chunk).getHandle();
|
||||
ChunkSection[] sections = c.getSections();
|
||||
if (mode != RelightMode.MINIMAL) {
|
||||
for (int i = 0; i < sections.length; i++) {
|
||||
ChunkSection section = sections[i];
|
||||
if (section != null) {
|
||||
if (mode == RelightMode.ALL) {
|
||||
section.a(new NibbleArray());
|
||||
}
|
||||
section.b(new NibbleArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
c.initLighting();
|
||||
|
||||
if (((bc.getTotalRelight() == 0) && !fixAll)) {
|
||||
if (((bc.getTotalRelight() == 0) && mode == RelightMode.MINIMAL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ChunkSection[] sections = c.getSections();
|
||||
net.minecraft.server.v1_9_R1.World w = c.world;
|
||||
|
||||
if (mode == RelightMode.ALL) {
|
||||
bc = getPrevious(bc, c.getSections(), null, null, null, true);
|
||||
}
|
||||
int total = bc.getTotalCount();
|
||||
net.minecraft.server.v1_9_R2.World w = c.world;
|
||||
final int X = chunk.getX() << 4;
|
||||
final int Z = chunk.getZ() << 4;
|
||||
|
||||
BlockPosition.MutableBlockPosition pos = new BlockPosition.MutableBlockPosition(0, 0, 0);
|
||||
for (int j = 0; j < sections.length; j++) {
|
||||
final Object section = sections[j];
|
||||
if (section == null) {
|
||||
continue;
|
||||
}
|
||||
if (((bc.getRelight(j) == 0) && !fixAll) || (bc.getCount(j) == 0) || ((bc.getCount(j) >= 4096) && (bc.getAir(j) == 0))) {
|
||||
if (((bc.getRelight(j) == 0) && mode == RelightMode.MINIMAL) || (bc.getCount(j) == 0 && mode != RelightMode.ALL) || ((bc.getCount(j) >= 4096) && (bc.getAir(j) == 0))) {
|
||||
continue;
|
||||
}
|
||||
final char[] array = bc.getIdArray(j);
|
||||
@ -136,7 +159,7 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
|
||||
case 0:
|
||||
continue;
|
||||
default:
|
||||
if (!fixAll) {
|
||||
if (mode == RelightMode.MINIMAL) {
|
||||
continue;
|
||||
}
|
||||
if ((k & 1) == l) {
|
||||
@ -161,7 +184,7 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
|
||||
final int x = FaweCache.CACHE_X[j][k];
|
||||
final int y = FaweCache.CACHE_Y[j][k];
|
||||
final int z = FaweCache.CACHE_Z[j][k];
|
||||
if (this.isSurrounded(bc.getIdArrays(), x, y, z)) {
|
||||
if (this.isSurrounded(bc.getCombinedIdArrays(), x, y, z)) {
|
||||
continue;
|
||||
}
|
||||
pos.c(X + x, y, Z + z);
|
||||
@ -249,62 +272,199 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setComponents(final FaweChunk pc, RunnableVal<FaweChunk> changeTask) {
|
||||
// TODO change task
|
||||
{
|
||||
// blah, stuff
|
||||
public CharFaweChunk getPrevious(CharFaweChunk fs, ChunkSection[] sections, Map<?, ?> tilesGeneric, Collection<?>[] entitiesGeneric, Set<UUID> createdEntities, boolean all) throws Exception {
|
||||
Map<BlockPosition, TileEntity> tiles = (Map<BlockPosition, TileEntity>) tilesGeneric;
|
||||
Collection<Entity>[] entities = (Collection<Entity>[]) entitiesGeneric;
|
||||
CharFaweChunk previous = (CharFaweChunk) getChunk(fs.getX(), fs.getZ());
|
||||
// Copy blocks
|
||||
char[][] idPrevious = new char[16][];
|
||||
for (int layer = 0; layer < sections.length; layer++) {
|
||||
if (fs.getCount(layer) != 0 || all) {
|
||||
ChunkSection section = sections[layer];
|
||||
if (section != null) {
|
||||
short solid = 0;
|
||||
char[] previousLayer = idPrevious[layer] = new char[4096];
|
||||
DataPaletteBlock blocks = section.getBlocks();
|
||||
for (int j = 0; j < 4096; j++) {
|
||||
int x = FaweCache.CACHE_X[0][j];
|
||||
int y = FaweCache.CACHE_Y[0][j];
|
||||
int z = FaweCache.CACHE_Z[0][j];
|
||||
IBlockData ibd = blocks.a(x, y, z);
|
||||
Block block = ibd.getBlock();
|
||||
int combined = Block.getId(block);
|
||||
if (FaweCache.hasData(combined)) {
|
||||
combined = (combined << 4) + block.toLegacyData(ibd);
|
||||
} else {
|
||||
combined = combined << 4;
|
||||
}
|
||||
if (combined > 1) {
|
||||
solid++;
|
||||
}
|
||||
previousLayer[j] = (char) combined;
|
||||
}
|
||||
previous.count[layer] = solid;
|
||||
previous.air[layer] = (short) (4096 - solid);
|
||||
}
|
||||
}
|
||||
}
|
||||
previous.ids = idPrevious;
|
||||
// Copy tiles
|
||||
if (tiles != null) {
|
||||
for (Map.Entry<BlockPosition, TileEntity> entry : tiles.entrySet()) {
|
||||
TileEntity tile = entry.getValue();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
tile.save(tag); // readTagIntoEntity
|
||||
BlockPosition pos = entry.getKey();
|
||||
CompoundTag nativeTag = (CompoundTag) methodToNative.invoke(adapter, tag);
|
||||
previous.setTile(pos.getX(), pos.getY(), pos.getZ(), nativeTag);
|
||||
}
|
||||
}
|
||||
// Copy entities
|
||||
if (entities != null) {
|
||||
for (Collection<Entity> entityList : entities) {
|
||||
for (Entity ent : entityList) {
|
||||
if (ent instanceof EntityPlayer || (!createdEntities.isEmpty() && !createdEntities.contains(ent.getUniqueID()))) {
|
||||
continue;
|
||||
}
|
||||
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); // readEntityIntoTag
|
||||
CompoundTag nativeTag = (CompoundTag) methodToNative.invoke(adapter, tag);
|
||||
Map<String, Tag> map = ReflectionUtils.getMap(nativeTag.getValue());
|
||||
map.put("Id", new StringTag(id));
|
||||
previous.setEntity(nativeTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return previous;
|
||||
}
|
||||
|
||||
final BukkitChunk_1_9 fs = (BukkitChunk_1_9) pc;
|
||||
@Override
|
||||
public boolean setComponents(final FaweChunk fc, RunnableVal<FaweChunk> changeTask) {
|
||||
final BukkitChunk_1_9 fs = (BukkitChunk_1_9) fc;
|
||||
final Chunk chunk = (Chunk) fs.getChunk();
|
||||
final World world = chunk.getWorld();
|
||||
chunk.load(true);
|
||||
try {
|
||||
final boolean flag = world.getEnvironment() == Environment.NORMAL;
|
||||
|
||||
// Sections
|
||||
net.minecraft.server.v1_9_R1.Chunk c = ((CraftChunk) chunk).getHandle();
|
||||
net.minecraft.server.v1_9_R1.World w = c.world;
|
||||
ChunkSection[] sections = c.getSections();
|
||||
|
||||
Class<? extends net.minecraft.server.v1_9_R1.Chunk> clazzChunk = c.getClass();
|
||||
net.minecraft.server.v1_9_R2.Chunk nmsChunk = ((CraftChunk) chunk).getHandle();
|
||||
net.minecraft.server.v1_9_R2.World nmsWorld = nmsChunk.world;
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
Class<? extends net.minecraft.server.v1_9_R2.Chunk> clazzChunk = nmsChunk.getClass();
|
||||
final Field ef = clazzChunk.getDeclaredField("entitySlices");
|
||||
final Collection<?>[] entities = (Collection<?>[]) ef.get(c);
|
||||
|
||||
// Trim tiles
|
||||
boolean removed = false;
|
||||
Map<BlockPosition, TileEntity> tiles = c.getTileEntities();
|
||||
if (fs.getTotalCount() >= 65536) {
|
||||
tiles.clear();
|
||||
removed = true;
|
||||
final Collection<Entity>[] entities = (Collection<Entity>[]) ef.get(nmsChunk);
|
||||
Map<BlockPosition, TileEntity> tiles = nmsChunk.getTileEntities();
|
||||
// Remove entities
|
||||
for (int i = 0; i < entities.length; i++) {
|
||||
int count = fs.getCount(i);
|
||||
if (count == 0) {
|
||||
continue;
|
||||
} else if (count >= 4096) {
|
||||
entities[i].clear();
|
||||
} else {
|
||||
Iterator<Entry<BlockPosition, TileEntity>> iter = tiles.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Entry<BlockPosition, TileEntity> tile = iter.next();
|
||||
char[] array = fs.getIdArray(i);
|
||||
Collection<Entity> ents = new ArrayList<>(entities[i]);
|
||||
for (Entity entity : ents) {
|
||||
if (entity instanceof EntityPlayer) {
|
||||
continue;
|
||||
}
|
||||
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 || y < 0 || y > 255) {
|
||||
continue;
|
||||
}
|
||||
int j = FaweCache.CACHE_J[y][x][z];
|
||||
if (array[j] != 0) {
|
||||
nmsWorld.removeEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
HashSet<UUID> entsToRemove = fs.getEntityRemoves();
|
||||
if (entsToRemove.size() > 0) {
|
||||
for (int i = 0; i < entities.length; i++) {
|
||||
Collection<Entity> ents = new ArrayList<>(entities[i]);
|
||||
for (Entity entity : ents) {
|
||||
if (entsToRemove.contains(entity.getUniqueID())) {
|
||||
nmsWorld.removeEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set entities
|
||||
Set<UUID> createdEntities = new HashSet<>();
|
||||
Set<CompoundTag> entitiesToSpawn = fs.getEntities();
|
||||
for (CompoundTag nativeTag : entitiesToSpawn) {
|
||||
Map<String, Tag> entityTagMap = ReflectionUtils.getMap(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) {
|
||||
UUID uuid = entity.getUniqueID();
|
||||
entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits()));
|
||||
entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits()));
|
||||
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);
|
||||
createdEntities.add(entity.getUniqueID());
|
||||
}
|
||||
}
|
||||
// Change task?
|
||||
if (changeTask != null) {
|
||||
CharFaweChunk previous = getPrevious(fs, sections, tiles, entities, createdEntities, false);
|
||||
changeTask.run(previous);
|
||||
}
|
||||
// Trim tiles
|
||||
Set<Entry<BlockPosition, TileEntity>> entryset = tiles.entrySet();
|
||||
Iterator<Map.Entry<BlockPosition, TileEntity>> iterator = entryset.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<BlockPosition, TileEntity> tile = iterator.next();
|
||||
BlockPosition pos = tile.getKey();
|
||||
final int lx = pos.getX() & 15;
|
||||
final int ly = pos.getY();
|
||||
final int lz = pos.getZ() & 15;
|
||||
final int j = FaweCache.CACHE_I[ly][lx][lz];
|
||||
final int k = FaweCache.CACHE_J[ly][lx][lz];
|
||||
final char[] array = fs.getIdArray(j);
|
||||
int lx = pos.getX() & 15;
|
||||
int ly = pos.getY();
|
||||
int lz = pos.getZ() & 15;
|
||||
int j = FaweCache.CACHE_I[ly][lx][lz];
|
||||
char[] array = fs.getIdArray(j);
|
||||
if (array == null) {
|
||||
continue;
|
||||
}
|
||||
int k = FaweCache.CACHE_J[ly][lx][lz];
|
||||
if (array[k] != 0) {
|
||||
removed = true;
|
||||
iter.remove();
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trim entities
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if ((entities[i] != null) && (fs.getCount(i) >= 4096)) {
|
||||
entities[i].clear();
|
||||
}
|
||||
}
|
||||
// Efficiently merge sections
|
||||
// Set blocks
|
||||
for (int j = 0; j < sections.length; j++) {
|
||||
int count = fs.getCount(j);
|
||||
if (count == 0) {
|
||||
@ -367,7 +527,38 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
|
||||
}
|
||||
setCount(0, nonEmptyBlockCount, section);
|
||||
}
|
||||
// Clear
|
||||
// Set biomes
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
nmsChunk.getBiomeIndex()[((z & 0xF) << 4 | x & 0xF)] = (byte) biome;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set tiles
|
||||
Map<BytePair, CompoundTag> tilesToSpawn = fs.getTiles();
|
||||
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();
|
||||
BlockPosition pos = new BlockPosition(MathMan.unpair16x(pair.pair[0]) + bx, pair.pair[1] & 0xFF, MathMan.unpair16y(pair.pair[0]) + bz); // Set pos
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||
if (tileEntity != null) {
|
||||
NBTTagCompound tag = (NBTTagCompound) methodFromNative.invoke(adapter, nativeTag);
|
||||
tileEntity.a(tag); // ReadTagIntoTile
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -392,117 +583,9 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when the server is < 1% available memory (i.e. likely to crash)<br>
|
||||
* - You can disable this in the conifg<br>
|
||||
* - Will try to free up some memory<br>
|
||||
* - Clears the queue<br>
|
||||
* - Clears worldedit history<br>
|
||||
* - Clears entities<br>
|
||||
* - Unloads chunks in vacant worlds<br>
|
||||
* - Unloads non visible chunks<br>
|
||||
*/
|
||||
@Override
|
||||
public void saveMemory() {
|
||||
super.saveMemory();
|
||||
// Clear the queue
|
||||
super.clear();
|
||||
ArrayDeque<Chunk> toUnload = new ArrayDeque<>();
|
||||
final int distance = Bukkit.getViewDistance() + 2;
|
||||
HashMap<String, HashMap<IntegerPair, Integer>> players = new HashMap<>();
|
||||
for (final Player player : Bukkit.getOnlinePlayers()) {
|
||||
// Clear history
|
||||
final FawePlayer<Object> fp = FawePlayer.wrap(player);
|
||||
final LocalSession s = fp.getSession();
|
||||
if (s != null) {
|
||||
s.clearHistory();
|
||||
s.setClipboard(null);
|
||||
}
|
||||
final Location loc = player.getLocation();
|
||||
final World worldObj = loc.getWorld();
|
||||
final String world = worldObj.getName();
|
||||
HashMap<IntegerPair, Integer> map = players.get(world);
|
||||
if (map == null) {
|
||||
map = new HashMap<>();
|
||||
players.put(world, map);
|
||||
}
|
||||
final IntegerPair origin = new IntegerPair(loc.getBlockX() >> 4, loc.getBlockZ() >> 4);
|
||||
Integer val = map.get(origin);
|
||||
int check;
|
||||
if (val != null) {
|
||||
if (val == distance) {
|
||||
continue;
|
||||
}
|
||||
check = distance - val;
|
||||
} else {
|
||||
check = distance;
|
||||
map.put(origin, distance);
|
||||
}
|
||||
for (int x = -distance; x <= distance; x++) {
|
||||
if ((x >= check) || (-x >= check)) {
|
||||
continue;
|
||||
}
|
||||
for (int z = -distance; z <= distance; z++) {
|
||||
if ((z >= check) || (-z >= check)) {
|
||||
continue;
|
||||
}
|
||||
final int weight = distance - Math.max(Math.abs(x), Math.abs(z));
|
||||
final IntegerPair chunk = new IntegerPair(x + origin.x, z + origin.z);
|
||||
val = map.get(chunk);
|
||||
if ((val == null) || (val < weight)) {
|
||||
map.put(chunk, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Fawe.get().getWorldEdit().clearSessions();
|
||||
for (final World world : Bukkit.getWorlds()) {
|
||||
final String name = world.getName();
|
||||
final HashMap<IntegerPair, Integer> map = players.get(name);
|
||||
if ((map == null) || (map.size() == 0)) {
|
||||
final boolean save = world.isAutoSave();
|
||||
world.setAutoSave(false);
|
||||
for (final Chunk chunk : world.getLoadedChunks()) {
|
||||
this.unloadChunk(name, chunk);
|
||||
}
|
||||
world.setAutoSave(save);
|
||||
continue;
|
||||
}
|
||||
final Chunk[] chunks = world.getLoadedChunks();
|
||||
for (final Chunk chunk : chunks) {
|
||||
final int x = chunk.getX();
|
||||
final int z = chunk.getZ();
|
||||
if (!map.containsKey(new IntegerPair(x, z))) {
|
||||
toUnload.add(chunk);
|
||||
} else if (chunk.getEntities().length > 4096) {
|
||||
for (final Entity ent : chunk.getEntities()) {
|
||||
ent.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// GC again
|
||||
System.gc();
|
||||
System.gc();
|
||||
// If still critical memory
|
||||
int free = MemUtil.calculateMemory();
|
||||
if (free <= 1) {
|
||||
for (final Chunk chunk : toUnload) {
|
||||
this.unloadChunk(chunk.getWorld().getName(), chunk);
|
||||
}
|
||||
} else if (free == Integer.MAX_VALUE) {
|
||||
for (final Chunk chunk : toUnload) {
|
||||
chunk.unload(true, false);
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
toUnload = null;
|
||||
players = null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean unloadChunk(final String world, final Chunk chunk) {
|
||||
net.minecraft.server.v1_9_R1.Chunk c = ((CraftChunk) chunk).getHandle();
|
||||
net.minecraft.server.v1_9_R2.Chunk c = ((CraftChunk) chunk).getHandle();
|
||||
c.mustSave = false;
|
||||
if (chunk.isLoaded()) {
|
||||
chunk.unload(false, false);
|
||||
@ -510,133 +593,6 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
|
||||
return true;
|
||||
}
|
||||
|
||||
public ChunkGenerator setGenerator(final World world, final ChunkGenerator newGen) {
|
||||
try {
|
||||
final ChunkGenerator gen = world.getGenerator();
|
||||
final Class<? extends World> clazz = world.getClass();
|
||||
final Field generator = clazz.getDeclaredField("generator");
|
||||
generator.setAccessible(true);
|
||||
generator.set(world, newGen);
|
||||
|
||||
final Field wf = clazz.getDeclaredField("world");
|
||||
wf.setAccessible(true);
|
||||
final Object w = wf.get(world);
|
||||
final Class<?> clazz2 = w.getClass().getSuperclass();
|
||||
final Field generator2 = clazz2.getDeclaredField("generator");
|
||||
generator2.set(w, newGen);
|
||||
|
||||
return gen;
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<BlockPopulator> setPopulator(final World world, final List<BlockPopulator> newPop) {
|
||||
try {
|
||||
final List<BlockPopulator> pop = world.getPopulators();
|
||||
final Field populators = world.getClass().getDeclaredField("populators");
|
||||
populators.setAccessible(true);
|
||||
populators.set(world, newPop);
|
||||
return pop;
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setEntitiesAndTiles(final Chunk chunk, final List<?>[] entities, final Map<?, ?> tiles) {
|
||||
try {
|
||||
final Class<? extends Chunk> clazz = chunk.getClass();
|
||||
final Method handle = clazz.getMethod("getHandle");
|
||||
final Object c = handle.invoke(chunk);
|
||||
final Class<? extends Object> clazz2 = c.getClass();
|
||||
|
||||
if (tiles.size() > 0) {
|
||||
final Field tef = clazz2.getDeclaredField("tileEntities");
|
||||
final Map<?, ?> te = (Map<?, ?>) tef.get(c);
|
||||
final Method put = te.getClass().getMethod("putAll", Map.class);
|
||||
put.invoke(te, tiles);
|
||||
}
|
||||
|
||||
final Field esf = clazz2.getDeclaredField("entitySlices");
|
||||
esf.setAccessible(true);
|
||||
esf.set(c, entities);
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public Object getProvider(final World world) {
|
||||
try {
|
||||
// Provider 1
|
||||
final Class<? extends World> clazz = world.getClass();
|
||||
final Field wf = clazz.getDeclaredField("world");
|
||||
wf.setAccessible(true);
|
||||
final Object w = wf.get(world);
|
||||
final Field provider = w.getClass().getSuperclass().getDeclaredField("chunkProvider");
|
||||
provider.setAccessible(true);
|
||||
// ChunkProviderServer
|
||||
final Class<? extends Object> clazz2 = w.getClass();
|
||||
final Field wpsf = clazz2.getDeclaredField("chunkProviderServer");
|
||||
// Store old provider server
|
||||
final Object worldProviderServer = wpsf.get(w);
|
||||
// Store the old provider
|
||||
final Field cp = worldProviderServer.getClass().getDeclaredField("chunkProvider");
|
||||
return cp.get(worldProviderServer);
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object setProvider(final World world, Object newProvider) {
|
||||
try {
|
||||
// Provider 1
|
||||
final Class<? extends World> clazz = world.getClass();
|
||||
final Field wf = clazz.getDeclaredField("world");
|
||||
wf.setAccessible(true);
|
||||
final Object w = wf.get(world);
|
||||
// ChunkProviderServer
|
||||
final Class<? extends Object> clazz2 = w.getClass();
|
||||
final Field wpsf = clazz2.getDeclaredField("chunkProviderServer");
|
||||
// Store old provider server
|
||||
final Object worldProviderServer = wpsf.get(w);
|
||||
// Store the old provider
|
||||
final Field cp = worldProviderServer.getClass().getDeclaredField("chunkProvider");
|
||||
final Object oldProvider = cp.get(worldProviderServer);
|
||||
// Provider 2
|
||||
final Class<? extends Object> clazz3 = worldProviderServer.getClass();
|
||||
final Field provider2 = clazz3.getDeclaredField("chunkProvider");
|
||||
// If the provider needs to be calculated
|
||||
if (newProvider == null) {
|
||||
Method k;
|
||||
try {
|
||||
k = clazz2.getDeclaredMethod("k");
|
||||
} catch (final Throwable e) {
|
||||
try {
|
||||
k = clazz2.getDeclaredMethod("j");
|
||||
} catch (final Throwable e2) {
|
||||
e2.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
k.setAccessible(true);
|
||||
final Object tempProviderServer = k.invoke(w);
|
||||
newProvider = cp.get(tempProviderServer);
|
||||
// Restore old provider
|
||||
wpsf.set(w, worldProviderServer);
|
||||
}
|
||||
// Set provider for provider server
|
||||
provider2.set(worldProviderServer, newProvider);
|
||||
// Return the previous provider
|
||||
return oldProvider;
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweChunk getChunk(int x, int z) {
|
||||
return new BukkitChunk_1_9(this, x, z);
|
||||
|
@ -0,0 +1,373 @@
|
||||
package com.boydti.fawe.bukkit.v1_9;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.sk89q.jnbt.ByteArrayTag;
|
||||
import com.sk89q.jnbt.ByteTag;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.DoubleTag;
|
||||
import com.sk89q.jnbt.EndTag;
|
||||
import com.sk89q.jnbt.FloatTag;
|
||||
import com.sk89q.jnbt.IntArrayTag;
|
||||
import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.LongTag;
|
||||
import com.sk89q.jnbt.NBTConstants;
|
||||
import com.sk89q.jnbt.ShortTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.server.v1_9_R2.BiomeBase;
|
||||
import net.minecraft.server.v1_9_R2.BlockPosition;
|
||||
import net.minecraft.server.v1_9_R2.EntityTypes;
|
||||
import net.minecraft.server.v1_9_R2.NBTBase;
|
||||
import net.minecraft.server.v1_9_R2.NBTTagByte;
|
||||
import net.minecraft.server.v1_9_R2.NBTTagByteArray;
|
||||
import net.minecraft.server.v1_9_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_9_R2.NBTTagDouble;
|
||||
import net.minecraft.server.v1_9_R2.NBTTagEnd;
|
||||
import net.minecraft.server.v1_9_R2.NBTTagFloat;
|
||||
import net.minecraft.server.v1_9_R2.NBTTagInt;
|
||||
import net.minecraft.server.v1_9_R2.NBTTagIntArray;
|
||||
import net.minecraft.server.v1_9_R2.NBTTagList;
|
||||
import net.minecraft.server.v1_9_R2.NBTTagLong;
|
||||
import net.minecraft.server.v1_9_R2.NBTTagShort;
|
||||
import net.minecraft.server.v1_9_R2.NBTTagString;
|
||||
import net.minecraft.server.v1_9_R2.TileEntity;
|
||||
import net.minecraft.server.v1_9_R2.World;
|
||||
import net.minecraft.server.v1_9_R2.WorldServer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.craftbukkit.v1_9_R2.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_9_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_9_R2.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.v1_9_R2.entity.CraftEntity;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
|
||||
public final class FaweAdapter_1_9 implements BukkitImplAdapter
|
||||
{
|
||||
private final Logger logger = Logger.getLogger(getClass().getCanonicalName());
|
||||
private final Field nbtListTagListField;
|
||||
private final Method nbtCreateTagMethod;
|
||||
|
||||
public FaweAdapter_1_9()
|
||||
throws NoSuchFieldException, NoSuchMethodException
|
||||
{
|
||||
CraftServer.class.cast(Bukkit.getServer());
|
||||
|
||||
this.nbtListTagListField = NBTTagList.class.getDeclaredField("list");
|
||||
this.nbtListTagListField.setAccessible(true);
|
||||
|
||||
this.nbtCreateTagMethod = NBTBase.class.getDeclaredMethod("createTag", new Class[] { Byte.TYPE });
|
||||
this.nbtCreateTagMethod.setAccessible(true);
|
||||
}
|
||||
|
||||
private static void readTagIntoTileEntity(NBTTagCompound tag, TileEntity tileEntity)
|
||||
{
|
||||
tileEntity.a(tag);
|
||||
}
|
||||
|
||||
private static void readTileEntityIntoTag(TileEntity tileEntity, NBTTagCompound tag)
|
||||
{
|
||||
tileEntity.save(tag);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getEntityId(net.minecraft.server.v1_9_R2.Entity entity)
|
||||
{
|
||||
return EntityTypes.b(entity);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static net.minecraft.server.v1_9_R2.Entity createEntityFromId(String id, World world)
|
||||
{
|
||||
return EntityTypes.createEntityByName(id, world);
|
||||
}
|
||||
|
||||
private static void readTagIntoEntity(NBTTagCompound tag, net.minecraft.server.v1_9_R2.Entity entity)
|
||||
{
|
||||
entity.f(tag);
|
||||
}
|
||||
|
||||
private static void readEntityIntoTag(net.minecraft.server.v1_9_R2.Entity entity, NBTTagCompound tag)
|
||||
{
|
||||
entity.e(tag);
|
||||
}
|
||||
|
||||
public int getBlockId(Material material)
|
||||
{
|
||||
return material.getId();
|
||||
}
|
||||
|
||||
public Material getMaterial(int id)
|
||||
{
|
||||
return Material.getMaterial(id);
|
||||
}
|
||||
|
||||
public int getBiomeId(Biome biome)
|
||||
{
|
||||
BiomeBase mcBiome = CraftBlock.biomeToBiomeBase(biome);
|
||||
return mcBiome != null ? BiomeBase.a(mcBiome) : 0;
|
||||
}
|
||||
|
||||
public Biome getBiome(int id)
|
||||
{
|
||||
BiomeBase mcBiome = BiomeBase.getBiome(id);
|
||||
return CraftBlock.biomeBaseToBiome(mcBiome);
|
||||
}
|
||||
|
||||
public BaseBlock getBlock(Location location)
|
||||
{
|
||||
Preconditions.checkNotNull(location);
|
||||
|
||||
CraftWorld craftWorld = (CraftWorld)location.getWorld();
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
|
||||
Block bukkitBlock = location.getBlock();
|
||||
BaseBlock block = new BaseBlock(bukkitBlock.getTypeId(), bukkitBlock.getData());
|
||||
|
||||
TileEntity te = craftWorld.getHandle().getTileEntity(new BlockPosition(x, y, z));
|
||||
if (te != null)
|
||||
{
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
readTileEntityIntoTag(te, tag);
|
||||
block.setNbtData((CompoundTag)toNative(tag));
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
public boolean setBlock(Location location, BaseBlock block, boolean notifyAndLight)
|
||||
{
|
||||
Preconditions.checkNotNull(location);
|
||||
Preconditions.checkNotNull(block);
|
||||
|
||||
CraftWorld craftWorld = (CraftWorld)location.getWorld();
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
|
||||
boolean changed = location.getBlock().setTypeIdAndData(block.getId(), (byte)block.getData(), notifyAndLight);
|
||||
|
||||
CompoundTag nativeTag = block.getNbtData();
|
||||
if (nativeTag != null)
|
||||
{
|
||||
TileEntity tileEntity = craftWorld.getHandle().getTileEntity(new BlockPosition(x, y, z));
|
||||
if (tileEntity != null)
|
||||
{
|
||||
NBTTagCompound tag = (NBTTagCompound)fromNative(nativeTag);
|
||||
tag.set("x", new NBTTagInt(x));
|
||||
tag.set("y", new NBTTagInt(y));
|
||||
tag.set("z", new NBTTagInt(z));
|
||||
readTagIntoTileEntity(tag, tileEntity);
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
public BaseEntity getEntity(org.bukkit.entity.Entity entity)
|
||||
{
|
||||
Preconditions.checkNotNull(entity);
|
||||
|
||||
CraftEntity craftEntity = (CraftEntity)entity;
|
||||
net.minecraft.server.v1_9_R2.Entity mcEntity = craftEntity.getHandle();
|
||||
|
||||
String id = getEntityId(mcEntity);
|
||||
if (id != null)
|
||||
{
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
readEntityIntoTag(mcEntity, tag);
|
||||
return new BaseEntity(id, (CompoundTag)toNative(tag));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state)
|
||||
{
|
||||
Preconditions.checkNotNull(location);
|
||||
Preconditions.checkNotNull(state);
|
||||
|
||||
CraftWorld craftWorld = (CraftWorld)location.getWorld();
|
||||
WorldServer worldServer = craftWorld.getHandle();
|
||||
|
||||
net.minecraft.server.v1_9_R2.Entity createdEntity = createEntityFromId(state.getTypeId(), craftWorld.getHandle());
|
||||
if (createdEntity != null)
|
||||
{
|
||||
CompoundTag nativeTag = state.getNbtData();
|
||||
if (nativeTag != null)
|
||||
{
|
||||
NBTTagCompound tag = (NBTTagCompound)fromNative(nativeTag);
|
||||
for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||
tag.remove(name);
|
||||
}
|
||||
readTagIntoEntity(tag, createdEntity);
|
||||
}
|
||||
createdEntity.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
|
||||
|
||||
worldServer.addEntity(createdEntity, CreatureSpawnEvent.SpawnReason.CUSTOM);
|
||||
return createdEntity.getBukkitEntity();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Tag toNative(NBTBase foreign)
|
||||
{
|
||||
if (foreign == null) {
|
||||
return null;
|
||||
}
|
||||
if ((foreign instanceof NBTTagCompound))
|
||||
{
|
||||
Map<String, Tag> values = new HashMap();
|
||||
Set<String> foreignKeys = ((NBTTagCompound)foreign).c();
|
||||
for (String str : foreignKeys)
|
||||
{
|
||||
NBTBase base = ((NBTTagCompound)foreign).get(str);
|
||||
values.put(str, toNative(base));
|
||||
}
|
||||
return new CompoundTag(values);
|
||||
}
|
||||
if ((foreign instanceof NBTTagByte)) {
|
||||
return new ByteTag(((NBTTagByte)foreign).f());
|
||||
}
|
||||
if ((foreign instanceof NBTTagByteArray)) {
|
||||
return new ByteArrayTag(((NBTTagByteArray)foreign).c());
|
||||
}
|
||||
if ((foreign instanceof NBTTagDouble)) {
|
||||
return new DoubleTag(((NBTTagDouble)foreign).g());
|
||||
}
|
||||
if ((foreign instanceof NBTTagFloat)) {
|
||||
return new FloatTag(((NBTTagFloat)foreign).h());
|
||||
}
|
||||
if ((foreign instanceof NBTTagInt)) {
|
||||
return new IntTag(((NBTTagInt)foreign).d());
|
||||
}
|
||||
if ((foreign instanceof NBTTagIntArray)) {
|
||||
return new IntArrayTag(((NBTTagIntArray)foreign).c());
|
||||
}
|
||||
if ((foreign instanceof NBTTagList)) {
|
||||
try
|
||||
{
|
||||
return toNativeList((NBTTagList)foreign);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
this.logger.log(Level.WARNING, "Failed to convert NBTTagList", e);
|
||||
return new ListTag(ByteTag.class, new ArrayList());
|
||||
}
|
||||
}
|
||||
if ((foreign instanceof NBTTagLong)) {
|
||||
return new LongTag(((NBTTagLong)foreign).c());
|
||||
}
|
||||
if ((foreign instanceof NBTTagShort)) {
|
||||
return new ShortTag(((NBTTagShort)foreign).e());
|
||||
}
|
||||
if ((foreign instanceof NBTTagString)) {
|
||||
return new StringTag(((NBTTagString)foreign).a_());
|
||||
}
|
||||
if ((foreign instanceof NBTTagEnd)) {
|
||||
return new EndTag();
|
||||
}
|
||||
throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName());
|
||||
}
|
||||
|
||||
private ListTag toNativeList(NBTTagList foreign)
|
||||
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException
|
||||
{
|
||||
List<Tag> values = new ArrayList();
|
||||
int type = foreign.d();
|
||||
|
||||
List foreignList = (List)this.nbtListTagListField.get(foreign);
|
||||
for (int i = 0; i < foreign.size(); i++)
|
||||
{
|
||||
NBTBase element = (NBTBase)foreignList.get(i);
|
||||
values.add(toNative(element));
|
||||
}
|
||||
Class<? extends Tag> cls = NBTConstants.getClassFromType(type);
|
||||
return new ListTag(cls, values);
|
||||
}
|
||||
|
||||
private NBTBase fromNative(Tag foreign)
|
||||
{
|
||||
if (foreign == null) {
|
||||
return null;
|
||||
}
|
||||
Map.Entry<String, Tag> entry;
|
||||
if ((foreign instanceof CompoundTag))
|
||||
{
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
for (Iterator localIterator = ((CompoundTag)foreign)
|
||||
.getValue().entrySet().iterator(); localIterator.hasNext();)
|
||||
{
|
||||
entry = (Map.Entry)localIterator.next();
|
||||
|
||||
tag.set((String)entry.getKey(), fromNative((Tag)entry.getValue()));
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
if ((foreign instanceof ByteTag)) {
|
||||
return new NBTTagByte(((ByteTag)foreign).getValue().byteValue());
|
||||
}
|
||||
if ((foreign instanceof ByteArrayTag)) {
|
||||
return new NBTTagByteArray(((ByteArrayTag)foreign).getValue());
|
||||
}
|
||||
if ((foreign instanceof DoubleTag)) {
|
||||
return new NBTTagDouble(((DoubleTag)foreign).getValue().doubleValue());
|
||||
}
|
||||
if ((foreign instanceof FloatTag)) {
|
||||
return new NBTTagFloat(((FloatTag)foreign).getValue().floatValue());
|
||||
}
|
||||
if ((foreign instanceof IntTag)) {
|
||||
return new NBTTagInt(((IntTag)foreign).getValue().intValue());
|
||||
}
|
||||
if ((foreign instanceof IntArrayTag)) {
|
||||
return new NBTTagIntArray(((IntArrayTag)foreign).getValue());
|
||||
}
|
||||
if ((foreign instanceof ListTag))
|
||||
{
|
||||
NBTTagList tag = new NBTTagList();
|
||||
ListTag foreignList = (ListTag)foreign;
|
||||
for (Tag t : foreignList.getValue()) {
|
||||
tag.add(fromNative(t));
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
if ((foreign instanceof LongTag)) {
|
||||
return new NBTTagLong(((LongTag)foreign).getValue().longValue());
|
||||
}
|
||||
if ((foreign instanceof ShortTag)) {
|
||||
return new NBTTagShort(((ShortTag)foreign).getValue().shortValue());
|
||||
}
|
||||
if ((foreign instanceof StringTag)) {
|
||||
return new NBTTagString(((StringTag)foreign).getValue());
|
||||
}
|
||||
if ((foreign instanceof EndTag)) {
|
||||
try
|
||||
{
|
||||
return (NBTBase)this.nbtCreateTagMethod.invoke(null, new Object[] { Byte.valueOf((byte) 0) });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
@ -21,9 +21,9 @@ commands:
|
||||
fawe:
|
||||
description: (FAWE) Reload the plugin
|
||||
aliases: [/fawe,/fawereload]
|
||||
wrg:
|
||||
select:
|
||||
description: (FAWE) Select your current WorldEdit Region.
|
||||
aliases: [/wrg,wer,/wer,worldeditregion,/worldeditregion,/region]
|
||||
aliases: [/select,wer,/wer,worldeditregion,/worldeditregion,/region]
|
||||
frb:
|
||||
description: (FAWE) Rollback an edit
|
||||
aliases: [fawerollback,fawerb,/uu,/rb,/frb,/fawerollback,/fawerb]
|
||||
|
@ -200,7 +200,7 @@ public class Fawe {
|
||||
this.IMP.setupCommand("wea", new Wea());
|
||||
this.IMP.setupCommand("fixlighting", new FixLighting());
|
||||
this.IMP.setupCommand("stream", new Stream());
|
||||
this.IMP.setupCommand("wrg", new WorldEditRegion());
|
||||
this.IMP.setupCommand("select", new WorldEditRegion());
|
||||
this.IMP.setupCommand("fawe", new Reload());
|
||||
this.IMP.setupCommand("frb", new Rollback());
|
||||
this.IMP.setupCommand("fcancel", new Cancel());
|
||||
|
@ -18,6 +18,7 @@ import com.sk89q.jnbt.IntTag;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.ShortTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
@ -39,6 +40,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import javax.annotation.Nonnull;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
|
||||
@ -51,6 +53,31 @@ import org.bukkit.Location;
|
||||
*/
|
||||
public class FaweAPI {
|
||||
|
||||
/**
|
||||
* Get a new EditSessionfor a player<br>
|
||||
* - The EditSession can be used from another thread<br>
|
||||
* - FAWE will handle
|
||||
* @see com.boydti.fawe.object.FawePlayer#wrap(Object)
|
||||
* @param player
|
||||
* @return
|
||||
*/
|
||||
public EditSession getNewEditSession(@Nonnull FawePlayer player) {
|
||||
if (player == null) {
|
||||
throw new IllegalArgumentException("Player may not be null");
|
||||
}
|
||||
return player.getNewEditSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new non-player EditSession
|
||||
* @see #getWorld(String)
|
||||
* @param world
|
||||
* @return
|
||||
*/
|
||||
public EditSession getNewEditSession(World world) {
|
||||
return WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* The TaskManager has some useful methods for doing things asynchronously
|
||||
* @return TaskManager
|
||||
@ -133,7 +160,7 @@ public class FaweAPI {
|
||||
* Cancel the edit with the following extent<br>
|
||||
* - The extent must be the one being used by an EditSession, otherwise an error may be thrown <br>
|
||||
* - Insert an extent into the EditSession using the EditSessionEvent: http://wiki.sk89q.com/wiki/WorldEdit/API/Hooking_EditSession <br>
|
||||
* @see com.sk89q.worldedit.EditSession#getFaweExtent() To get the FaweExtent for an EditSession
|
||||
* @see com.sk89q.worldedit.EditSession#getRegionExtent() To get the FaweExtent for an EditSession
|
||||
* @param extent
|
||||
* @param reason
|
||||
*/
|
||||
@ -229,7 +256,11 @@ public class FaweAPI {
|
||||
Collections.sort(files, new Comparator<File>() {
|
||||
@Override
|
||||
public int compare(File a, File b) {
|
||||
long value = a.lastModified() - b.lastModified();
|
||||
String aName = a.getName();
|
||||
String bName = b.getName();
|
||||
int aI = Integer.parseInt(aName.substring(0, aName.length() - 3));
|
||||
int bI = Integer.parseInt(bName.substring(0, bName.length() - 3));
|
||||
long value = aI - bI;
|
||||
return value == 0 ? 0 : value < 0 ? -1 : 1;
|
||||
}
|
||||
});
|
||||
@ -292,21 +323,21 @@ public class FaweAPI {
|
||||
* @param world
|
||||
* @param x
|
||||
* @param z
|
||||
* @param fixAll
|
||||
* @param mode
|
||||
*/
|
||||
public static void fixLighting(String world, int x, int z, final boolean fixAll) {
|
||||
public static void fixLighting(String world, int x, int z, FaweQueue.RelightMode mode) {
|
||||
FaweQueue queue = SetQueue.IMP.getNewQueue(world, true, false);
|
||||
queue.fixLighting(queue.getChunk(x, z), fixAll);
|
||||
queue.fixLighting(queue.getChunk(x, z), mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix the lighting in a chunk
|
||||
* @param chunk
|
||||
* @param fixAll
|
||||
* @param mode
|
||||
*/
|
||||
public static void fixLighting(final Chunk chunk, final boolean fixAll) {
|
||||
public static void fixLighting(final Chunk chunk, FaweQueue.RelightMode mode) {
|
||||
FaweQueue queue = SetQueue.IMP.getNewQueue(chunk.getWorld().getName(), true, false);
|
||||
queue.fixLighting(queue.getChunk(chunk.getX(), chunk.getZ()), fixAll);
|
||||
queue.fixLighting(queue.getChunk(chunk.getX(), chunk.getZ()), mode);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -318,6 +349,7 @@ public class FaweAPI {
|
||||
* @param loc
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public static void streamSchematic(final File file, final Location loc) {
|
||||
final FaweLocation fl = new FaweLocation(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
streamSchematic(file, fl);
|
||||
@ -331,6 +363,7 @@ public class FaweAPI {
|
||||
* @param loc
|
||||
* @return
|
||||
*/
|
||||
@Deprecated
|
||||
public static void streamSchematic(final File file, final FaweLocation loc) {
|
||||
try {
|
||||
final FileInputStream is = new FileInputStream(file);
|
||||
@ -347,6 +380,7 @@ public class FaweAPI {
|
||||
* @param url
|
||||
* @param loc
|
||||
*/
|
||||
@Deprecated
|
||||
public static void streamSchematic(final URL url, final FaweLocation loc) {
|
||||
try {
|
||||
final ReadableByteChannel rbc = Channels.newChannel(url.openStream());
|
||||
@ -366,6 +400,7 @@ public class FaweAPI {
|
||||
* @param loc
|
||||
* @throws IOException
|
||||
*/
|
||||
@Deprecated
|
||||
public static void streamSchematic(final InputStream is, final FaweLocation loc) throws IOException {
|
||||
final NBTInputStream stream = new NBTInputStream(new GZIPInputStream(is));
|
||||
Tag tag = stream.readNamedTag().getTag();
|
||||
@ -403,79 +438,10 @@ public class FaweAPI {
|
||||
final int i = i2 + x;
|
||||
final int xx = x_offset + x;
|
||||
final short id = (short) (ids[i] & 0xFF);
|
||||
switch (id) {
|
||||
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(xx, yy, zz, id, (byte) 0);
|
||||
break;
|
||||
default: {
|
||||
if (FaweCache.hasData(id)) {
|
||||
queue.setBlock(xx, yy, zz, id, datas[i]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
queue.setBlock(xx, yy, zz, id, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,26 +6,56 @@ import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
|
||||
public class FaweCache {
|
||||
/**
|
||||
* y | x | z
|
||||
* [ y | x | z ] => index
|
||||
*/
|
||||
public final static short[][][] CACHE_I = new short[256][16][16];
|
||||
/**
|
||||
* y | x | z
|
||||
* [ y | x | z ] => index
|
||||
*/
|
||||
public final static short[][][] CACHE_J = new short[256][16][16];
|
||||
|
||||
/**
|
||||
* [ i | j ] => x
|
||||
*/
|
||||
public final static byte[][] CACHE_X = new byte[16][4096];
|
||||
/**
|
||||
* [ i | j ] => y
|
||||
*/
|
||||
public final static short[][] CACHE_Y = new short[16][4096];
|
||||
/**
|
||||
* [ i | j ] => z
|
||||
*/
|
||||
public final static byte[][] CACHE_Z = new byte[16][4096];
|
||||
|
||||
/**
|
||||
* [ combined ] => id
|
||||
* (combined >> 4) = id
|
||||
*/
|
||||
public final static short[] CACHE_ID = new short[65535];
|
||||
/**
|
||||
* [ combined ] => data
|
||||
* (combined & 0xF) = data
|
||||
*/
|
||||
public final static byte[] CACHE_DATA = new byte[65535];
|
||||
|
||||
/**
|
||||
* Immutable BaseBlock cache
|
||||
* [ combined ] => block
|
||||
*/
|
||||
public final static BaseBlock[] CACHE_BLOCK = new BaseBlock[Short.MAX_VALUE];
|
||||
|
||||
// Faster than java random (since the game just needs to look random)
|
||||
/**
|
||||
* Faster than java random (since it just needs to look random)
|
||||
*/
|
||||
public final static PseudoRandom RANDOM = new PseudoRandom();
|
||||
|
||||
/**
|
||||
* Get the cached BaseBlock object for an id/data<br>
|
||||
* - The block is immutable
|
||||
* @param id
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
public static BaseBlock getBlock(int id, int data) {
|
||||
return CACHE_BLOCK[(id << 4) + data];
|
||||
}
|
||||
@ -85,6 +115,11 @@ public class FaweCache {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an id might have data
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public static boolean hasData(int id) {
|
||||
switch (id) {
|
||||
case 0:
|
||||
@ -168,6 +203,11 @@ public class FaweCache {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an id might have nbt
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public static boolean hasNBT(int id) {
|
||||
switch (id) {
|
||||
case 54:
|
||||
|
@ -28,7 +28,7 @@ public class Cancel extends FaweCommand {
|
||||
for (FaweQueue queue : queues) {
|
||||
Set<EditSession> sessions = queue.getEditSessions();
|
||||
for (EditSession session : sessions) {
|
||||
Actor actor = session.actor;
|
||||
Actor actor = session.getActor();
|
||||
if (actor == null) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2,11 +2,13 @@ package com.boydti.fawe.command;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweCommand;
|
||||
import com.boydti.fawe.object.FaweLocation;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
public class FixLighting extends FaweCommand {
|
||||
@ -21,27 +23,27 @@ public class FixLighting extends FaweCommand {
|
||||
return false;
|
||||
}
|
||||
final FaweLocation loc = player.getLocation();
|
||||
final Region selection = player.getSelection();
|
||||
if (selection == null) {
|
||||
FaweAPI.fixLighting(loc.world, loc.x >> 4, loc.z >> 4, Settings.FIX_ALL_LIGHTING);
|
||||
BBC.FIX_LIGHTING_CHUNK.send(player);
|
||||
return true;
|
||||
}
|
||||
final int cx = loc.x >> 4;
|
||||
final int cz = loc.z >> 4;
|
||||
|
||||
Region selection = player.getSelection();
|
||||
if (selection == null) {
|
||||
selection = new CuboidRegion(new Vector(cx - 8, 0, cz - 8).multiply(16), new Vector(cx + 8, 0, cz + 8).multiply(16));
|
||||
}
|
||||
final Vector bot = selection.getMinimumPoint();
|
||||
final Vector top = selection.getMaximumPoint();
|
||||
|
||||
final int minX = Math.max(cx - 8, bot.getBlockX() >> 4);
|
||||
final int minZ = Math.max(cz - 8, bot.getBlockZ() >> 4);
|
||||
final int minX = bot.getBlockX() >> 4;
|
||||
final int minZ = bot.getBlockZ() >> 4;
|
||||
|
||||
final int maxX = Math.min(cx + 8, top.getBlockX() >> 4);
|
||||
final int maxZ = Math.min(cz + 8, top.getBlockZ() >> 4);
|
||||
final int maxX = top.getBlockX() >> 4;
|
||||
final int maxZ = top.getBlockZ() >> 4;
|
||||
|
||||
int count = 0;
|
||||
FaweQueue queue = SetQueue.IMP.getNewQueue(loc.world, true, false);
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
FaweAPI.fixLighting(loc.world, x, z, Settings.FIX_ALL_LIGHTING);
|
||||
queue.fixLighting(queue.getChunk(x, z), FaweQueue.RelightMode.ALL);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.blocks.ItemType;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
@ -102,7 +101,7 @@ public class Rollback extends FaweCommand {
|
||||
EditSession session = edit.toEditSession(null);
|
||||
session.undo(session);
|
||||
edit.deleteFiles();
|
||||
SetQueue.IMP.addTask(this);
|
||||
session.getQueue().addNotifyTask(this);
|
||||
}
|
||||
};
|
||||
task.run();
|
||||
|
@ -17,7 +17,7 @@ public enum BBC {
|
||||
* Things to note about this class:
|
||||
* Can use multiple arguments %s, %s1, %s2, %s3 etc
|
||||
*/
|
||||
PREFIX("&8(&5&lFAWE&8)&7", "Info"),
|
||||
PREFIX("&8(&4&lFAWE&8)&7", "Info"),
|
||||
SCHEMATIC_PASTING("&7The schematic is pasting. This cannot be undone.", "Info"),
|
||||
FIX_LIGHTING_CHUNK("&7Lighting has been fixed in your current chunk. Relog to see the affect.", "Info"),
|
||||
FIX_LIGHTING_SELECTION("&7Lighting has been fixed in %s0 chunks. Relog to see the affect.", "Info"),
|
||||
@ -95,6 +95,8 @@ public enum BBC {
|
||||
SELECTOR_CUBOID_POS1("First position set to %s0 %s1.", "WorldEdit.Selector"),
|
||||
SELECTOR_CUBOID_POS2("Second position set to %s0 %s1.", "WorldEdit.Selector"),
|
||||
|
||||
PROGRESS_MESSAGE("[ Queue: %s0 | Dispatched: %s1 ]", "Progress"),
|
||||
PROGRESS_DONE ("[ Took: %s0s ]", "Progress"),
|
||||
|
||||
|
||||
COMMAND_SYNTAX("&cUsage: &7%s0", "Error"),
|
||||
|
@ -14,33 +14,37 @@ import java.util.Map.Entry;
|
||||
|
||||
public class Settings {
|
||||
|
||||
// public static boolean REQUIRE_SELECTION = false;
|
||||
// public static boolean COMMAND_PROCESSOR = false;
|
||||
// public static List<String> WE_BLACKLIST = Arrays.asList("cs", ".s", "restore", "snapshot", "delchunks", "listchunks");
|
||||
public static long MEM_FREE = 95;
|
||||
public static boolean ENABLE_HARD_LIMIT = true;
|
||||
public static boolean STORE_HISTORY_ON_DISK = false;
|
||||
public static boolean STORE_CLIPBOARD_ON_DISK = false;
|
||||
public static int DELETE_HISTORY_AFTER_DAYS = 7;
|
||||
public static boolean CLEAN_HISTORY_ON_LOGOUT = true;
|
||||
public static int DELETE_CLIPBOARD_AFTER_DAYS = 1;
|
||||
public static int COMPRESSION_LEVEL = 0;
|
||||
public static int BUFFER_SIZE = 531441;
|
||||
public static boolean METRICS = true;
|
||||
public static int CHUNK_WAIT = 100;
|
||||
public static boolean REGION_RESTRICTIONS = true;
|
||||
public static int ALLOCATE = 0;
|
||||
public static int QUEUE_SIZE = 64;
|
||||
public static int QUEUE_MAX_WAIT = 1000;
|
||||
public static int QUEUE_DISCARD_AFTER = 60000;
|
||||
public static boolean DISPLAY_PROGRESS = false;
|
||||
public static int DISPLAY_PROGRESS_INTERVAL = 1;
|
||||
public static List<String> ALLOWED_3RDPARTY_EXTENTS;
|
||||
public static boolean EXTENT_DEBUG = true;
|
||||
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 = 500000;
|
||||
public static int ITEMS_PER_TICK = 50000;
|
||||
|
||||
public static boolean COMBINE_HISTORY_STAGE = true;
|
||||
// Maybe confusing?
|
||||
// - `compression: false` just uses cheaper compression, but still compresses
|
||||
public static int COMPRESSION_LEVEL = 0;
|
||||
public static boolean COMBINE_HISTORY_STAGE = false;
|
||||
public static int PARALLEL_THREADS = 1;
|
||||
|
||||
// Non configurable (yet / shouldn't be?)
|
||||
public static int BUFFER_SIZE = 531441;
|
||||
public static int QUEUE_DISCARD_AFTER = 60000;
|
||||
|
||||
public static HashMap<String, FaweLimit> limits;
|
||||
|
||||
@ -77,13 +81,11 @@ public class Settings {
|
||||
}
|
||||
}
|
||||
final YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
|
||||
config.set("DOCUMENTATION","https://github.com/boy0001/FastAsyncWorldedit/wiki/Configuration");
|
||||
|
||||
limits = new HashMap<>();
|
||||
|
||||
final Map<String, Object> options = new HashMap<>();
|
||||
// options.put("require-selection-in-mask", REQUIRE_SELECTION);
|
||||
// options.put("command-blacklist", WE_BLACKLIST);
|
||||
// options.put("command-processor", COMMAND_PROCESSOR);
|
||||
options.put("max-memory-percent", MEM_FREE);
|
||||
options.put("crash-mitigation", ENABLE_HARD_LIMIT);
|
||||
options.put("lighting.fix-all", FIX_ALL_LIGHTING);
|
||||
@ -93,18 +95,22 @@ public class Settings {
|
||||
options.put("history.use-disk", STORE_HISTORY_ON_DISK);
|
||||
options.put("history.compress", false);
|
||||
options.put("history.chunk-wait-ms", CHUNK_WAIT);
|
||||
// options.put("history.buffer-size", BUFFER_SIZE);
|
||||
options.put("history.delete-after-days", DELETE_HISTORY_AFTER_DAYS);
|
||||
options.put("history.delete-on-logout", CLEAN_HISTORY_ON_LOGOUT);
|
||||
options.put("region-restrictions", REGION_RESTRICTIONS);
|
||||
options.put("queue.parallel-threads", UNSAFE_PARALLEL_THREADS);
|
||||
options.put("queue.extra-time-ms", ALLOCATE);
|
||||
options.put("queue.progress.display", DISPLAY_PROGRESS);
|
||||
options.put("queue.progress.interval", DISPLAY_PROGRESS_INTERVAL);
|
||||
options.put("queue.target-size", QUEUE_SIZE);
|
||||
options.put("queue.max-wait-ms", QUEUE_MAX_WAIT);
|
||||
// options.put("queue.discard-after-ms", QUEUE_DISCARD_AFTER);
|
||||
options.put("extent.allowed-plugins", new ArrayList<String>());
|
||||
options.put("extent.debug", EXTENT_DEBUG);
|
||||
options.put("metrics", METRICS);
|
||||
|
||||
// Possibly confusing? - leave configurable since not entirely stable yet
|
||||
options.put("history.combine-stages", COMBINE_HISTORY_STAGE);
|
||||
options.put("queue.parallel-threads", Math.max(1, Runtime.getRuntime().availableProcessors()));
|
||||
|
||||
if (config.getInt("tick-limiter.physics") == 1337) {
|
||||
config.set("tick-limiter.physics", PHYSICS_PER_TICK);
|
||||
}
|
||||
@ -130,21 +136,19 @@ public class Settings {
|
||||
FIX_ALL_LIGHTING = config.getBoolean("lighting.fix-all");
|
||||
ASYNC_LIGHTING = config.getBoolean("lighting.async");
|
||||
MEM_FREE = config.getInt("max-memory-percent");
|
||||
// COMMAND_PROCESSOR = config.getBoolean("command-processor");
|
||||
// REQUIRE_SELECTION = config.getBoolean("require-selection-in-mask");
|
||||
// WE_BLACKLIST = config.getStringList("command-blacklist");
|
||||
ENABLE_HARD_LIMIT = config.getBoolean("crash-mitigation");
|
||||
REGION_RESTRICTIONS = config.getBoolean("region-restrictions");
|
||||
METRICS = config.getBoolean("metrics");
|
||||
COMPRESSION_LEVEL = config.getInt("history.compression-level", config.getBoolean("history.compress") ? 1 : 0);
|
||||
DELETE_HISTORY_AFTER_DAYS = config.getInt("history.delete-after-days");
|
||||
BUFFER_SIZE = config.getInt("history.buffer-size", BUFFER_SIZE);
|
||||
CLEAN_HISTORY_ON_LOGOUT = config.getBoolean("history.delete-on-logout");
|
||||
CHUNK_WAIT = config.getInt("history.chunk-wait-ms");
|
||||
ALLOCATE = config.getInt("queue.extra-time-ms");
|
||||
QUEUE_SIZE = config.getInt("queue.target-size");
|
||||
QUEUE_MAX_WAIT = config.getInt("queue.max-wait-ms");
|
||||
UNSAFE_PARALLEL_THREADS = config.getInt("queue.parallel-threads");
|
||||
QUEUE_DISCARD_AFTER = config.getInt("queue.discard-after-ms", QUEUE_DISCARD_AFTER);
|
||||
DISPLAY_PROGRESS = config.getBoolean("queue.progress.display");
|
||||
DISPLAY_PROGRESS_INTERVAL = config.getInt("queue.progress.interval");
|
||||
PARALLEL_THREADS = config.getInt("queue.parallel-threads", Math.max(1, Runtime.getRuntime().availableProcessors()));
|
||||
ALLOWED_3RDPARTY_EXTENTS = config.getStringList("extent.allowed-plugins");
|
||||
EXTENT_DEBUG = config.getBoolean("extent.debug");
|
||||
STORE_CLIPBOARD_ON_DISK = config.getBoolean("clipboard.use-disk");
|
||||
@ -152,6 +156,11 @@ public class Settings {
|
||||
PHYSICS_PER_TICK = config.getInt("tick-limiter.physics");
|
||||
ITEMS_PER_TICK = config.getInt("tick-limiter.items");
|
||||
|
||||
// Not usually configurable
|
||||
BUFFER_SIZE = config.getInt("history.buffer-size", BUFFER_SIZE);
|
||||
QUEUE_DISCARD_AFTER = config.getInt("queue.discard-after-ms", QUEUE_DISCARD_AFTER);
|
||||
COMBINE_HISTORY_STAGE = config.getBoolean("history.combine-stages", COMBINE_HISTORY_STAGE);
|
||||
|
||||
if (STORE_HISTORY_ON_DISK = config.getBoolean("history.use-disk")) {
|
||||
LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class CharFaweChunk<T> extends FaweChunk<T> {
|
||||
|
||||
@ -111,7 +112,7 @@ public abstract class CharFaweChunk<T> extends FaweChunk<T> {
|
||||
return this.ids[i];
|
||||
}
|
||||
|
||||
public char[][] getIdArrays() {
|
||||
public char[][] getCombinedIdArrays() {
|
||||
return this.ids;
|
||||
}
|
||||
|
||||
@ -153,8 +154,12 @@ public abstract class CharFaweChunk<T> extends FaweChunk<T> {
|
||||
return entities == null ? new HashSet<CompoundTag>() : entities;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public HashSet<CompoundTag> entities;
|
||||
|
||||
public HashSet<UUID> entityRemoves;
|
||||
|
||||
@Override
|
||||
public void setEntity(CompoundTag tag) {
|
||||
if (entities == null) {
|
||||
@ -163,6 +168,19 @@ public abstract class CharFaweChunk<T> extends FaweChunk<T> {
|
||||
entities.add(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEntity(UUID uuid) {
|
||||
if (entityRemoves == null) {
|
||||
entityRemoves = new HashSet<>();
|
||||
}
|
||||
entityRemoves.add(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<UUID> getEntityRemoves() {
|
||||
return entityRemoves == null ? new HashSet<UUID>() : entityRemoves;
|
||||
}
|
||||
|
||||
@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];
|
||||
|
@ -14,6 +14,7 @@ import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
|
||||
@ -25,7 +26,15 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
|
||||
* Map of chunks in the queue
|
||||
*/
|
||||
private ConcurrentHashMap<Long, FaweChunk> blocks = new ConcurrentHashMap<>();
|
||||
private LinkedBlockingDeque<FaweChunk> chunks = new LinkedBlockingDeque<>();
|
||||
private LinkedBlockingDeque<FaweChunk> chunks = new LinkedBlockingDeque<FaweChunk>() {
|
||||
@Override
|
||||
public boolean add(FaweChunk o) {
|
||||
if (progressTask != null) {
|
||||
progressTask.run(ProgressType.QUEUE, size() + 1);
|
||||
}
|
||||
return super.add(o);
|
||||
}
|
||||
};
|
||||
private ArrayDeque<Runnable> tasks = new ArrayDeque<>();
|
||||
|
||||
@Override
|
||||
@ -53,6 +62,7 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
|
||||
@Override
|
||||
public void addNotifyTask(Runnable runnable) {
|
||||
this.tasks.add(runnable);
|
||||
size();
|
||||
}
|
||||
|
||||
public MappedFaweQueue(final String world) {
|
||||
@ -72,9 +82,6 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
|
||||
@Override
|
||||
public abstract FaweChunk getChunk(int x, int z);
|
||||
|
||||
@Override
|
||||
public abstract boolean fixLighting(FaweChunk fc, boolean fixAll);
|
||||
|
||||
public abstract boolean loadChunk(WORLD world, int x, int z, boolean generate);
|
||||
|
||||
public abstract CHUNK getCachedChunk(WORLD world, int cx, int cz);
|
||||
@ -202,6 +209,33 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
|
||||
lastWrappedChunk.setEntity(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEntity(int x, int y, int z, UUID uuid) {
|
||||
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.removeEntity(uuid);
|
||||
FaweChunk previous = this.blocks.put(pair, lastWrappedChunk);
|
||||
if (previous == null) {
|
||||
chunks.add(lastWrappedChunk);
|
||||
return;
|
||||
}
|
||||
this.blocks.put(pair, previous);
|
||||
lastWrappedChunk = previous;
|
||||
}
|
||||
}
|
||||
lastWrappedChunk.removeEntity(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int z, BaseBiome biome) {
|
||||
long pair = (long) (x >> 4) << 32 | (z >> 4) & 0xFFFFFFFFL;
|
||||
@ -243,15 +277,23 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
|
||||
}
|
||||
|
||||
public void runTasks() {
|
||||
for (Runnable run : tasks) {
|
||||
run.run();
|
||||
if (progressTask != null) {
|
||||
progressTask.run(ProgressType.DONE, 1);
|
||||
}
|
||||
ArrayDeque<Runnable> tmp = new ArrayDeque<>(tasks);
|
||||
tasks.clear();
|
||||
for (Runnable run : tmp) {
|
||||
try {
|
||||
run.run();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
if (chunks.size() == 0 && SetQueue.IMP.isStage(this, SetQueue.QueueStage.ACTIVE)) {
|
||||
if (chunks.size() == 0 && SetQueue.IMP.getStage(this) != SetQueue.QueueStage.INACTIVE) {
|
||||
runTasks();
|
||||
}
|
||||
return chunks.size();
|
||||
@ -259,11 +301,17 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
|
||||
|
||||
private LinkedBlockingDeque<FaweChunk> toUpdate = new LinkedBlockingDeque<>();
|
||||
|
||||
private int dispatched = 0;
|
||||
|
||||
public boolean execute(final FaweChunk fc) {
|
||||
if (fc == null) {
|
||||
return false;
|
||||
}
|
||||
// Set blocks / entities / biome
|
||||
if (progressTask != null) {
|
||||
progressTask.run(ProgressType.QUEUE, chunks.size());
|
||||
progressTask.run(ProgressType.DISPATCH, ++dispatched);
|
||||
}
|
||||
if (getChangeTask() != null) {
|
||||
if (!this.setComponents(fc, new RunnableVal<FaweChunk>() {
|
||||
@Override
|
||||
@ -284,6 +332,7 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
|
||||
public void clear() {
|
||||
this.blocks.clear();
|
||||
this.chunks.clear();
|
||||
runTasks();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,7 +2,12 @@ package com.boydti.fawe.example;
|
||||
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> extends MappedFaweQueue<WORLD, CHUNKSECTION, SECTION> {
|
||||
public NMSMappedFaweQueue(String world) {
|
||||
@ -14,12 +19,12 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
|
||||
TaskManager.IMP.taskSyncSoon(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING;
|
||||
final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING ? FaweQueue.RelightMode.OPTIMAL : FaweQueue.RelightMode.MINIMAL) || !Settings.ASYNC_LIGHTING;
|
||||
TaskManager.IMP.taskSyncNow(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!result) {
|
||||
fixLighting(fc, Settings.FIX_ALL_LIGHTING);
|
||||
fixLighting(fc, Settings.FIX_ALL_LIGHTING ? FaweQueue.RelightMode.OPTIMAL : FaweQueue.RelightMode.MINIMAL);
|
||||
}
|
||||
CHUNK chunk = (CHUNK) fc.getChunk();
|
||||
refreshChunk(getWorld(), chunk);
|
||||
@ -31,6 +36,5 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
|
||||
|
||||
public abstract void refreshChunk(WORLD world, CHUNK chunk);
|
||||
|
||||
@Override
|
||||
public abstract boolean fixLighting(FaweChunk fc, boolean fixAll);
|
||||
public abstract CharFaweChunk getPrevious(CharFaweChunk fs, CHUNKSECTION sections, Map<?, ?> tiles, Collection<?>[] entities, Set<UUID> createdEntities, boolean all) throws Exception;
|
||||
}
|
||||
|
@ -9,6 +9,14 @@ public class BytePair {
|
||||
|
||||
int hash;
|
||||
|
||||
public byte get0() {
|
||||
return pair[0];
|
||||
}
|
||||
|
||||
public byte get1() {
|
||||
return pair[1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return pair[0] + (pair[1] << 8);
|
||||
|
@ -117,7 +117,7 @@ public class EditSessionWrapper {
|
||||
return minY;
|
||||
}
|
||||
|
||||
public Extent getHistoryExtent(EditSession session, FaweLimit limit, Extent parent, FaweChangeSet set, FaweQueue queue, FawePlayer<?> player) {
|
||||
return new HistoryExtent(session, limit, parent, set, queue);
|
||||
public FaweChangeSet wrapChangeSet(EditSession session, FaweLimit limit, Extent parent, FaweChangeSet set, FaweQueue queue, FawePlayer<?> player) {
|
||||
return set;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
@ -7,6 +8,7 @@ import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class FaweChunk<T> {
|
||||
|
||||
@ -24,12 +26,23 @@ public abstract class FaweChunk<T> {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the chunk's location<br>
|
||||
* - E.g. if you are cloning a chunk and want to set multiple
|
||||
* @param parent
|
||||
* @param x
|
||||
* @param z
|
||||
*/
|
||||
public void setLoc(FaweQueue parent, int x, int z) {
|
||||
this.parent = parent;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent queue this chunk belongs to
|
||||
* @return
|
||||
*/
|
||||
public FaweQueue getParent() {
|
||||
return parent;
|
||||
}
|
||||
@ -42,24 +55,65 @@ public abstract class FaweChunk<T> {
|
||||
return z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a unique hashcode for this chunk
|
||||
* @return
|
||||
*/
|
||||
public long longHash() {
|
||||
return (long) x << 32 | z & 0xFFFFFFFFL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a hashcode; unique below abs(x/z) < Short.MAX_VALUE
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return x << 16 | z & 0xFFFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the chunk to the queue
|
||||
*/
|
||||
public void addToQueue() {
|
||||
parent.setChunk(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix the lighting in this chunk
|
||||
*/
|
||||
public void fixLighting() {
|
||||
parent.fixLighting(this, Settings.FIX_ALL_LIGHTING);
|
||||
parent.fixLighting(this, Settings.FIX_ALL_LIGHTING ? FaweQueue.RelightMode.OPTIMAL : FaweQueue.RelightMode.MINIMAL);
|
||||
}
|
||||
|
||||
public abstract char[][] getIdArrays();
|
||||
/**
|
||||
* This may return the raw value or constructed depending on the implementation<br>
|
||||
* - The first index (i) is the layer (layer = y >> 4) (16 layers)<br>
|
||||
* - The second array is length 4096 and contains the combined ids (cast to an int if you want)
|
||||
*
|
||||
* @see com.boydti.fawe.FaweCache#CACHE_I
|
||||
* @see com.boydti.fawe.FaweCache#CACHE_J
|
||||
* @see com.boydti.fawe.FaweCache#CACHE_X
|
||||
* @see com.boydti.fawe.FaweCache#CACHE_Y
|
||||
* @see com.boydti.fawe.FaweCache#CACHE_Z
|
||||
*
|
||||
* @return Combined id arrays
|
||||
*/
|
||||
public abstract char[][] getCombinedIdArrays();
|
||||
|
||||
/**
|
||||
* Get the combined block id at a location<br>
|
||||
* combined = (id <<<< 4) + data
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @return The combined id
|
||||
*/
|
||||
public int getBlockCombinedId(int x, int y, int z) {
|
||||
char[][] arrays = getCombinedIdArrays();
|
||||
char[] array = arrays[y >> 4];
|
||||
return array != null ? (array[FaweCache.CACHE_J[y][x][z]]) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill this chunk with a block
|
||||
@ -91,6 +145,10 @@ public abstract class FaweChunk<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a task to run when this chunk is dispatched
|
||||
* @param run
|
||||
*/
|
||||
public void addNotifyTask(Runnable run) {
|
||||
if (run != null) {
|
||||
tasks.add(run);
|
||||
@ -108,22 +166,61 @@ public abstract class FaweChunk<T> {
|
||||
tasks.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying chunk object
|
||||
* @return
|
||||
*/
|
||||
public abstract T getChunk();
|
||||
|
||||
/**
|
||||
* Set a tile entity at a location<br>
|
||||
* - May throw an error if an invalid block is at the location
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param tile
|
||||
*/
|
||||
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 void removeEntity(UUID uuid);
|
||||
|
||||
public abstract CompoundTag getTile(int x, int y, int z);
|
||||
public abstract void setBlock(final int x, final int y, final int z, final int id, final byte data);
|
||||
|
||||
public abstract Set<CompoundTag> getEntities();
|
||||
|
||||
/**
|
||||
* Get the UUID of entities being removed
|
||||
* @return
|
||||
*/
|
||||
public abstract Set<UUID> getEntityRemoves();
|
||||
|
||||
/**
|
||||
* Get the map of location to tile entity<br>
|
||||
* - The byte pair represents the location in the chunk<br>
|
||||
* @see com.boydti.fawe.util.MathMan#unpair16x (get0) => x
|
||||
* @see com.boydti.fawe.util.MathMan#unpair16y (get0) => z
|
||||
* get1 => y
|
||||
* @return
|
||||
*/
|
||||
public abstract Map<BytePair, CompoundTag> getTiles();
|
||||
|
||||
/**
|
||||
* Get the tile at a location
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @return
|
||||
*/
|
||||
public abstract CompoundTag getTile(int x, int y, int z);
|
||||
|
||||
public abstract void setBiome(final int x, final int z, final BaseBiome biome);
|
||||
|
||||
/**
|
||||
* Spend time now so that the chunk can be more efficiently dispatched later<br>
|
||||
* - Modifications after this call will be ignored
|
||||
*/
|
||||
public void optimize() {}
|
||||
|
||||
@Override
|
||||
|
@ -21,6 +21,7 @@ public abstract class FaweCommand<T> {
|
||||
}
|
||||
|
||||
public boolean executeSafe(final FawePlayer<T> player, final String... args) {
|
||||
try {
|
||||
if (player == null || !safe) {
|
||||
execute(player, args);
|
||||
return true;
|
||||
@ -39,6 +40,10 @@ public abstract class FaweCommand<T> {
|
||||
});
|
||||
}
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract boolean execute(final FawePlayer<T> player, final String... args);
|
||||
|
@ -173,7 +173,7 @@ public abstract class FawePlayer<T> {
|
||||
FaweStreamChangeSet set = new DiskStorageHistory(world, uuid, index);
|
||||
EditSession edit = set.toEditSession(getPlayer());
|
||||
if (world.equals(getWorld())) {
|
||||
session.remember(edit, false);
|
||||
session.remember(edit, false, false);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@ -184,6 +184,15 @@ public abstract class FawePlayer<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a title
|
||||
* @param head
|
||||
* @param sub
|
||||
*/
|
||||
public abstract void sendTitle(String head, String sub);
|
||||
|
||||
public abstract void resetTitle();
|
||||
|
||||
/**
|
||||
* Get the player's limit
|
||||
* @return
|
||||
@ -370,4 +379,11 @@ public abstract class FawePlayer<T> {
|
||||
WorldEdit.getInstance().removeSession(getPlayer());
|
||||
Fawe.get().unregister(getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new EditSession from this player
|
||||
*/
|
||||
public EditSession getNewEditSession() {
|
||||
return WorldEdit.getInstance().getEditSessionFactory().getEditSession(getWorld(), -1, getPlayer());
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,15 @@ package com.boydti.fawe.object;
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.history.change.Change;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class NullChangeSet extends FaweChangeSet {
|
||||
public NullChangeSet(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean flush() {
|
||||
return false;
|
||||
|
@ -0,0 +1,4 @@
|
||||
package com.boydti.fawe.object.brush;
|
||||
|
||||
public class AbstractDelegateBrush {
|
||||
}
|
@ -1,30 +1,23 @@
|
||||
package com.boydti.fawe.object.brush;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.IntegerPair;
|
||||
import com.boydti.fawe.object.brush.heightmap.ArrayHeightMap;
|
||||
import com.boydti.fawe.object.brush.heightmap.HeightMap;
|
||||
import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.command.tool.BrushTool;
|
||||
import com.sk89q.worldedit.command.tool.brush.Brush;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.Masks;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.Raster;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
public class HeightBrush implements Brush {
|
||||
|
||||
public final HeightMap heightMap;
|
||||
public final ScalableHeightMap heightMap;
|
||||
private final int rotation;
|
||||
double yscale = 1;
|
||||
private final BrushTool tool;
|
||||
@ -36,57 +29,13 @@ public class HeightBrush implements Brush {
|
||||
if (file == null || !file.exists()) {
|
||||
// Since I can't be bothered using separate args, we'll get it from the filename
|
||||
if (file.getName().equalsIgnoreCase("#clipboard.png") && clipboard != null) {
|
||||
Vector dim = clipboard.getDimensions();
|
||||
byte[][] heightArray = new byte[dim.getBlockX()][dim.getBlockZ()];
|
||||
int minX = clipboard.getMinimumPoint().getBlockX();
|
||||
int minZ = clipboard.getMinimumPoint().getBlockZ();
|
||||
int minY = clipboard.getMinimumPoint().getBlockY();
|
||||
int maxY = clipboard.getMaximumPoint().getBlockY();
|
||||
int clipHeight = maxY - minY + 1;
|
||||
HashSet<IntegerPair> visited = new HashSet<>();
|
||||
for (Vector pos : clipboard.getRegion()) {
|
||||
IntegerPair pair = new IntegerPair((int) pos.x, (int) pos.z);
|
||||
if (visited.contains(pair)) {
|
||||
continue;
|
||||
}
|
||||
visited.add(pair);
|
||||
int xx = pos.getBlockX();
|
||||
int zz = pos.getBlockZ();
|
||||
int highestY = 0;
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
pos.y = y;
|
||||
BaseBlock block = clipboard.getBlock(pos);
|
||||
if (block != EditSession.nullBlock) {
|
||||
highestY = y + 1;
|
||||
}
|
||||
}
|
||||
int pointHeight = Math.min(255, (256 * (highestY - minY)) / clipHeight);
|
||||
int x = xx - minX;
|
||||
int z = zz - minZ;
|
||||
heightArray[x][z] = (byte) pointHeight;
|
||||
}
|
||||
heightMap = new ArrayHeightMap(heightArray);
|
||||
heightMap = ScalableHeightMap.fromClipboard(clipboard);
|
||||
} else {
|
||||
heightMap = new HeightMap();
|
||||
heightMap = new ScalableHeightMap();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
BufferedImage heightFile = ImageIO.read(file);
|
||||
int width = heightFile.getWidth();
|
||||
int length = heightFile.getHeight();
|
||||
Raster data = heightFile.getData();
|
||||
byte[][] array = new byte[width][length];
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int z = 0; z < length; z++) {
|
||||
int pixel = heightFile.getRGB(x, z);
|
||||
int red = (pixel >> 16) & 0xFF;
|
||||
int green = (pixel >> 8) & 0xFF;
|
||||
int blue = (pixel >> 0) & 0xFF;
|
||||
int intensity = (red + green + blue) / 3;
|
||||
array[x][z] = (byte) intensity;
|
||||
}
|
||||
}
|
||||
heightMap = new ArrayHeightMap(array);
|
||||
heightMap = ScalableHeightMap.fromPNG(file);
|
||||
} catch (IOException e) {
|
||||
throw new FaweException(BBC.BRUSH_HEIGHT_INVALID);
|
||||
}
|
||||
@ -101,69 +50,6 @@ public class HeightBrush implements Brush {
|
||||
}
|
||||
int size = (int) sizeDouble;
|
||||
heightMap.setSize(size);
|
||||
int size2 = size * size;
|
||||
int startY = position.getBlockY() + size;
|
||||
int endY = position.getBlockY() - size;
|
||||
int cx = position.getBlockX();
|
||||
int cz = position.getBlockZ();
|
||||
Vector mutablePos = new Vector(0, 0, 0);
|
||||
for (int x = -size; x <= size; x++) {
|
||||
int xx = cx + x;
|
||||
mutablePos.x = xx;
|
||||
for (int z = -size; z <= size; z++) {
|
||||
int zz = cz + z;
|
||||
int raise;
|
||||
switch (rotation) {
|
||||
default:
|
||||
raise = heightMap.getHeight(x, z);
|
||||
break;
|
||||
case 1:
|
||||
raise = heightMap.getHeight(z, x);
|
||||
break;
|
||||
case 2:
|
||||
raise = heightMap.getHeight(-x, -z);
|
||||
break;
|
||||
case 3:
|
||||
raise = heightMap.getHeight(-z, -x);
|
||||
break;
|
||||
}
|
||||
raise = (int) (yscale * raise);
|
||||
if (raise == 0) {
|
||||
continue;
|
||||
}
|
||||
mutablePos.z = zz;
|
||||
int foundHeight = Integer.MAX_VALUE;
|
||||
BaseBlock block = null;
|
||||
for (int y = startY; y >= endY; y--) {
|
||||
block = editSession.getLazyBlock(xx, y, zz);
|
||||
if (block != EditSession.nullBlock) {
|
||||
if (mask != null) {
|
||||
mutablePos.y = y;
|
||||
if (!mask.test(mutablePos)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
foundHeight = y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (foundHeight == Integer.MAX_VALUE) {
|
||||
continue;
|
||||
}
|
||||
if (raise > 0) {
|
||||
for (int y = foundHeight + 1; y <= foundHeight + raise; y++) {
|
||||
mutablePos.y = y;
|
||||
editSession.setBlock(mutablePos, block);
|
||||
}
|
||||
} else {
|
||||
for (int y = foundHeight; y > foundHeight + raise; y--) {
|
||||
mutablePos.y = y;
|
||||
editSession.setBlock(mutablePos, EditSession.nullBlock);
|
||||
}
|
||||
mutablePos.y = foundHeight + raise;
|
||||
editSession.setBlock(mutablePos, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
heightMap.apply(editSession, mask, position, size, rotation, yscale, true);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.object.brush.heightmap;
|
||||
|
||||
public class ArrayHeightMap extends HeightMap {
|
||||
public class ArrayHeightMap extends ScalableHeightMap {
|
||||
// The heights
|
||||
private final byte[][] height;
|
||||
// The height map width/length
|
||||
@ -19,15 +19,15 @@ public class ArrayHeightMap extends HeightMap {
|
||||
public void setSize(int size) {
|
||||
super.setSize(size);
|
||||
this.rx = (double) width / (size << 1);
|
||||
this.rz = (double) width / (size << 1);
|
||||
this.rz = (double) length / (size << 1);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight(int x, int z) {
|
||||
public double getHeight(int x, int z) {
|
||||
x = (int) Math.max(0, Math.min(width - 1, (x + size) * rx));
|
||||
z = (int) Math.max(0, Math.min(length - 1, (z + size) * rz));
|
||||
return (((int) height[x][z] & 0xFF) * size) / 256;
|
||||
return ((height[x][z] & 0xFF) * size) / 256d;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
package com.boydti.fawe.object.brush.heightmap;
|
||||
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
|
||||
public class HeightMap {
|
||||
public int size2;
|
||||
public int size;
|
||||
|
||||
public HeightMap() {
|
||||
setSize(5);
|
||||
}
|
||||
|
||||
public HeightMap(int size) {
|
||||
setSize(size);
|
||||
}
|
||||
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
this.size2 = size * size;
|
||||
}
|
||||
|
||||
public int getHeight(int x, int z) {
|
||||
int dx = Math.abs(x);
|
||||
int dz = Math.abs(z);
|
||||
int d2 = dx * dx + dz * dz;
|
||||
if (d2 > size2) {
|
||||
return 0;
|
||||
}
|
||||
return size - MathMan.sqrt(d2);
|
||||
}
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
package com.boydti.fawe.object.brush.heightmap;
|
||||
|
||||
import com.boydti.fawe.object.IntegerPair;
|
||||
import com.boydti.fawe.object.PseudoRandom;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldVector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.internal.LocalWorldAdapter;
|
||||
import com.sk89q.worldedit.math.convolution.GaussianKernel;
|
||||
import com.sk89q.worldedit.math.convolution.HeightMap;
|
||||
import com.sk89q.worldedit.math.convolution.HeightMapFilter;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.Raster;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
public class ScalableHeightMap {
|
||||
public int size2;
|
||||
public int size;
|
||||
|
||||
public ScalableHeightMap() {
|
||||
setSize(5);
|
||||
}
|
||||
|
||||
public ScalableHeightMap(int size) {
|
||||
setSize(size);
|
||||
}
|
||||
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
this.size2 = size * size;
|
||||
}
|
||||
|
||||
public double getHeight(int x, int z) {
|
||||
int dx = Math.abs(x);
|
||||
int dz = Math.abs(z);
|
||||
int d2 = dx * dx + dz * dz;
|
||||
if (d2 > size2) {
|
||||
return 0;
|
||||
}
|
||||
return size - MathMan.sqrtApprox(d2);
|
||||
}
|
||||
|
||||
public static ScalableHeightMap fromClipboard(Clipboard clipboard) {
|
||||
Vector dim = clipboard.getDimensions();
|
||||
byte[][] heightArray = new byte[dim.getBlockX()][dim.getBlockZ()];
|
||||
int minX = clipboard.getMinimumPoint().getBlockX();
|
||||
int minZ = clipboard.getMinimumPoint().getBlockZ();
|
||||
int minY = clipboard.getMinimumPoint().getBlockY();
|
||||
int maxY = clipboard.getMaximumPoint().getBlockY();
|
||||
int clipHeight = maxY - minY + 1;
|
||||
HashSet<IntegerPair> visited = new HashSet<>();
|
||||
for (Vector pos : clipboard.getRegion()) {
|
||||
IntegerPair pair = new IntegerPair((int) pos.x, (int) pos.z);
|
||||
if (visited.contains(pair)) {
|
||||
continue;
|
||||
}
|
||||
visited.add(pair);
|
||||
int xx = pos.getBlockX();
|
||||
int zz = pos.getBlockZ();
|
||||
int highestY = minY;
|
||||
for (int y = minY; y <= maxY; y++) {
|
||||
pos.y = y;
|
||||
BaseBlock block = clipboard.getBlock(pos);
|
||||
if (block != EditSession.nullBlock) {
|
||||
highestY = y + 1;
|
||||
}
|
||||
}
|
||||
int pointHeight = Math.min(255, (256 * (highestY - minY)) / clipHeight);
|
||||
int x = xx - minX;
|
||||
int z = zz - minZ;
|
||||
heightArray[x][z] = (byte) pointHeight;
|
||||
}
|
||||
return new ArrayHeightMap(heightArray);
|
||||
}
|
||||
|
||||
public static ScalableHeightMap fromPNG(File file) throws IOException {
|
||||
BufferedImage heightFile = ImageIO.read(file);
|
||||
int width = heightFile.getWidth();
|
||||
int length = heightFile.getHeight();
|
||||
Raster data = heightFile.getData();
|
||||
byte[][] array = new byte[width][length];
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int z = 0; z < length; z++) {
|
||||
int pixel = heightFile.getRGB(x, z);
|
||||
int red = (pixel >> 16) & 0xFF;
|
||||
int green = (pixel >> 8) & 0xFF;
|
||||
int blue = (pixel >> 0) & 0xFF;
|
||||
int intensity = (red + green + blue) / 3;
|
||||
array[x][z] = (byte) intensity;
|
||||
}
|
||||
}
|
||||
return new ArrayHeightMap(array);
|
||||
}
|
||||
|
||||
public void apply(EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth) throws MaxChangedBlocksException {
|
||||
int diameter = 2 * size + 1;
|
||||
int centerX = pos.getBlockX();
|
||||
int centerZ = pos.getBlockZ();
|
||||
int endY = pos.getBlockY() + size;
|
||||
int startY = pos.getBlockY() - size;
|
||||
int[] newData = new int[diameter * diameter];
|
||||
Vector mutablePos = new Vector(0, 0, 0);
|
||||
for (int x = -size; x <= size; x++) {
|
||||
int xx = centerX + x;
|
||||
mutablePos.x = xx;
|
||||
for (int z = -size; z <= size; z++) {
|
||||
int index = (z + size) * diameter + (x + size);
|
||||
int zz = centerZ + z;
|
||||
double raise;
|
||||
switch (rotationMode) {
|
||||
default:
|
||||
raise = getHeight(x, z);
|
||||
break;
|
||||
case 1:
|
||||
raise = getHeight(z, x);
|
||||
break;
|
||||
case 2:
|
||||
raise = getHeight(-x, -z);
|
||||
break;
|
||||
case 3:
|
||||
raise = getHeight(-z, -x);
|
||||
break;
|
||||
}
|
||||
raise = (yscale * raise);
|
||||
int random = PseudoRandom.random.random(256) < (int) ((raise - (int) raise) * 256) ? 1 : 0;
|
||||
int height = session.getHighestTerrainBlock(xx, zz, 0, 255, true) + (int) raise + random;
|
||||
newData[index] = height;
|
||||
}
|
||||
}
|
||||
int iterations = 1;
|
||||
WorldVector min = new WorldVector(LocalWorldAdapter.adapt(session.getWorld()), pos.subtract(size, 255, size));
|
||||
Vector max = pos.add(size, 255, size);
|
||||
Region region = new CuboidRegion(session.getWorld(), min, max);
|
||||
HeightMap heightMap = new HeightMap(session, region, true);
|
||||
if (smooth) {
|
||||
HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1));
|
||||
newData = filter.filter(newData, diameter, diameter);
|
||||
// MainUtil.smoothArray(newData, diameter, 1, 4);
|
||||
}
|
||||
heightMap.apply(newData);
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.boydti.fawe.object.change;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
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 MutableChunkChange implements Change {
|
||||
|
||||
public FaweChunk from;
|
||||
public FaweChunk to;
|
||||
|
||||
public MutableChunkChange(FaweChunk from, FaweChunk to) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo(UndoContext context) throws WorldEditException {
|
||||
create(context, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void redo(UndoContext context) throws WorldEditException {
|
||||
create(context, false);
|
||||
}
|
||||
|
||||
public void create(UndoContext context, boolean undo) {
|
||||
Extent extent = context.getExtent();
|
||||
if (extent.getClass() == FastWorldEditExtent.class) {
|
||||
FastWorldEditExtent fwee = (FastWorldEditExtent) extent;
|
||||
if (undo) {
|
||||
fwee.getQueue().setChunk(from);
|
||||
} else {
|
||||
fwee.getQueue().setChunk(to);
|
||||
}
|
||||
} else {
|
||||
Fawe.debug("FAWE doesn't support: " + context + " for " + getClass());
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ 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.LongTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
@ -11,6 +12,7 @@ import com.sk89q.worldedit.history.UndoContext;
|
||||
import com.sk89q.worldedit.history.change.Change;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class MutableEntityChange implements Change {
|
||||
|
||||
@ -26,6 +28,8 @@ public class MutableEntityChange implements Change {
|
||||
public void undo(UndoContext context) throws WorldEditException {
|
||||
if (!create) {
|
||||
create(context);
|
||||
} else {
|
||||
delete(context);
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,6 +37,36 @@ public class MutableEntityChange implements Change {
|
||||
public void redo(UndoContext context) throws WorldEditException {
|
||||
if (create) {
|
||||
create(context);
|
||||
} else {
|
||||
delete(context);
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(UndoContext context) {
|
||||
Extent extent = context.getExtent();
|
||||
if (extent.getClass() == FastWorldEditExtent.class) {
|
||||
FastWorldEditExtent fwee = (FastWorldEditExtent) extent;
|
||||
Map<String, Tag> map = tag.getValue();
|
||||
long most;
|
||||
long least;
|
||||
if (map.containsKey("UUIDMost")) {
|
||||
most = ((LongTag) map.get("UUIDMost")).getValue();
|
||||
least = ((LongTag) map.get("UUIDLeast")).getValue();
|
||||
} else if (map.containsKey("PersistentIDMSB")) {
|
||||
most = ((LongTag) map.get("PersistentIDMSB")).getValue();
|
||||
least = ((LongTag) map.get("PersistentIDLSB")).getValue();
|
||||
} else {
|
||||
Fawe.debug("Skipping entity without uuid.");
|
||||
return;
|
||||
}
|
||||
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());
|
||||
UUID uuid = new UUID(most, least);
|
||||
fwee.getQueue().removeEntity(x, y, z, uuid);
|
||||
} else {
|
||||
Fawe.debug("FAWE doesn't support: " + context + " for " + getClass() + " (bug Empire92)");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,72 @@
|
||||
package com.boydti.fawe.object.changeset;
|
||||
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.object.change.MutableChunkChange;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.history.change.Change;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class CPUOptimizedChangeSet extends FaweChangeSet {
|
||||
|
||||
public CPUOptimizedChangeSet(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
private ArrayList<Change> changes = new ArrayList<>();
|
||||
|
||||
public void addChangeTask(FaweQueue queue) {
|
||||
queue.setChangeTask(new RunnableVal2<FaweChunk, FaweChunk>() {
|
||||
@Override
|
||||
public void run(final FaweChunk previous, final FaweChunk next) {
|
||||
char[][] previousIds = previous.getCombinedIdArrays();
|
||||
char[][] nextIds = next.getCombinedIdArrays();
|
||||
for (int i = 0; i < nextIds.length; i++) {
|
||||
if (nextIds[i] != null && previousIds[i] == null) {
|
||||
previous.fillCuboid(0, 15, i << 4, (i << 4) + 15, 0, 15, 0, (byte) 0);
|
||||
}
|
||||
}
|
||||
changes.add(new MutableChunkChange(previous, next));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public void add(int x, int y, int z, int combinedFrom, int combinedTo) {
|
||||
throw new UnsupportedOperationException("Invalid mode");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTileCreate(CompoundTag tag) {
|
||||
throw new UnsupportedOperationException("Invalid mode");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTileRemove(CompoundTag tag) {
|
||||
throw new UnsupportedOperationException("Invalid mode");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntityRemove(CompoundTag tag) {
|
||||
throw new UnsupportedOperationException("Invalid mode");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntityCreate(CompoundTag tag) {
|
||||
throw new UnsupportedOperationException("Invalid mode");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Change> getIterator(boolean redo) {
|
||||
return changes.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return changes.size() * 65536; // num chunks * 65536 (guess of 65536 changes per chunk)
|
||||
}
|
||||
}
|
@ -16,8 +16,6 @@ import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import net.jpountz.lz4.LZ4Compressor;
|
||||
import net.jpountz.lz4.LZ4Factory;
|
||||
import net.jpountz.lz4.LZ4InputStream;
|
||||
@ -56,20 +54,15 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
|
||||
// NBT From
|
||||
private NBTOutputStream osNBTF;
|
||||
private GZIPOutputStream osNBTFG;
|
||||
private AtomicInteger osNBTFI;
|
||||
|
||||
// NBT To
|
||||
private NBTOutputStream osNBTT;
|
||||
private GZIPOutputStream osNBTTG;
|
||||
|
||||
// Entity Create From
|
||||
private NBTOutputStream osENTCF;
|
||||
private GZIPOutputStream osENTCFG;
|
||||
|
||||
// Entity Create To
|
||||
private NBTOutputStream osENTCT;
|
||||
private GZIPOutputStream osENTCTG;
|
||||
|
||||
private World world;
|
||||
|
||||
@ -82,6 +75,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
}
|
||||
|
||||
public DiskStorageHistory(World world, UUID uuid) {
|
||||
super(world);
|
||||
String base = "history" + File.separator + world.getName() + File.separator + uuid;
|
||||
File folder = new File(Fawe.imp().getDirectory(), base);
|
||||
int max = 0;
|
||||
@ -100,6 +94,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
}
|
||||
|
||||
public DiskStorageHistory(World world, UUID uuid, int index) {
|
||||
super(world);
|
||||
init(world, uuid, index);
|
||||
}
|
||||
|
||||
@ -125,27 +120,28 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
|
||||
@Override
|
||||
public boolean flush() {
|
||||
boolean flushed = false;
|
||||
super.flush();
|
||||
boolean flushed = osBD != null || osNBTF != null || osNBTT != null && osENTCF != null || osENTCT != null;
|
||||
try {
|
||||
if (osBD != null) {
|
||||
flushed = true;
|
||||
osBD.flush();
|
||||
osBD.close();
|
||||
osBD = null;
|
||||
}
|
||||
if (osNBTF != null) {
|
||||
flushed = true;
|
||||
osNBTFG.flush();
|
||||
osNBTF.close();
|
||||
osNBTF = null;
|
||||
osNBTFG = null;
|
||||
}
|
||||
if (osNBTT != null) {
|
||||
flushed = true;
|
||||
osNBTTG.flush();
|
||||
osNBTT.close();
|
||||
osNBTT = null;
|
||||
osNBTTG = null;
|
||||
}
|
||||
if (osENTCF != null) {
|
||||
osENTCF.close();
|
||||
osENTCF = null;
|
||||
}
|
||||
if (osENTCT != null) {
|
||||
osENTCT.close();
|
||||
osENTCT = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@ -185,8 +181,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
}
|
||||
enttFile.getParentFile().mkdirs();
|
||||
enttFile.createNewFile();
|
||||
osENTCTG = new GZIPOutputStream(new FileOutputStream(enttFile), true);
|
||||
osENTCT = new NBTOutputStream(osENTCTG);
|
||||
osENTCT = new NBTOutputStream(getCompressedOS(new FileOutputStream(enttFile)));
|
||||
return osENTCT;
|
||||
}
|
||||
|
||||
@ -197,8 +192,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
}
|
||||
entfFile.getParentFile().mkdirs();
|
||||
entfFile.createNewFile();
|
||||
osENTCFG = new GZIPOutputStream(new FileOutputStream(entfFile), true);
|
||||
osENTCF = new NBTOutputStream(osENTCFG);
|
||||
osENTCF = new NBTOutputStream(getCompressedOS(new FileOutputStream(entfFile)));
|
||||
return osENTCF;
|
||||
}
|
||||
|
||||
@ -209,8 +203,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
}
|
||||
nbttFile.getParentFile().mkdirs();
|
||||
nbttFile.createNewFile();
|
||||
osNBTTG = new GZIPOutputStream(new FileOutputStream(nbttFile), true);
|
||||
osNBTT = new NBTOutputStream(osNBTTG);
|
||||
osNBTT = new NBTOutputStream(getCompressedOS(new FileOutputStream(nbttFile)));
|
||||
return osNBTT;
|
||||
}
|
||||
|
||||
@ -221,9 +214,7 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
}
|
||||
nbtfFile.getParentFile().mkdirs();
|
||||
nbtfFile.createNewFile();
|
||||
osNBTFG = new GZIPOutputStream(new FileOutputStream(nbtfFile), true);
|
||||
osNBTF = new NBTOutputStream(osNBTFG);
|
||||
osNBTFI = new AtomicInteger();
|
||||
osNBTF = new NBTOutputStream(getCompressedOS(new FileOutputStream(nbtfFile)));
|
||||
return osNBTF;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ 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.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
@ -20,12 +21,36 @@ 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.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public abstract class FaweChangeSet implements ChangeSet {
|
||||
public abstract boolean flush();
|
||||
|
||||
private final World world;
|
||||
|
||||
public FaweChangeSet(World world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public boolean flush() {
|
||||
try {
|
||||
while (waiting.get() > 0) {
|
||||
synchronized (lock) {
|
||||
lock.wait(1000);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract void add(int x, int y, int z, int combinedFrom, int combinedTo);
|
||||
|
||||
@ -47,7 +72,7 @@ public abstract class FaweChangeSet implements ChangeSet {
|
||||
|
||||
public EditSession toEditSession(Player player) {
|
||||
EditSessionFactory factory = WorldEdit.getInstance().getEditSessionFactory();
|
||||
EditSession edit = factory.getEditSession(player.getWorld(), -1, null, player);
|
||||
EditSession edit = factory.getEditSession(world, -1, null, player);
|
||||
edit.setChangeSet(this);
|
||||
edit.dequeue();
|
||||
return edit;
|
||||
@ -131,31 +156,32 @@ public abstract class FaweChangeSet implements ChangeSet {
|
||||
}
|
||||
}
|
||||
|
||||
private AtomicInteger waiting = new AtomicInteger(0);
|
||||
private Object lock = new Object();
|
||||
|
||||
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
|
||||
*/
|
||||
public void run(final FaweChunk previous, final FaweChunk next) {
|
||||
waiting.incrementAndGet();
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
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();
|
||||
char[][] currentIds = next.getCombinedIdArrays();
|
||||
// Previous blocks in modified sections (i.e. we skip sections that weren't modified)
|
||||
char[][] previousIds = previous.getIdArrays();
|
||||
char[][] previousIds = previous.getCombinedIdArrays();
|
||||
for (int layer = 0; layer < currentIds.length; layer++) {
|
||||
char[] currentLayer = currentIds[layer];
|
||||
char[] previousLayer = previousIds[layer];
|
||||
@ -181,6 +207,7 @@ public abstract class FaweChangeSet implements ChangeSet {
|
||||
default:
|
||||
char combinedIdPrevious = previousLayer != null ? previousLayer[index] : 0;
|
||||
if (combinedIdCurrent != combinedIdPrevious) {
|
||||
synchronized (lock) {
|
||||
add(xx, yy, zz, combinedIdPrevious, combinedIdCurrent);
|
||||
}
|
||||
}
|
||||
@ -189,34 +216,52 @@ public abstract class FaweChangeSet implements ChangeSet {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// Tile changes
|
||||
{
|
||||
// Tiles created
|
||||
Map<BytePair, CompoundTag> tiles = next.getTiles();
|
||||
for (Map.Entry<BytePair, CompoundTag> entry : tiles.entrySet()) {
|
||||
synchronized (lock) {
|
||||
addTileCreate(entry.getValue());
|
||||
}
|
||||
}
|
||||
// Tiles removed
|
||||
tiles = previous.getTiles();
|
||||
for (Map.Entry<BytePair, CompoundTag> entry : tiles.entrySet()) {
|
||||
synchronized (lock) {
|
||||
addTileRemove(entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Entity changes
|
||||
{
|
||||
// Entities created
|
||||
Set<CompoundTag> entities = next.getEntities();
|
||||
for (CompoundTag entityTag : entities) {
|
||||
synchronized (lock) {
|
||||
addEntityCreate(entityTag);
|
||||
}
|
||||
}
|
||||
// Entities removed
|
||||
entities = previous.getEntities();
|
||||
for (CompoundTag entityTag : entities) {
|
||||
synchronized (lock) {
|
||||
addEntityRemove(entityTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
waiting.decrementAndGet();
|
||||
synchronized (lock) {
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ 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 com.sk89q.worldedit.world.World;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -21,9 +21,12 @@ import net.jpountz.lz4.LZ4OutputStream;
|
||||
|
||||
public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
||||
|
||||
public FaweStreamChangeSet(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
System.out.println("SIZE: " + blockSize);
|
||||
// Flush so we can accurately get the size
|
||||
flush();
|
||||
return blockSize;
|
||||
@ -172,7 +175,6 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
||||
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;
|
||||
@ -192,7 +194,6 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
||||
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();
|
||||
@ -206,10 +207,8 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
||||
last = read();
|
||||
}
|
||||
if (last != null) {
|
||||
System.out.println("HAS NEXT!");
|
||||
return true;
|
||||
}
|
||||
System.out.println("NO NEXT");
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
@ -333,18 +332,43 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
|
||||
}
|
||||
|
||||
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);
|
||||
final Iterator<MutableTileChange> tileCreate = getTileIterator(getTileCreateIS(), true, dir);
|
||||
final Iterator<MutableTileChange> tileRemove = getTileIterator(getTileRemoveIS(), false, dir);
|
||||
|
||||
Iterator<MutableEntityChange> entityCreate = getEntityIterator(getEntityCreateIS(), true, dir);
|
||||
Iterator<MutableEntityChange> entityRemove = getEntityIterator(getEntityRemoveIS(), false, dir);
|
||||
final Iterator<MutableEntityChange> entityCreate = getEntityIterator(getEntityCreateIS(), true, dir);
|
||||
final Iterator<MutableEntityChange> entityRemove = getEntityIterator(getEntityRemoveIS(), false, dir);
|
||||
|
||||
Iterator<MutableBlockChange> blockChange = getBlockIterator(dir);
|
||||
final Iterator<MutableBlockChange> blockChange = getBlockIterator(dir);
|
||||
|
||||
return Iterators.concat(tileCreate, tileRemove, entityCreate, entityRemove, blockChange);
|
||||
return new Iterator<Change>() {
|
||||
Iterator<Change>[] iterators = new Iterator[]{tileCreate, tileRemove, entityCreate, entityRemove, blockChange};
|
||||
int i = 0;
|
||||
Iterator<Change> current = iterators[0];
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (current.hasNext()) {
|
||||
return true;
|
||||
} else if (i >= iterators.length - 1) {
|
||||
return false;
|
||||
} else {
|
||||
current = iterators[++i];
|
||||
}
|
||||
return hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
current.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Change next() {
|
||||
return current.next();
|
||||
}
|
||||
};
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -1,17 +1,14 @@
|
||||
package com.boydti.fawe.object.changeset;
|
||||
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import net.jpountz.lz4.LZ4Factory;
|
||||
import net.jpountz.lz4.LZ4InputStream;
|
||||
import net.jpountz.lz4.LZ4OutputStream;
|
||||
|
||||
/**
|
||||
* ChangeSet optimized for low memory usage
|
||||
@ -21,26 +18,67 @@ import net.jpountz.lz4.LZ4OutputStream;
|
||||
*/
|
||||
public class MemoryOptimizedHistory extends FaweStreamChangeSet {
|
||||
|
||||
private final Actor actor;
|
||||
private byte[] ids;
|
||||
private ByteArrayOutputStream idsStream;
|
||||
private OutputStream idsStreamZip;
|
||||
|
||||
public MemoryOptimizedHistory(Actor actor) {
|
||||
this.actor = actor;
|
||||
private byte[] entC;
|
||||
private ByteArrayOutputStream entCStream;
|
||||
private NBTOutputStream entCStreamZip;
|
||||
|
||||
private byte[] entR;
|
||||
private ByteArrayOutputStream entRStream;
|
||||
private NBTOutputStream entRStreamZip;
|
||||
|
||||
private byte[] tileC;
|
||||
private ByteArrayOutputStream tileCStream;
|
||||
private NBTOutputStream tileCStreamZip;
|
||||
|
||||
private byte[] tileR;
|
||||
private ByteArrayOutputStream tileRStream;
|
||||
private NBTOutputStream tileRStreamZip;
|
||||
|
||||
public MemoryOptimizedHistory(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean flush() {
|
||||
if (idsStreamZip != null) {
|
||||
super.flush();
|
||||
try {
|
||||
idsStream.flush();
|
||||
idsStreamZip.flush();
|
||||
if (idsStream != null) {
|
||||
idsStreamZip.close();
|
||||
ids = idsStream.toByteArray(true);
|
||||
ids = idsStream.toByteArray();
|
||||
idsStream = null;
|
||||
idsStreamZip = null;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (entCStream != null) {
|
||||
entCStreamZip.close();
|
||||
entC = entCStream.toByteArray();
|
||||
entCStream = null;
|
||||
entCStreamZip = null;
|
||||
}
|
||||
if (entRStream != null) {
|
||||
entRStreamZip.close();
|
||||
entR = entRStream.toByteArray();
|
||||
entRStream = null;
|
||||
entRStreamZip = null;
|
||||
}
|
||||
if (tileCStream != null) {
|
||||
tileCStreamZip.close();
|
||||
tileC = tileCStream.toByteArray();
|
||||
tileCStream = null;
|
||||
tileCStreamZip = null;
|
||||
}
|
||||
if (tileRStream != null) {
|
||||
tileRStreamZip.close();
|
||||
tileR = tileRStream.toByteArray();
|
||||
tileRStream = null;
|
||||
tileRStreamZip = null;
|
||||
}
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -50,75 +88,74 @@ public class MemoryOptimizedHistory extends FaweStreamChangeSet {
|
||||
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;
|
||||
idsStream = new ByteArrayOutputStream(Settings.BUFFER_SIZE);
|
||||
return idsStreamZip = getCompressedOS(idsStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBlockIS() {
|
||||
if (ids == null) {
|
||||
return null;
|
||||
return ids == null ? null : getCompressedIS(new ByteArrayInputStream(ids));
|
||||
}
|
||||
InputStream is = new ByteArrayInputStream(ids);
|
||||
is = new LZ4InputStream(is);
|
||||
if (Settings.COMPRESSION_LEVEL > 0) {
|
||||
is = new LZ4InputStream(is);
|
||||
|
||||
@Override
|
||||
public NBTOutputStream getEntityCreateOS() throws IOException {
|
||||
if (entCStreamZip != null) {
|
||||
return entCStreamZip;
|
||||
}
|
||||
return is;
|
||||
entCStream = new ByteArrayOutputStream(Settings.BUFFER_SIZE);
|
||||
return entCStreamZip = new NBTOutputStream(getCompressedOS(entCStream));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTOutputStream getEntityRemoveOS() throws IOException {
|
||||
if (entRStreamZip != null) {
|
||||
return entRStreamZip;
|
||||
}
|
||||
entRStream = new ByteArrayOutputStream(Settings.BUFFER_SIZE);
|
||||
return entRStreamZip = new NBTOutputStream(getCompressedOS(entRStream));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTOutputStream getTileCreateOS() throws IOException {
|
||||
if (tileCStreamZip != null) {
|
||||
return tileCStreamZip;
|
||||
}
|
||||
tileCStream = new ByteArrayOutputStream(Settings.BUFFER_SIZE);
|
||||
return tileCStreamZip = new NBTOutputStream(getCompressedOS(tileCStream));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTOutputStream getTileRemoveOS() throws IOException {
|
||||
if (tileRStreamZip != null) {
|
||||
return tileRStreamZip;
|
||||
}
|
||||
tileRStream = new ByteArrayOutputStream(Settings.BUFFER_SIZE);
|
||||
return tileRStreamZip = new NBTOutputStream(getCompressedOS(tileRStream));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTInputStream getEntityCreateIS() throws IOException {
|
||||
return null;
|
||||
return entC == null ? null : new NBTInputStream(getCompressedIS(new ByteArrayInputStream(entC)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTInputStream getEntityRemoveIS() throws IOException {
|
||||
return null;
|
||||
return entR == null ? null : new NBTInputStream(getCompressedIS(new ByteArrayInputStream(entR)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTInputStream getTileCreateIS() throws IOException {
|
||||
return null;
|
||||
return tileC == null ? null : new NBTInputStream(getCompressedIS(new ByteArrayInputStream(tileC)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTInputStream getTileRemoveIS() throws IOException {
|
||||
return null;
|
||||
return tileR == null ? null : new NBTInputStream(getCompressedIS(new ByteArrayInputStream(tileR)));
|
||||
}
|
||||
}
|
||||
|
@ -154,6 +154,7 @@ public class FastWorldEditExtent extends AbstractDelegateExtent {
|
||||
case 178: {
|
||||
if (block.hasNbtData()) {
|
||||
CompoundTag nbt = block.getNbtData();
|
||||
MainUtil.setPosition(nbt, x, y, z);
|
||||
queue.setTile(x, y, z, nbt);
|
||||
}
|
||||
queue.setBlock(x, y, z, id, (byte) block.getData());
|
||||
|
@ -75,12 +75,12 @@ public class ProcessedWEExtent extends FaweRegionExtent {
|
||||
}
|
||||
if (WEManager.IMP.maskContains(this.mask, (int) location.x, (int) location.z)) {
|
||||
if (limit.MAX_CHANGES-- < 0) {
|
||||
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_TILES);
|
||||
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES);
|
||||
return false;
|
||||
}
|
||||
return super.setBlock(location, block);
|
||||
} else if (limit.MAX_FAILS-- < 0) {
|
||||
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_TILES);
|
||||
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -0,0 +1,76 @@
|
||||
package com.boydti.fawe.object.progress;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class DefaultProgressTracker extends RunnableVal2<FaweQueue.ProgressType, Integer> {
|
||||
|
||||
private final FawePlayer player;
|
||||
private final long start;
|
||||
|
||||
public DefaultProgressTracker(FawePlayer player) {
|
||||
this.start = System.currentTimeMillis();
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
private int amountQueue = 0;
|
||||
private int amountDispatch = 0;
|
||||
private long lastTick = 0;
|
||||
|
||||
@Override
|
||||
public void run(FaweQueue.ProgressType type, Integer amount) {
|
||||
switch (type) {
|
||||
case DISPATCH:
|
||||
amountDispatch = amount;
|
||||
break;
|
||||
case QUEUE:
|
||||
amountQueue = amount;
|
||||
break;
|
||||
case DONE:
|
||||
if (amountDispatch > 64) {
|
||||
done();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (amountQueue > 64 || amountDispatch > 64) {
|
||||
send();
|
||||
}
|
||||
}
|
||||
|
||||
private void done() {
|
||||
TaskManager.IMP.task(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final long time = System.currentTimeMillis() - start;
|
||||
player.sendTitle("", BBC.PROGRESS_DONE.format(time / 1000d));
|
||||
TaskManager.IMP.later(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
player.resetTitle();
|
||||
}
|
||||
}, 60);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void send() {
|
||||
TaskManager.IMP.task(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
long currentTick = Bukkit.getServer().getWorlds().get(0).getFullTime();
|
||||
if (currentTick > lastTick + Settings.DISPLAY_PROGRESS_INTERVAL) {
|
||||
lastTick = currentTick;
|
||||
String queue = StringMan.padRight("" + amountQueue, 3);
|
||||
String dispatch = StringMan.padRight("" + amountDispatch, 3);
|
||||
player.sendTitle("", BBC.PROGRESS_MESSAGE.format(queue, dispatch));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -10,14 +10,28 @@ import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
|
||||
public abstract class FaweQueue {
|
||||
|
||||
public static enum ProgressType {
|
||||
QUEUE,
|
||||
DISPATCH,
|
||||
DONE,
|
||||
}
|
||||
|
||||
public enum RelightMode {
|
||||
MINIMAL,
|
||||
OPTIMAL,
|
||||
ALL,
|
||||
}
|
||||
|
||||
public final String world;
|
||||
public LinkedBlockingDeque<EditSession> sessions;
|
||||
public long modified = System.currentTimeMillis();
|
||||
public RunnableVal2<FaweChunk, FaweChunk> changeTask;
|
||||
public RunnableVal2<ProgressType, Integer> progressTask;
|
||||
|
||||
public FaweQueue(String world) {
|
||||
this.world = world;
|
||||
@ -33,6 +47,16 @@ public abstract class FaweQueue {
|
||||
sessions.add(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a progress task<br>
|
||||
* - Progress type
|
||||
* - Amount of type
|
||||
* @param progressTask
|
||||
*/
|
||||
public void setProgressTracker(RunnableVal2<ProgressType, Integer> progressTask) {
|
||||
this.progressTask = progressTask;
|
||||
}
|
||||
|
||||
public Set<EditSession> getEditSessions() {
|
||||
return sessions == null ? new HashSet<EditSession>() : new HashSet<>(sessions);
|
||||
}
|
||||
@ -53,13 +77,15 @@ public abstract class FaweQueue {
|
||||
|
||||
public abstract void setEntity(int x, int y, int z, CompoundTag tag);
|
||||
|
||||
public abstract void removeEntity(int x, int y, int z, UUID uuid);
|
||||
|
||||
public abstract boolean setBiome(final int x, final int z, final BaseBiome biome);
|
||||
|
||||
public abstract FaweChunk<?> getChunk(int x, int z);
|
||||
|
||||
public abstract void setChunk(final FaweChunk<?> chunk);
|
||||
|
||||
public abstract boolean fixLighting(final FaweChunk<?> chunk, final boolean fixAll);
|
||||
public abstract boolean fixLighting(final FaweChunk<?> chunk, RelightMode mode);
|
||||
|
||||
public abstract boolean isChunkLoaded(final int x, final int z);
|
||||
|
||||
|
@ -70,6 +70,9 @@ public class MainUtil {
|
||||
try {
|
||||
int elements = set.size();
|
||||
int compressedSize = set.getCompressedSize();
|
||||
if (compressedSize == 0) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* BlockVector
|
||||
* - reference to the object --> 8 bytes
|
||||
@ -90,10 +93,9 @@ public class MainUtil {
|
||||
* This compares FAWE's usage to standard WE.
|
||||
*/
|
||||
int total = 128 * elements;
|
||||
int current = compressedSize;
|
||||
|
||||
int ratio = total / current;
|
||||
int saved = total - current;
|
||||
int ratio = total / compressedSize;
|
||||
int saved = total - compressedSize;
|
||||
|
||||
if (ratio > 3 && Thread.currentThread() != Fawe.get().getMainThread() && actor != null && actor.isPlayer() && actor.getSessionKey().isActive()) {
|
||||
BBC.COMPRESSED.send(actor, saved, ratio);
|
||||
@ -103,6 +105,31 @@ public class MainUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void smoothArray(int[] data, int width, int radius, int weight) {
|
||||
int[] copy = data.clone();
|
||||
int length = data.length / width;
|
||||
int diameter = 2 * radius + 1;
|
||||
weight += diameter * diameter - 1;
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < length; y++) {
|
||||
int index = x + width * y;
|
||||
int value = 0;
|
||||
int count = 0;
|
||||
for (int x2 = Math.max(0, x - radius); x2 <= Math.min(width - 1, x + radius); x2++) {
|
||||
for (int y2 = Math.max(0, y - radius); y2 <= Math.min(length - 1, y + radius); y2++) {
|
||||
count++;
|
||||
int index2 = x2 + width * y2;
|
||||
value += data[index2];
|
||||
|
||||
}
|
||||
}
|
||||
value += data[index] * (weight - count);
|
||||
value = value / (weight);
|
||||
data[index] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void warnDeprecated(Class... alternatives) {
|
||||
StackTraceElement[] stack = new RuntimeException().getStackTrace();
|
||||
if (stack.length > 1) {
|
||||
|
@ -89,11 +89,11 @@ public class SetQueue {
|
||||
// Disable the async catcher as it can't discern async vs parallel
|
||||
SET_TASK.value2.startSet(true);
|
||||
try {
|
||||
if (Settings.UNSAFE_PARALLEL_THREADS <= 1) {
|
||||
if (Settings.PARALLEL_THREADS <= 1) {
|
||||
SET_TASK.run();
|
||||
} else {
|
||||
ArrayList<Thread> threads = new ArrayList<Thread>();
|
||||
for (int i = 0; i < Settings.UNSAFE_PARALLEL_THREADS; i++) {
|
||||
for (int i = 0; i < Settings.PARALLEL_THREADS; i++) {
|
||||
threads.add(new Thread(SET_TASK));
|
||||
}
|
||||
for (Thread thread : threads) {
|
||||
@ -197,7 +197,6 @@ public class SetQueue {
|
||||
inactiveQueues.remove(queue);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (Settings.QUEUE_SIZE != -1) {
|
||||
|
@ -40,6 +40,14 @@ public class StringMan {
|
||||
return count;
|
||||
}
|
||||
|
||||
public static String padRight(String s, int n) {
|
||||
return String.format("%1$-" + n + "s", s);
|
||||
}
|
||||
|
||||
public static String padLeft(String s, int n) {
|
||||
return String.format("%1$" + n + "s", s);
|
||||
}
|
||||
|
||||
public static String getString(final Object obj) {
|
||||
if (obj == null) {
|
||||
return "null";
|
||||
|
@ -104,7 +104,6 @@ public abstract class TaskManager {
|
||||
/**
|
||||
* Break up a task and run it in fragments of 5ms.<br>
|
||||
* - Each task will run on the main thread.<br>
|
||||
* - Usualy wait time is around 25ms<br>
|
||||
* @param objects - The list of objects to run the task for
|
||||
* @param task - The task to run on each object
|
||||
* @param whenDone - When the object task completes
|
||||
@ -133,6 +132,7 @@ public abstract class TaskManager {
|
||||
/**
|
||||
* Quickly run a task on the main thread, and wait for execution to finish:<br>
|
||||
* - Useful if you need to access something from the Bukkit API from another thread<br>
|
||||
* - Usualy wait time is around 25ms<br>
|
||||
* @param function
|
||||
* @param <T>
|
||||
* @return
|
||||
@ -144,6 +144,7 @@ public abstract class TaskManager {
|
||||
/**
|
||||
* Quickly run a task on the main thread, and wait for execution to finish:<br>
|
||||
* - Useful if you need to access something from the Bukkit API from another thread<br>
|
||||
* - Usualy wait time is around 25ms<br>
|
||||
* @param function
|
||||
* @param timeout - How long to wait for execution
|
||||
* @param <T>
|
||||
|
@ -5,6 +5,7 @@ import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweLocation;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.boydti.fawe.object.extent.NullExtent;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
@ -58,14 +59,23 @@ public class WEManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a player's mask
|
||||
* @param player
|
||||
* @return
|
||||
*/
|
||||
public HashSet<RegionWrapper> getMask(final FawePlayer<?> player) {
|
||||
return TaskManager.IMP.sync(new RunnableVal<HashSet<RegionWrapper>>() {
|
||||
@Override
|
||||
public void run(HashSet<RegionWrapper> value) {
|
||||
final HashSet<RegionWrapper> regions = new HashSet<>();
|
||||
if (player.hasPermission("fawe.bypass") || !Settings.REGION_RESTRICTIONS) {
|
||||
regions.add(new RegionWrapper(Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE));
|
||||
player.deleteMeta("lastmask");
|
||||
return regions;
|
||||
this.value = regions;
|
||||
return;
|
||||
}
|
||||
for (final FaweMaskManager manager : this.managers) {
|
||||
for (final FaweMaskManager manager : managers) {
|
||||
if (player.hasPermission("fawe." + manager.getKey())) {
|
||||
final FaweMask mask = manager.getMask(player);
|
||||
if (mask != null) {
|
||||
@ -80,14 +90,19 @@ public class WEManager {
|
||||
for (RegionWrapper region : mask) {
|
||||
if (region.isIn(loc.x, loc.z)) {
|
||||
player.deleteMeta("lastmask");
|
||||
return regions;
|
||||
this.value = regions;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
this.value = mask;
|
||||
return;
|
||||
}
|
||||
}
|
||||
player.setMeta("lastmask", regions);
|
||||
return regions;
|
||||
this.value = regions;
|
||||
return;
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
public boolean intersects(final RegionWrapper region1, final RegionWrapper region2) {
|
||||
|
@ -205,7 +205,7 @@ public class PlayerWrapper implements Player {
|
||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
edit.queue.next();
|
||||
edit.getQueue().next();
|
||||
setPosition(new Vector(x + 0.5, y, z + 0.5));
|
||||
}
|
||||
});
|
||||
|
@ -229,6 +229,7 @@ public class WorldWrapper extends AbstractWorld {
|
||||
@Override
|
||||
public boolean regenerate(final Region region, final EditSession session) {
|
||||
final FaweQueue queue = session.getQueue();
|
||||
queue.setChangeTask(null);
|
||||
final FaweChangeSet fcs = (FaweChangeSet) session.getChangeSet();
|
||||
final FaweRegionExtent fe = session.getRegionExtent();
|
||||
session.setChangeSet(fcs);
|
||||
@ -274,22 +275,25 @@ public class WorldWrapper extends AbstractWorld {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Vector mutable = new Vector(0,0,0);
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int xx = x + bx;
|
||||
mutable.x = xx;
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int zz = z + bz;
|
||||
mutable.z = zz;
|
||||
for (int y = 0; y < getMaxY() + 1; y++) {
|
||||
final Vector loc = new Vector(xx, y, zz);
|
||||
mutable.y = y;
|
||||
int from = queue.getCombinedId4Data(xx, y, zz);
|
||||
boolean contains = (fe != null && fe.contains(xx, y, zz)) && region.contains(loc);
|
||||
boolean contains = (fe == null || fe.contains(xx, y, zz)) && region.contains(mutable);
|
||||
if (contains) {
|
||||
if (fcs != null) {
|
||||
if (!FaweCache.hasNBT(from >> 4)) {
|
||||
fcs.add(xx, y, zz, from, 0);
|
||||
} else {
|
||||
try {
|
||||
BaseBlock block = getLazyBlock(loc);
|
||||
fcs.add(loc, block, FaweCache.CACHE_BLOCK[0]);
|
||||
BaseBlock block = getLazyBlock(mutable);
|
||||
fcs.add(mutable, block, FaweCache.CACHE_BLOCK[0]);
|
||||
} catch (Throwable e) {
|
||||
fcs.add(xx, y, zz, from, 0);
|
||||
}
|
||||
@ -298,30 +302,14 @@ public class WorldWrapper extends AbstractWorld {
|
||||
} else {
|
||||
short id = (short) (from >> 4);
|
||||
byte data = (byte) (from & 0xf);
|
||||
if (!FaweCache.hasNBT(id)) {
|
||||
queue.setBlock(xx, y, zz, id, data);
|
||||
} else {
|
||||
try {
|
||||
final BaseBlock block = getBlock(loc);
|
||||
final Vector v = new Vector(loc.x, loc.y, loc.z);
|
||||
queue.addNotifyTask(cx, cz, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
setBlock(v, block, false);
|
||||
} catch (WorldEditException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
queue.setBlock(xx, y, zz, id, data);
|
||||
if (FaweCache.hasNBT(id)) {
|
||||
BaseBlock block = getBlock(new Vector(xx, y, zz));
|
||||
if (block.hasNbtData()) {
|
||||
queue.setTile(xx, y, zz, block.getNbtData());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,9 +26,11 @@ import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.EditSessionWrapper;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.HistoryExtent;
|
||||
import com.boydti.fawe.object.NullChangeSet;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.changeset.CPUOptimizedChangeSet;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.boydti.fawe.object.changeset.MemoryOptimizedHistory;
|
||||
@ -38,6 +40,7 @@ import com.boydti.fawe.object.extent.FaweRegionExtent;
|
||||
import com.boydti.fawe.object.extent.MemoryCheckingExtent;
|
||||
import com.boydti.fawe.object.extent.NullExtent;
|
||||
import com.boydti.fawe.object.extent.ProcessedWEExtent;
|
||||
import com.boydti.fawe.object.progress.DefaultProgressTracker;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.boydti.fawe.util.Perm;
|
||||
@ -158,21 +161,21 @@ public class EditSession implements Extent {
|
||||
BEFORE_HISTORY, BEFORE_REORDER, BEFORE_CHANGE
|
||||
}
|
||||
|
||||
public World world;
|
||||
public Actor actor;
|
||||
public FaweChangeSet changeSet;
|
||||
public EditSessionWrapper wrapper;
|
||||
public MaskingExtent maskingExtent;
|
||||
public FaweRegionExtent regionExtent;
|
||||
public Extent primaryExtent;
|
||||
public Extent bypassReorderHistory;
|
||||
public Extent bypassHistory;
|
||||
public Extent bypassNone;
|
||||
public SurvivalModeExtent lazySurvivalExtent;
|
||||
public boolean fastmode;
|
||||
public Mask oldMask;
|
||||
public FaweLimit limit = FaweLimit.MAX.copy();
|
||||
public FaweQueue queue;
|
||||
private World world;
|
||||
private Actor actor;
|
||||
private FaweChangeSet changeSet;
|
||||
private EditSessionWrapper wrapper;
|
||||
private MaskingExtent maskingExtent;
|
||||
private FaweRegionExtent regionExtent;
|
||||
private Extent primaryExtent;
|
||||
private Extent bypassReorderHistory;
|
||||
private Extent bypassHistory;
|
||||
private Extent bypassNone;
|
||||
private SurvivalModeExtent lazySurvivalExtent;
|
||||
private boolean fastmode;
|
||||
private Mask oldMask;
|
||||
private FaweLimit limit = FaweLimit.MAX.copy();
|
||||
private FaweQueue queue;
|
||||
|
||||
public static BaseBiome nullBiome = new BaseBiome(0);
|
||||
public static BaseBlock nullBlock = FaweCache.CACHE_BLOCK[0];
|
||||
@ -229,13 +232,13 @@ public class EditSession implements Extent {
|
||||
this.bypassReorderHistory = extent;
|
||||
this.bypassHistory = extent;
|
||||
this.bypassNone = extent;
|
||||
this.changeSet = new NullChangeSet();
|
||||
this.changeSet = new NullChangeSet(world);
|
||||
this.wrapper = Fawe.imp().getEditSessionWrapper(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Wrap the world
|
||||
this.world = (world = new WorldWrapper((AbstractWorld) world));
|
||||
this.world = (world instanceof WorldWrapper) ? world : (world = new WorldWrapper((AbstractWorld) world));
|
||||
|
||||
// Delegate some methods to an implementation specific class
|
||||
this.wrapper = Fawe.imp().getEditSessionWrapper(this);
|
||||
@ -252,7 +255,7 @@ public class EditSession implements Extent {
|
||||
this.bypassReorderHistory = extent;
|
||||
this.bypassHistory = extent;
|
||||
this.bypassNone = extent;
|
||||
this.changeSet = new NullChangeSet();
|
||||
this.changeSet = new NullChangeSet(world);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -261,8 +264,10 @@ public class EditSession implements Extent {
|
||||
final FawePlayer fp = FawePlayer.wrap(actor);
|
||||
final LocalSession session = fp.getSession();
|
||||
this.fastmode = session.hasFastMode();
|
||||
if (fp.hasWorldEditBypass()) {
|
||||
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), true, true);
|
||||
boolean bypass = fp.hasWorldEditBypass();
|
||||
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), bypass, true);
|
||||
queue.setProgressTracker(new DefaultProgressTracker(fp));
|
||||
if (bypass) {
|
||||
queue.addEditSession(this);
|
||||
// Bypass skips processing and area restrictions
|
||||
extent = primaryExtent = new FastWorldEditExtent(world, queue);
|
||||
@ -278,7 +283,6 @@ public class EditSession implements Extent {
|
||||
}
|
||||
mask = null;
|
||||
} else {
|
||||
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), false, true);
|
||||
queue.addEditSession(this);
|
||||
this.limit = fp.getLimit();
|
||||
mask = WEManager.IMP.getMask(fp);
|
||||
@ -326,13 +330,13 @@ public class EditSession implements Extent {
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER);
|
||||
|
||||
// History
|
||||
this.changeSet = Settings.STORE_HISTORY_ON_DISK ? new DiskStorageHistory(world, actor.getUniqueId()) : new MemoryOptimizedHistory(actor);
|
||||
this.changeSet = Settings.STORE_HISTORY_ON_DISK ? new DiskStorageHistory(world, actor.getUniqueId()) : (Settings.COMBINE_HISTORY_STAGE && Settings.COMPRESSION_LEVEL == 0) ? new CPUOptimizedChangeSet(world) : new MemoryOptimizedHistory(world);
|
||||
this.changeSet = this.wrapper.wrapChangeSet(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);
|
||||
extent = new HistoryExtent(this, limit, extent, changeSet, queue);
|
||||
}
|
||||
|
||||
// Region restrictions if mask is not null
|
||||
if (mask != null) {
|
||||
extent = this.regionExtent = new ProcessedWEExtent(extent, mask, limit);
|
||||
@ -367,6 +371,15 @@ public class EditSession implements Extent {
|
||||
return regionExtent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actor
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public Actor getActor() {
|
||||
return actor;
|
||||
}
|
||||
|
||||
public boolean cancel() {
|
||||
// Cancel this
|
||||
if (primaryExtent != null && queue != null) {
|
||||
@ -388,6 +401,12 @@ public class EditSession implements Extent {
|
||||
}
|
||||
}
|
||||
|
||||
public void addNotifyTask(Runnable whenDone) {
|
||||
if (queue != null) {
|
||||
queue.addNotifyTask(whenDone);
|
||||
}
|
||||
}
|
||||
|
||||
public FastWorldEditExtent getPrimaryExtent() {
|
||||
return (FastWorldEditExtent) primaryExtent;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jchronic.Chronic;
|
||||
import com.sk89q.jchronic.Options;
|
||||
import com.sk89q.jchronic.utils.Span;
|
||||
@ -199,10 +200,16 @@ public class LocalSession {
|
||||
* @param editSession the edit session
|
||||
*/
|
||||
public void remember(EditSession editSession) {
|
||||
remember(editSession, true);
|
||||
remember(editSession, true, false);
|
||||
}
|
||||
|
||||
public void remember(final EditSession editSession, final boolean append) {
|
||||
public void remember(final EditSession editSession, final boolean append, final boolean sendMessage) {
|
||||
if (editSession == null) {
|
||||
return;
|
||||
}
|
||||
if (Settings.STORE_HISTORY_ON_DISK) {
|
||||
MAX_HISTORY_SIZE = Integer.MAX_VALUE;
|
||||
}
|
||||
// Enqueue it
|
||||
if (editSession.getQueue() != null) {
|
||||
FaweQueue queue = editSession.getQueue();
|
||||
@ -215,9 +222,11 @@ public class LocalSession {
|
||||
if (editSession.size() == 0 || editSession.hasFastMode()) return;
|
||||
|
||||
// Destroy any sessions after this undo point
|
||||
if (append) {
|
||||
while (historyPointer < history.size()) {
|
||||
history.remove(historyPointer);
|
||||
}
|
||||
}
|
||||
ChangeSet set = editSession.getChangeSet();
|
||||
if (set instanceof FaweStreamChangeSet) {
|
||||
final FaweStreamChangeSet fcs = (FaweStreamChangeSet) set;
|
||||
@ -225,14 +234,19 @@ public class LocalSession {
|
||||
editSession.getQueue().addNotifyTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (fcs.flush() && append) {
|
||||
MainUtil.sendCompressedMessage(fcs, editSession.actor);
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (fcs.flush() && append && sendMessage) {
|
||||
MainUtil.sendCompressedMessage(fcs, editSession.getActor());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (fcs.flush() && append) {
|
||||
MainUtil.sendCompressedMessage(fcs, editSession.actor);
|
||||
if (fcs.flush() && append && sendMessage) {
|
||||
MainUtil.sendCompressedMessage(fcs, editSession.getActor());
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,13 +255,15 @@ public class LocalSession {
|
||||
}
|
||||
if (append) {
|
||||
history.add(editSession);
|
||||
historyPointer = history.size();
|
||||
} else {
|
||||
history.add(0, editSession);
|
||||
historyPointer++;
|
||||
}
|
||||
while (history.size() > MAX_HISTORY_SIZE) {
|
||||
history.remove(0);
|
||||
historyPointer--;
|
||||
}
|
||||
historyPointer = append ? history.size() : historyPointer + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -278,7 +294,6 @@ public class LocalSession {
|
||||
newEditSession.enableQueue();
|
||||
newEditSession.setFastMode(fastMode);
|
||||
editSession.undo(newEditSession);
|
||||
System.out.println("UNDO: " + historyPointer + " | " + history.size());
|
||||
return editSession;
|
||||
} else {
|
||||
historyPointer = 0;
|
||||
@ -306,7 +321,6 @@ 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()
|
||||
@ -315,10 +329,7 @@ public class LocalSession {
|
||||
newEditSession.setFastMode(fastMode);
|
||||
editSession.redo(newEditSession);
|
||||
++historyPointer;
|
||||
System.out.println("CAN REDO");
|
||||
return editSession;
|
||||
} else {
|
||||
System.out.println("POINTER");
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -155,7 +155,7 @@ public class SelectionCommand extends SimpleCommand<Operation> {
|
||||
}
|
||||
});
|
||||
queue.enqueue();
|
||||
editSession.setChangeSet(new NullChangeSet());
|
||||
editSession.setChangeSet(new NullChangeSet(null));
|
||||
BBC.OPERATION.send(actor, BBC.VISITOR_BLOCK.format(cuboid.getArea()));
|
||||
return null;
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ package com.sk89q.worldedit.extension.platform;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.wrappers.PlayerWrapper;
|
||||
import com.google.common.base.Joiner;
|
||||
@ -224,7 +223,6 @@ 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(" "));
|
||||
|
||||
@ -233,11 +231,11 @@ public final class CommandManager {
|
||||
return;
|
||||
}
|
||||
|
||||
LocalSession session = worldEdit.getSessionManager().get(actor);
|
||||
final LocalSession session = worldEdit.getSessionManager().get(actor);
|
||||
LocalConfiguration config = worldEdit.getConfiguration();
|
||||
|
||||
CommandLocals locals = new CommandLocals();
|
||||
FawePlayer fp = FawePlayer.wrap(actor);
|
||||
final FawePlayer fp = FawePlayer.wrap(actor);
|
||||
if (fp != null) {
|
||||
if (fp.getMeta("fawe_action") != null) {
|
||||
BBC.WORLDEDIT_COMMAND_LIMIT.send(fp);
|
||||
@ -285,36 +283,33 @@ 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");
|
||||
}
|
||||
EditSession editSession = locals.get(EditSession.class);
|
||||
|
||||
final EditSession editSession = locals.get(EditSession.class);
|
||||
boolean delayed = false;
|
||||
if (editSession != null) {
|
||||
session.remember(editSession);
|
||||
editSession.flushQueue();
|
||||
final long time = System.currentTimeMillis() - start;
|
||||
if (time > 5 && editSession.size() != 0) {
|
||||
SetQueue.IMP.addTask(new Runnable() {
|
||||
worldEdit.flushBlockBag(actor, editSession);
|
||||
}
|
||||
if (fp != null) {
|
||||
if (editSession != null && editSession.size() > 0 && editSession.getQueue() != null) {
|
||||
delayed = true;
|
||||
editSession.getQueue().addNotifyTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
session.remember(editSession, true, true);
|
||||
fp.deleteMeta("fawe_action");
|
||||
final long time = System.currentTimeMillis() - start;
|
||||
if (time > 5) {
|
||||
BBC.ACTION_COMPLETE.send(actor, (time / 1000d));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (config.profile) {
|
||||
int changed = editSession.getBlockChangeCount();
|
||||
if (time > 0) {
|
||||
double throughput = changed / (time / 1000.0);
|
||||
actor.printDebug((time / 1000.0) + "s elapsed (history: " + changed + " changed; " + Math.round(throughput) + " blocks/sec).");
|
||||
} else {
|
||||
actor.printDebug((time / 1000.0) + "s elapsed.");
|
||||
}
|
||||
if (!delayed) {
|
||||
if (fp != null) {
|
||||
fp.deleteMeta("fawe_action");
|
||||
}
|
||||
|
||||
worldEdit.flushBlockBag(actor, editSession);
|
||||
session.remember(editSession, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
7
pom.xml
7
pom.xml
@ -29,6 +29,13 @@
|
||||
</includes>
|
||||
<directory>bukkit18/src/main/resources/</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<filtering>false</filtering>
|
||||
<includes>
|
||||
<include>**/*.*</include>
|
||||
</includes>
|
||||
<directory>core/src/main/resources/</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
@ -47,11 +47,11 @@ public class SpongeCommand implements CommandCallable {
|
||||
|
||||
@Override
|
||||
public Optional<? extends Text> getHelp(final CommandSource cmd) {
|
||||
return Optional.of(Text.of("/<fixlighting|stream|wea|wrg>"));
|
||||
return Optional.of(Text.of("/<fixlighting|stream|wea|select>"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Text getUsage(final CommandSource cmd) {
|
||||
return Text.of("/<fixlighting|stream|wea|wrg>");
|
||||
return Text.of("/<fixlighting|stream|wea|select>");
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ public class SpongeQueue_ALL extends NMSMappedFaweQueue<World, net.minecraft.wor
|
||||
net.minecraft.world.chunk.Chunk nmsChunk = fs.getChunk();
|
||||
Chunk spongeChunk = (Chunk) nmsChunk;
|
||||
|
||||
char[][] ids = ((SpongeChunk_1_8) fc).getIdArrays();
|
||||
char[][] ids = ((SpongeChunk_1_8) fc).getCombinedIdArrays();
|
||||
MutableBlockVolumeWorker<? extends Chunk> blockWorker = spongeChunk.getBlockWorker();
|
||||
blockWorker.map(new BlockVolumeMapper() {
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user