Keep chunks loaded for at least 10s
Optimizations for 1.10
Fix cast for 1.8
Memory/Disk Optimizations for relighting large areas in unloaded chunks
Fix for clipboard entities
This commit is contained in:
Jesse Boyd 2016-08-10 17:18:55 +10:00
parent 1ed87eabbc
commit 5c0ae62b17
7 changed files with 65 additions and 34 deletions

View File

@ -6,6 +6,7 @@ import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.example.NMSMappedFaweQueue; import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.object.FaweChunk; import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
@ -16,12 +17,14 @@ import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.WorldCreator; import org.bukkit.WorldCreator;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.WorldInitEvent; import org.bukkit.event.world.WorldInitEvent;
public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMappedFaweQueue<World, CHUNK, CHUNKSECTIONS, SECTION> implements Listener { public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMappedFaweQueue<World, CHUNK, CHUNKSECTIONS, SECTION> implements Listener {
@ -80,6 +83,22 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
} }
} }
public static ConcurrentHashMap<Long, Long> keepLoaded = new ConcurrentHashMap<>();
@EventHandler
public static void onChunkUnload(ChunkUnloadEvent event) {
Chunk chunk = event.getChunk();
long pair = MathMan.pairInt(chunk.getX(), chunk.getZ());
Long lastLoad = keepLoaded.get(pair);
if (lastLoad != null) {
if (System.currentTimeMillis() - lastLoad < 10000) {
event.setCancelled(true);
} else {
keepLoaded.remove(pair);
}
}
}
public World createWorld(final WorldCreator creator) { public World createWorld(final WorldCreator creator) {
World world = TaskManager.IMP.sync(new RunnableVal<World>() { World world = TaskManager.IMP.sync(new RunnableVal<World>() {
@Override @Override
@ -154,7 +173,11 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
@Override @Override
public boolean loadChunk(World impWorld, int x, int z, boolean generate) { public boolean loadChunk(World impWorld, int x, int z, boolean generate) {
return impWorld.loadChunk(x, z, generate); if (impWorld.loadChunk(x, z, generate)) {
keepLoaded.put(MathMan.pairInt(x, z), System.currentTimeMillis());
return true;
}
return false;
} }
private volatile boolean timingsEnabled; private volatile boolean timingsEnabled;

View File

@ -33,7 +33,6 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import net.minecraft.server.v1_10_R1.Block; import net.minecraft.server.v1_10_R1.Block;
import net.minecraft.server.v1_10_R1.BlockPosition; import net.minecraft.server.v1_10_R1.BlockPosition;
import net.minecraft.server.v1_10_R1.Blocks;
import net.minecraft.server.v1_10_R1.ChunkSection; import net.minecraft.server.v1_10_R1.ChunkSection;
import net.minecraft.server.v1_10_R1.DataBits; import net.minecraft.server.v1_10_R1.DataBits;
import net.minecraft.server.v1_10_R1.DataPaletteBlock; import net.minecraft.server.v1_10_R1.DataPaletteBlock;
@ -64,7 +63,6 @@ import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.World.Environment; import org.bukkit.World.Environment;
import org.bukkit.WorldCreator; import org.bukkit.WorldCreator;
import org.bukkit.block.Biome;
import org.bukkit.craftbukkit.v1_10_R1.CraftChunk; import org.bukkit.craftbukkit.v1_10_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_10_R1.CraftServer; import org.bukkit.craftbukkit.v1_10_R1.CraftServer;
import org.bukkit.craftbukkit.v1_10_R1.CraftWorld; import org.bukkit.craftbukkit.v1_10_R1.CraftWorld;
@ -79,6 +77,8 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
private static Field fieldBits; private static Field fieldBits;
private static Method getEntitySlices; private static Method getEntitySlices;
public static final IBlockData[] IBD_CACHE = new IBlockData[Character.MAX_VALUE];
public BukkitQueue_1_10(final String world) { public BukkitQueue_1_10(final String world) {
super(world); super(world);
checkVersion("v1_10_R1"); checkVersion("v1_10_R1");
@ -95,6 +95,11 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
Fawe.debug("Using adapter: " + adapter); Fawe.debug("Using adapter: " + adapter);
Fawe.debug("========================================="); Fawe.debug("=========================================");
} }
for (int i = 0; i < Character.MAX_VALUE; i++) {
try {
IBD_CACHE[i] = Block.getById(i >> 4).fromLegacyData(i & 0xF);
} catch (Throwable ignore) {}
}
} catch (Throwable e) { } catch (Throwable e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -658,9 +663,11 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
DataPaletteBlock nibble = section.getBlocks(); DataPaletteBlock nibble = section.getBlocks();
int nonEmptyBlockCount = 0; int nonEmptyBlockCount = 0;
for (int y = 0; y < 16; y++) { for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) { short[][] i1 = FaweCache.CACHE_J[y];
for (int x = 0; x < 16; x++) { for (int x= 0; x < 16; x++) {
char combinedId = array[FaweCache.CACHE_J[y][x][z]]; short[] i2 = i1[x];
for (int z = 0; z < 16; z++) {
char combinedId = array[i2[z]];
switch (combinedId) { switch (combinedId) {
case 0: case 0:
IBlockData existing = nibble.a(x, y, z); IBlockData existing = nibble.a(x, y, z);
@ -669,11 +676,11 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
} }
continue; continue;
case 1: case 1:
nibble.setBlock(x, y, z, Blocks.AIR.getBlockData()); nibble.setBlock(x, y, z, air);
continue; continue;
default: default:
nonEmptyBlockCount++; nonEmptyBlockCount++;
nibble.setBlock(x, y, z, Block.getById(combinedId >> 4).fromLegacyData(combinedId & 0xF)); nibble.setBlock(x, y, z, IBD_CACHE[(int) combinedId]);
} }
} }
} }
@ -715,23 +722,6 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
} catch (Throwable e) { } catch (Throwable e) {
MainUtil.handleError(e); MainUtil.handleError(e);
} }
final int[][] biomes = fs.getBiomeArray();
final Biome[] values = Biome.values();
if (biomes != null) {
for (int x = 0; x < 16; x++) {
final int[] array = biomes[x];
if (array == null) {
continue;
}
for (int z = 0; z < 16; z++) {
final int biome = array[z];
if (biome == 0) {
continue;
}
chunk.getBlock(x, 0, z).setBiome(values[biome]);
}
}
}
return true; return true;
} }

View File

@ -579,12 +579,7 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkS
@Override @Override
public FaweChunk getFaweChunk(int x, int z) { public FaweChunk getFaweChunk(int x, int z) {
return new CharFaweChunk<Chunk>(this, x, z) { return new BukkitChunk_1_8(this, x, z);
@Override
public Chunk getNewChunk() {
return BukkitQueue18R3.this.getWorld().getChunkAt(getX(), getZ());
}
};
} }
@Override @Override

View File

@ -8,6 +8,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
public class NMSRelighter { public class NMSRelighter {
@ -15,6 +16,8 @@ public class NMSRelighter {
private final HashMap<Long, RelightSkyEntry> skyToRelight; private final HashMap<Long, RelightSkyEntry> skyToRelight;
private final HashMap<Long, RelightBlockEntry> blocksToRelight; private final HashMap<Long, RelightBlockEntry> blocksToRelight;
private static final int DISPATCH_SIZE = 64;
public NMSRelighter(NMSMappedFaweQueue queue) { public NMSRelighter(NMSMappedFaweQueue queue) {
this.queue = queue; this.queue = queue;
skyToRelight = new HashMap<>(); skyToRelight = new HashMap<>();
@ -127,7 +130,22 @@ public class NMSRelighter {
// Order chunks // Order chunks
ArrayList<RelightSkyEntry> chunksList = new ArrayList<>(skyToRelight.values()); ArrayList<RelightSkyEntry> chunksList = new ArrayList<>(skyToRelight.values());
Collections.sort(chunksList); Collections.sort(chunksList);
RelightSkyEntry[] chunks = chunksList.toArray(new RelightSkyEntry[chunksList.size()]); int size = chunksList.size();
if (size > DISPATCH_SIZE) {
int amount = (size + 1) / DISPATCH_SIZE;
for (int i = 0; i <= amount; i++) {
int start = i * DISPATCH_SIZE;
int end = Math.min(size, start + DISPATCH_SIZE);
List<RelightSkyEntry> sub = chunksList.subList(start, end);
fixSkyLighting(sub);
}
} else {
fixSkyLighting(chunksList);
}
}
private void fixSkyLighting(List<RelightSkyEntry> sorted) {
RelightSkyEntry[] chunks = sorted.toArray(new RelightSkyEntry[sorted.size()]);
byte[] cacheX = FaweCache.CACHE_X[0]; byte[] cacheX = FaweCache.CACHE_X[0];
byte[] cacheZ = FaweCache.CACHE_Z[0]; byte[] cacheZ = FaweCache.CACHE_Z[0];
for (int y = 255; y > 0; y--) { for (int y = 255; y > 0; y--) {

View File

@ -83,7 +83,7 @@ public class SchematicStreamer extends NBTStreamer {
ListTag positionTag = compound.getListTag("Pos"); ListTag positionTag = compound.getListTag("Pos");
ListTag directionTag = compound.getListTag("Rotation"); ListTag directionTag = compound.getListTag("Rotation");
BaseEntity state = new BaseEntity(id, compound); BaseEntity state = new BaseEntity(id, compound);
fc.createEntity(null, positionTag.asDouble(0), positionTag.asDouble(1), positionTag.asDouble(2), (float) directionTag.asDouble(0), (float) directionTag.asDouble(1), state); fc.createEntity(clipboard, positionTag.asDouble(0), positionTag.asDouble(1), positionTag.asDouble(2), (float) directionTag.asDouble(0), (float) directionTag.asDouble(1), state);
} }
}); });
} }

View File

@ -57,6 +57,7 @@ public abstract class FaweClipboard {
public ClipboardEntity(Extent world, double x, double y, double z, float yaw, float pitch, BaseEntity entity) { public ClipboardEntity(Extent world, double x, double y, double z, float yaw, float pitch, BaseEntity entity) {
checkNotNull(entity); checkNotNull(entity);
checkNotNull(world);
this.world = world; this.world = world;
this.x = x; this.x = x;
this.y = y; this.y = y;

View File

@ -159,7 +159,11 @@ public class MainUtil {
} }
int highAmount = amount > 3 ? 1 : 0; int highAmount = amount > 3 ? 1 : 0;
for (int i = 0; i < highAmount; i++) { for (int i = 0; i < highAmount; i++) {
os = new LZ4OutputStream(os, buffer, factory.highCompressor()); if (amount == 9) {
os = new LZ4OutputStream(os, buffer, factory.highCompressor(17));
} else {
os = new LZ4OutputStream(os, buffer, factory.highCompressor());
}
} }
return new FaweOutputStream(os); return new FaweOutputStream(os);
} }