fake chunk packet
aliases
cfi wip
This commit is contained in:
Jesse Boyd
2019-10-30 12:26:52 +01:00
parent 8356004ec9
commit 72951cdf23
33 changed files with 704 additions and 286 deletions

View File

@ -38,8 +38,11 @@ import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
@ -101,6 +104,7 @@ public enum FaweCache implements Trimable {
@Override
public synchronized boolean trim(boolean aggressive) {
BYTE_BUFFER_8192.clean();
BLOCK_TO_PALETTE.clean();
PALETTE_TO_BLOCK.clean();
BLOCK_STATES.clean();
@ -202,6 +206,8 @@ public enum FaweCache implements Trimable {
thread cache
*/
public final CleanableThreadLocal<byte[]> BYTE_BUFFER_8192 = new CleanableThreadLocal<>(() -> new byte[8192]);
public final CleanableThreadLocal<int[]> BLOCK_TO_PALETTE = new CleanableThreadLocal<>(() -> {
int[] result = new int[BlockTypes.states.length];
Arrays.fill(result, Integer.MAX_VALUE);
@ -502,6 +508,31 @@ public enum FaweCache implements Trimable {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS, queue
, Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
new ThreadPoolExecutor.CallerRunsPolicy()) {
protected void afterExecute(Runnable r, Throwable t) {
try {
super.afterExecute(r, t);
if (t == null && r instanceof Future<?>) {
try {
Future<?> future = (Future<?>) r;
if (future.isDone()) {
future.get();
}
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
if (t != null) {
t.printStackTrace();
}
} catch (Throwable e) {
e.printStackTrace();
}
}
};
}
}

View File

@ -1,11 +1,20 @@
package com.boydti.fawe.beta;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.object.collection.BitArray4096;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockID;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.registry.BlockRegistry;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
@ -29,11 +38,107 @@ public interface IBlocks extends Trimable {
default int getBitMask() {
int mask = 0;
for (int layer = 0; layer < FaweCache.IMP.CHUNK_LAYERS; layer++) {
if (hasSection(layer));
mask |= (1 << layer);
if (hasSection(layer)) {
System.out.println("Has layer 0 " + layer);
mask += (1 << layer);
}
}
return mask;
}
IBlocks reset();
default byte[] toByteArray(boolean writeBiomes) {
return toByteArray(null, writeBiomes);
}
default byte[] toByteArray(byte[] buffer, boolean writeBiomes) {
if (buffer == null) {
buffer = new byte[1024];
}
BlockRegistry registry = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry();
FastByteArrayOutputStream sectionByteArray = new FastByteArrayOutputStream(buffer);
FaweOutputStream sectionWriter = new FaweOutputStream(sectionByteArray);
try {
for (int layer = 0; layer < FaweCache.IMP.CHUNK_LAYERS; layer++) {
if (!this.hasSection(layer)) continue;
char[] ids = this.getArray(layer);
int nonEmpty = 0; // TODO optimize into same loop as toPalette
for (char id : ids) {
if (id != 0) nonEmpty++;
}
sectionWriter.writeShort(nonEmpty); // non empty
sectionWriter.writeByte(14); // globalPaletteBitsPerBlock
if (true) {
BitArray4096 bits = new BitArray4096(14); // globalPaletteBitsPerBlock
bits.setAt(0, 0);
for (int i = 0; i < 4096; i++) {
int ordinal = ids[i];
BlockState state = BlockState.getFromOrdinal(ordinal);
if (!state.getMaterial().isAir()) {
int mcId = registry.getInternalBlockStateId(state).getAsInt();
bits.setAt(i, mcId);
}
}
sectionWriter.write(bits.getData());
} else {
FaweCache.Palette palette = FaweCache.IMP.toPalette(0, ids);
sectionWriter.writeByte(palette.bitsPerEntry); // bits per block
sectionWriter.writeVarInt(palette.paletteToBlockLength);
for (int i = 0; i < palette.paletteToBlockLength; i++) {
int ordinal = palette.paletteToBlock[i];
switch (ordinal) {
case BlockID.CAVE_AIR:
case BlockID.VOID_AIR:
case BlockID.AIR:
case BlockID.__RESERVED__:
sectionWriter.writeVarInt(0);
break;
default:
BlockState state = BlockState.getFromOrdinal(ordinal);
int mcId = registry.getInternalBlockStateId(state).getAsInt();
sectionWriter.writeVarInt(mcId);
break;
}
}
sectionWriter.writeVarInt(palette.blockStatesLength);
for (int i = 0; i < palette.blockStatesLength; i++) {
sectionWriter.writeLong(palette.blockStates[i]);
}
}
}
// if (writeBiomes) {
// for (int x = 0; x < 16; x++) {
// for (int z = 0; z < 16; z++) {
// BiomeType biome = this.getBiomeType(x, z);
// if (biome == null) {
// if (writeBiomes) {
// break;
// } else {
// biome = BiomeTypes.FOREST;
// }
// }
// }
// }
// }
if (writeBiomes) {
for (int i = 0; i < 256; i++) {
// TODO biomes
sectionWriter.writeInt(0);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return sectionByteArray.toByteArray();
}
}

View File

@ -1,6 +1,9 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.beta.IBatchProcessor;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
public class BatchProcessorHolder implements IBatchProcessorHolder {
private IBatchProcessor processor = EmptyBatchProcessor.INSTANCE;
@ -10,6 +13,13 @@ public class BatchProcessorHolder implements IBatchProcessorHolder {
return processor;
}
@Override
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) {
System.out.println("Process set");
System.out.println(getProcessor());
return getProcessor().processSet(chunk, get, set);
}
@Override
public void setProcessor(IBatchProcessor set) {
this.processor = set;

View File

@ -4,42 +4,100 @@ import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBlocks;
import com.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.world.block.BlockID;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.registry.BlockRegistry;
import com.sk89q.jnbt.CompoundTag;
import java.util.HashMap;
import java.util.function.Function;
import java.util.function.Supplier;
public class ChunkPacket implements Function<byte[], byte[]>, Supplier<byte[]> {
private final boolean full;
private final boolean biomes;
private final IBlocks chunk;
private final int chunkX;
private final int chunkZ;
private final Supplier<IBlocks> chunkSupplier;
private IBlocks chunk;
public ChunkPacket(int chunkX, int chunkZ, IBlocks chunk, boolean replaceAllSections, boolean sendBiomeData) {
private int chunkX;
private int chunkZ;
private byte[] sectionBytes;
private Object nativePacket;
public ChunkPacket(int chunkX, int chunkZ, Supplier<IBlocks> chunkSupplier, boolean replaceAllSections) {
this.chunkX = chunkX;
this.chunkZ = chunkZ;
this.chunk = chunk;
this.chunkSupplier = chunkSupplier;
this.full = replaceAllSections;
this.biomes = sendBiomeData;
}
public int getChunkX() {
return chunkX;
}
public int getChunkZ() {
return chunkZ;
}
public synchronized void setPosition(int chunkX, int chunkZ) {
this.chunkX = chunkX;
this.chunkZ = chunkZ;
nativePacket = null;
}
public boolean isFull() {
return full;
}
public IBlocks getChunk() {
if (this.chunk == null) {
synchronized (this) {
if (this.chunk == null) {
this.chunk = chunkSupplier.get();
}
}
}
return chunk;
}
private byte[] getSectionBytes() {
byte[] tmp = this.sectionBytes;
if (tmp == null) {
synchronized (this) {
if (sectionBytes == null) {
sectionBytes = getChunk().toByteArray(FaweCache.IMP.BYTE_BUFFER_8192.get(), this.full);
}
tmp = sectionBytes;
}
}
return tmp;
}
public Object getNativePacket() {
return nativePacket;
}
public void setNativePacket(Object nativePacket) {
this.nativePacket = nativePacket;
}
@Override
@Deprecated
public byte[] get() {
System.out.println("TODO deprecated, use buffer");
return apply(new byte[8192]);
return apply(FaweCache.IMP.BYTE_BUFFER_8192.get());
}
public CompoundTag getHeightMap() {
HashMap<String, Object> map = new HashMap<>();
map.put("MOTION_BLOCKING", new long[36]);
CompoundTag tag = FaweCache.IMP.asTag(map);
// TODO
return tag;
}
@Override
public byte[] apply(byte[] buffer) {
try {
FastByteArrayOutputStream baos = new FastByteArrayOutputStream();
byte[] sectionBytes = getSectionBytes();
FastByteArrayOutputStream baos = new FastByteArrayOutputStream(buffer);
FaweOutputStream fos = new FaweOutputStream(baos);
fos.writeInt(this.chunkX);
@ -47,75 +105,16 @@ public class ChunkPacket implements Function<byte[], byte[]>, Supplier<byte[]> {
fos.writeBoolean(this.full);
fos.writeVarInt(this.chunk.getBitMask()); // writeVarInt
fos.writeVarInt(getChunk().getBitMask());
// TODO write NBTTagCompound of HeightMaps
fos.writeVarInt(0); // (Entities / NBT)
// TODO write chunk data to byte[]
{
BlockRegistry registry = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry();
try (FastByteArrayOutputStream sectionByteArray = new FastByteArrayOutputStream(buffer); FaweOutputStream sectionWriter = new FaweOutputStream(sectionByteArray)) {
for (int layer = 0; layer < FaweCache.IMP.CHUNK_LAYERS; layer++) {
if (!this.chunk.hasSection(layer)) continue;
char[] ids = this.chunk.getArray(layer);
FaweCache.Palette palette = FaweCache.IMP.toPalette(0, ids);
fos.writeNBT("", getHeightMap());
int nonEmpty = 0; // TODO optimize into same loop as toPalette
for (char id :ids) {
if (id != 0) nonEmpty++;
}
sectionWriter.writeShort(nonEmpty); // non empty
sectionWriter.writeByte(palette.bitsPerEntry); // bits per block
sectionWriter.writeVarInt(palette.paletteToBlockLength);
for (int i = 0; i < palette.paletteToBlockLength; i++) {
int ordinal = palette.paletteToBlock[i];
switch (ordinal) {
case BlockID.CAVE_AIR:
case BlockID.VOID_AIR:
case BlockID.AIR:
case BlockID.__RESERVED__:
sectionWriter.writeByte(0);
break;
default:
BlockState state = BlockState.getFromOrdinal(ordinal);
int mcId = registry.getInternalBlockStateId(state).getAsInt();
sectionWriter.writeVarInt(mcId);
}
}
sectionWriter.writeVarInt(palette.blockStatesLength);
for (int i = 0; i < palette.blockStatesLength; i++) {
sectionWriter.writeLong(palette.blockStates[i]);
}
}
// TODO write biomes
// boolean writeBiomes = true;
// for (int x = 0; x < 16; x++) {
// for (int z = 0; z < 16; z++) {
// BiomeType biome = this.chunk.getBiomeType(x, z);
// if (biome == null) {
// if (writeBiomes) {
// break;
// } else {
// biome = BiomeTypes.FOREST;
// }
// }
// }
// }
if (this.full) {
for (int i = 0; i < 256; i++) {
sectionWriter.writeInt(0);
}
}
fos.writeVarInt(sectionByteArray.getSize());
for (byte[] arr : sectionByteArray.toByteArrays()) {
fos.write(arr);
}
}
}
fos.writeVarInt(sectionBytes.length);
fos.write(sectionBytes);
// TODO entities / NBT
// Set<CompoundTag> entities = chunk.getEntities();
// Map<BlockVector3, CompoundTag> tiles = chunk.getTiles();
fos.writeVarInt(0); // (Entities / NBT)
return baos.toByteArray();
} catch (Throwable e) {

View File

@ -4,21 +4,21 @@ import com.boydti.fawe.beta.IBatchProcessor;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.object.extent.NullExtent;
import com.google.common.base.Suppliers;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.World;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class ChunkSendProcessor extends AbstractDelegateExtent implements IBatchProcessor {
public class ChunkSendProcessor implements IBatchProcessor {
private final Supplier<Stream<Player>> players;
private final World world;
public ChunkSendProcessor(Supplier<Stream<Player>> players) {
super(new NullExtent());
public ChunkSendProcessor(World world, Supplier<Stream<Player>> players) {
this.players = players;
this.world = world;
}
@Override
@ -26,10 +26,14 @@ public class ChunkSendProcessor extends AbstractDelegateExtent implements IBatch
int chunkX = chunk.getX();
int chunkZ = chunk.getZ();
boolean replaceAll = true;
boolean sendBiome = set.getBiomes() != null;
ChunkPacket packet = new ChunkPacket(chunkX, chunkZ, set, replaceAll, sendBiome);
Supplier<byte[]> packetData = Suppliers.memoize(packet::get);
players.get().forEach(plr -> plr.sendFakeChunk(chunkX, chunkZ, packetData));
ChunkPacket packet = new ChunkPacket(chunkX, chunkZ, () -> set, replaceAll);
Stream<Player> stream = this.players.get();
if (stream == null) {
world.sendFakeChunk(null, packet);
} else {
stream.filter(player -> player.getWorld().equals(world))
.forEach(player -> world.sendFakeChunk(player, packet));
}
return set;
}

View File

@ -37,6 +37,7 @@ public interface IBatchProcessorHolder extends IBatchProcessor {
@Override
default IBatchProcessor join(IBatchProcessor other) {
setProcessor(getProcessor().join(other));
System.out.println("Join " + other + " | " + getProcessor());
return this;
}

View File

@ -55,13 +55,21 @@ public class MultiBatchProcessor implements IBatchProcessor {
@Override
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) {
for (IBatchProcessor processor : this.processors) {
set = processor.processSet(chunk, get, set);
if (set == null) {
return null;
try {
System.out.println("Processes len " + this.processors.length);
for (IBatchProcessor processor : this.processors) {
set = processor.processSet(chunk, get, set);
if (set == null) {
System.out.println("Return null " + processor.getClass());
return null;
}
System.out.println("Process " + processor.getClass());
}
return set;
} catch (Throwable e) {
e.printStackTrace();
throw e;
}
return set;
}
@Override

View File

@ -0,0 +1,22 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.beta.IBatchProcessor;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.NullExtent;
public enum NullProcessor implements IBatchProcessor {
INSTANCE;
@Override
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) {
System.out.println("Null process " + chunk.getX() + "," + chunk.getZ());
return null;
}
@Override
public Extent construct(Extent child) {
return new NullExtent();
}
}

View File

@ -89,6 +89,8 @@ public class SingleThreadQueueExtent extends BatchProcessorHolder implements IQu
*/
protected synchronized void reset() {
if (!this.initialized) return;
System.out.println("Reset");
new Exception().printStackTrace();
checkThread();
if (!this.chunks.isEmpty()) {
for (IChunk chunk : this.chunks.values()) {
@ -128,6 +130,7 @@ public class SingleThreadQueueExtent extends BatchProcessorHolder implements IQu
@Override
public Extent addProcessor(IBatchProcessor processor) {
join(processor);
System.out.println("Add processor " + this.getClass());
return this;
}
@ -276,11 +279,20 @@ public class SingleThreadQueueExtent extends BatchProcessorHolder implements IQu
private void pollSubmissions(int targetSize, boolean aggressive) {
final int overflow = submissions.size() - targetSize;
if (aggressive) {
if (targetSize == 0) {
while (!submissions.isEmpty()) {
Future future = submissions.poll();
try {
while (future != null) future = (Future) future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
for (int i = 0; i < overflow; i++) {
Future first = submissions.poll();
try {
while ((first = (Future) first.get()) != null) {
}
while ((first = (Future) first.get()) != null);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
@ -327,7 +339,7 @@ public class SingleThreadQueueExtent extends BatchProcessorHolder implements IQu
chunks.clear();
}
pollSubmissions(0, true);
reset();
System.out.println(submissions.size());
}
@Override

View File

@ -2,6 +2,7 @@ package com.boydti.fawe.object.brush.visualization.cfi;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBlocks;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.ChunkPacket;
@ -21,6 +22,7 @@ import com.boydti.fawe.object.schematic.Schematic;
import com.boydti.fawe.util.CachedTextureUtil;
import com.boydti.fawe.util.RandomTextureUtil;
import com.boydti.fawe.util.ReflectionUtils;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.TextureUtil;
import com.boydti.fawe.util.image.Drawable;
import com.boydti.fawe.util.image.ImageViewer;
@ -69,7 +71,6 @@ import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Supplier;
import javax.annotation.Nullable;
// TODO FIXME
public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Drawable, VirtualWorld {
private final MutableBlockVector3 mutable = new MutableBlockVector3();
@ -282,51 +283,53 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
if (viewer != null) {
viewer.view(this);
}
// if (chunkOffset != null && player != null) { TODO NOT IMPLEMENTED
// IQueueExtent packetQueue = SetQueue.IMP.getNewQueue(player.getWorld(), true, false);
//
// if (!packetQueue.supports(Capability.CHUNK_PACKETS)) {
// return;
// }
//
// int lenCX = (getWidth() + 15) >> 4;
// int lenCZ = (getLength() + 15) >> 4;
//
// int OX = chunkOffset.getBlockX();
// int OZ = chunkOffset.getBlockZ();
//
// Location position = player.getLocation();
// int pcx = (position.getBlockX() >> 4) - OX;
// int pcz = (position.getBlockZ() >> 4) - OZ;
//
// int scx = Math.max(0, pcx - 15);
// int scz = Math.max(0, pcz - 15);
// int ecx = Math.min(lenCX - 1, pcx + 15);
// int ecz = Math.min(lenCZ - 1, pcz + 15);
//
// for (int cz = scz; cz <= ecz; cz++) {
// for (int cx = scx; cx <= ecx; cx++) {
// final int finalCX = cx;
// final int finalCZ = cz;
// TaskManager.IMP.getPublicForkJoinPool().submit(() -> {
// try {
// FaweChunk toSend = getSnapshot(finalCX, finalCZ);
// toSend.setLoc(HeightMapMCAGenerator.this, finalCX + OX, finalCZ + OZ);
// packetQueue.sendChunkUpdate(toSend, player);
// } catch (Throwable e) {
// e.printStackTrace();
// }
// });
// }
// }
// }
if (chunkOffset != null && player != null) {
World world = player.getWorld();
int lenCX = (getWidth() + 15) >> 4;
int lenCZ = (getLength() + 15) >> 4;
int OX = chunkOffset.getBlockX();
int OZ = chunkOffset.getBlockZ();
Location position = player.getLocation();
int pcx = (position.getBlockX() >> 4) - OX;
int pcz = (position.getBlockZ() >> 4) - OZ;
int scx = Math.max(0, pcx - 15);
int scz = Math.max(0, pcz - 15);
int ecx = Math.min(lenCX - 1, pcx + 15);
int ecz = Math.min(lenCZ - 1, pcz + 15);
for (int chunkZ = scz; chunkZ <= ecz; chunkZ++) {
for (int chunkX = scx; chunkX <= ecx; chunkX++) {
int finalChunkX = chunkX;
int finalChunkZ = chunkZ;
int realWorldX = chunkX + OX;
int realWorldZ = chunkZ + OZ;
Supplier<IBlocks> blocksSupplier = () -> getChunk(finalChunkX, finalChunkZ);
ChunkPacket packet = new ChunkPacket(realWorldX, realWorldZ, blocksSupplier, true);
world.sendFakeChunk(player, packet);
}
}
}
}
@Override
public void sendFakeChunk(@Nullable Player player, ChunkPacket packet) {
if (this.player != null) {
player.getWorld().sendFakeChunk(player, packet);
}
}
@Override
public void refreshChunk(int chunkX, int chunkZ) {
IChunkSet chunk = getChunk(chunkX, chunkZ);
ChunkPacket packet = new ChunkPacket(chunkX, chunkZ, chunk, true, true);
player.sendFakeChunk(chunkX, chunkZ, packet::get);
if (chunkOffset != null && player != null) {
player.getWorld().refreshChunk(chunkX, chunkZ);
}
}
public IChunkSet getChunk(int chunkX, int chunkZ) {

View File

@ -28,6 +28,10 @@ public final class BitArray4096 {
this.data = new long[longLen];
}
public long[] getData() {
return data;
}
public final void setAt(int index, int value) {
if (longLen == 0) return;
int bitIndexStart = index * bitsPerEntry;

View File

@ -59,8 +59,8 @@ public class StringMan {
}
public static String prettyFormat(double d) {
if (d == Double.MIN_VALUE) return "-∞";
if (d == Double.MAX_VALUE) return "";
if (d == Double.MIN_VALUE || d == Double.NEGATIVE_INFINITY) return "-∞";
if (d == Double.MAX_VALUE || d == Double.POSITIVE_INFINITY) return "";
if(d == (long) d) return String.format("%d",(long)d);
else return String.format("%s",d);
}

View File

@ -1,6 +1,7 @@
package com.boydti.fawe.wrappers;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.implementation.ChunkPacket;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.ExtentTraverser;
import com.boydti.fawe.util.TaskManager;
@ -13,6 +14,7 @@ import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
@ -304,4 +306,9 @@ public class WorldWrapper extends AbstractWorld {
public IChunkGet get(int x, int z) {
return parent.get(x, z);
}
@Override
public void sendFakeChunk(@Nullable Player player, ChunkPacket packet) {
parent.sendFakeChunk(player, packet);
}
}

View File

@ -167,11 +167,12 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da
}
public void writeNamedTagName(String name, int type) throws IOException {
byte[] nameBytes = name.getBytes(NBTConstants.CHARSET);
// byte[] nameBytes = name.getBytes(NBTConstants.CHARSET);
os.writeByte(type);
os.writeShort(nameBytes.length);
os.write(nameBytes);
os.writeUTF(name);
// os.writeShort(nameBytes.length);
// os.write(nameBytes);
}
public void writeLazyCompoundTag(String name, LazyWrite next) throws IOException {
@ -208,47 +209,47 @@ public final class NBTOutputStream extends OutputStream implements Closeable, Da
public void writeTagPayload(Tag tag) throws IOException {
int type = NBTUtils.getTypeCode(tag.getClass());
switch (type) {
case NBTConstants.TYPE_END:
writeEndTagPayload((EndTag) tag);
break;
case NBTConstants.TYPE_BYTE:
writeByteTagPayload((ByteTag) tag);
break;
case NBTConstants.TYPE_SHORT:
writeShortTagPayload((ShortTag) tag);
break;
case NBTConstants.TYPE_INT:
writeIntTagPayload((IntTag) tag);
break;
case NBTConstants.TYPE_LONG:
writeLongTagPayload((LongTag) tag);
break;
case NBTConstants.TYPE_FLOAT:
writeFloatTagPayload((FloatTag) tag);
break;
case NBTConstants.TYPE_DOUBLE:
writeDoubleTagPayload((DoubleTag) tag);
break;
case NBTConstants.TYPE_BYTE_ARRAY:
writeByteArrayTagPayload((ByteArrayTag) tag);
break;
case NBTConstants.TYPE_STRING:
writeStringTagPayload((StringTag) tag);
break;
case NBTConstants.TYPE_LIST:
writeListTagPayload((ListTag) tag);
break;
case NBTConstants.TYPE_COMPOUND:
writeCompoundTagPayload((CompoundTag) tag);
break;
case NBTConstants.TYPE_INT_ARRAY:
writeIntArrayTagPayload((IntArrayTag) tag);
break;
case NBTConstants.TYPE_LONG_ARRAY:
writeLongArrayTagPayload((LongArrayTag) tag);
break;
default:
throw new IOException("Invalid tag type: " + type + ".");
case NBTConstants.TYPE_END:
writeEndTagPayload((EndTag) tag);
break;
case NBTConstants.TYPE_BYTE:
writeByteTagPayload((ByteTag) tag);
break;
case NBTConstants.TYPE_SHORT:
writeShortTagPayload((ShortTag) tag);
break;
case NBTConstants.TYPE_INT:
writeIntTagPayload((IntTag) tag);
break;
case NBTConstants.TYPE_LONG:
writeLongTagPayload((LongTag) tag);
break;
case NBTConstants.TYPE_FLOAT:
writeFloatTagPayload((FloatTag) tag);
break;
case NBTConstants.TYPE_DOUBLE:
writeDoubleTagPayload((DoubleTag) tag);
break;
case NBTConstants.TYPE_BYTE_ARRAY:
writeByteArrayTagPayload((ByteArrayTag) tag);
break;
case NBTConstants.TYPE_STRING:
writeStringTagPayload((StringTag) tag);
break;
case NBTConstants.TYPE_LIST:
writeListTagPayload((ListTag) tag);
break;
case NBTConstants.TYPE_COMPOUND:
writeCompoundTagPayload((CompoundTag) tag);
break;
case NBTConstants.TYPE_INT_ARRAY:
writeIntArrayTagPayload((IntArrayTag) tag);
break;
case NBTConstants.TYPE_LONG_ARRAY:
writeLongArrayTagPayload((LongArrayTag) tag);
break;
default:
throw new IOException("Invalid tag type: " + type + ".");
}
}

View File

@ -540,6 +540,7 @@ public class ClipboardCommands {
@Command(
name = "/rotate",
aliases = {"/rt"},
desc = "Rotate the contents of the clipboard",
descFooter = "Non-destructively rotate the contents of the clipboard.\n" +
"Angles are provided in degrees and a positive angle will result in a clockwise rotation. " +

View File

@ -219,8 +219,8 @@ public class HistoryCommands {
}
@Command(
name = "undo",
aliases = { "/undo" },
name = "/undo",
aliases = { "/un", "/ud", "undo" },
desc = "Undoes the last action (from history)"
)
@CommandPermissions({"worldedit.history.undo", "worldedit.history.undo.self"})
@ -266,8 +266,8 @@ public class HistoryCommands {
}
@Command(
name = "redo",
aliases = { "/redo" },
name = "/redo",
aliases = { "/do", "/rd", "redo" },
desc = "Redoes the last action (from history)"
)
@CommandPermissions({"worldedit.history.redo", "worldedit.history.redo.self"})

View File

@ -31,6 +31,8 @@ import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.implementation.ChunkSendProcessor;
import com.boydti.fawe.beta.implementation.NullProcessor;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FaweLimit;
import com.sk89q.jnbt.CompoundTag;
@ -74,8 +76,13 @@ import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Stream;
import com.sk89q.worldedit.world.block.BlockTypes;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
@ -102,15 +109,29 @@ public class RegionCommands {
}
@Command(
name = "/set",
desc = "Sets all the blocks in the region"
name = "/air",
aliases = {"/0"},
desc = "Sets all the blocks in the region to air"
)
@CommandPermissions("worldedit.region.set")
@Logging(REGION)
public void air(Actor actor, EditSession editSession,
@Selection Region region,
InjectedValueAccess context) throws WorldEditException {
set(actor, editSession, region, BlockTypes.AIR, context);
}
@Command(
name = "/set",
aliases = {"/"},
desc = "Sets all the blocks in the region"
)
@CommandPermissions("worldedit.region.set")
@Logging(REGION)
public void set(Actor actor, EditSession editSession,
@Selection Region region,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern, InjectedValueAccess context) throws WorldEditException {
@Selection Region region,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern, InjectedValueAccess context) throws WorldEditException {
actor.checkConfirmationRegion(() -> {
int affected = editSession.setBlocks(region, pattern);
if (affected != 0) {
@ -121,6 +142,22 @@ public class RegionCommands {
}, getArguments(context), region, context);
}
@Command(
name = "/test",
desc = "test region"
)
@CommandPermissions("worldedit.region.test")
@Logging(REGION)
public void test(World world, Player player, EditSession editSession,
@Selection Region region,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern, InjectedValueAccess context) throws WorldEditException {
editSession.addProcessor(new ChunkSendProcessor(world, () -> Stream.of(player)));
editSession.addProcessor(NullProcessor.INSTANCE);
editSession.setBlocks(region, pattern);
System.out.println("Done");
}
@Command(
name = "/fixlighting",
desc = "Get the light at a position"
@ -267,7 +304,7 @@ public class RegionCommands {
@Command(
name = "/replace",
aliases = { "/re", "/rep", "/r" },
aliases = { "/repl", "/rep" },
desc = "Replace all blocks in the selection with another"
)
@CommandPermissions("worldedit.region.replace")
@ -459,6 +496,7 @@ public class RegionCommands {
@Command(
name = "/move",
aliases = {"/mv"},
desc = "Move the contents of the selection"
)
@CommandPermissions("worldedit.region.move")

View File

@ -194,8 +194,8 @@ public class ToolUtilCommands {
}
@Command(
name = "/",
aliases = {","},
name = "/superpickaxe",
aliases = {",", "sp", "/sp", "superpickaxe", "/pickaxe"},
desc = "Toggle the super pickaxe function"
)
@CommandPermissions("worldedit.superpickaxe")

View File

@ -421,7 +421,7 @@ public class UtilityCommands {
@Command(
name = "replacenear",
aliases = { "/replacenear" },
aliases = { "/replacenear", "/rn" },
desc = "Replace nearby blocks"
)
@CommandPermissions("worldedit.replacenear")

View File

@ -20,6 +20,7 @@
package com.sk89q.worldedit.entity;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.beta.implementation.ChunkPacket;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
@ -321,8 +322,6 @@ public interface Player extends Entity, Actor {
*/
<B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, @Nullable B block);
void sendFakeChunk(int chunkX, int chunkZ, Supplier<byte[]> data);
public Region[] getCurrentRegions();
Region[] getCurrentRegions(FaweMaskManager.MaskType type);

View File

@ -212,11 +212,6 @@ public class PlayerProxy extends AbstractPlayerActor {
basePlayer.sendFakeBlock(pos, block);
}
@Override
public void sendFakeChunk(int chunkX, int chunkZ, Supplier<byte[]> data) {
basePlayer.sendFakeChunk(chunkX, chunkZ, data);
}
@Override
public void sendTitle(String title, String sub) {
basePlayer.sendTitle(title, sub);

View File

@ -20,6 +20,7 @@
package com.sk89q.worldedit.world;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.implementation.ChunkPacket;
import com.boydti.fawe.beta.implementation.NullChunkGet;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.EditSession;
@ -28,6 +29,7 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
@ -207,4 +209,8 @@ public class NullWorld extends AbstractWorld {
return INSTANCE;
}
@Override
public void sendFakeChunk(@Nullable Player player, ChunkPacket packet) {
}
}

View File

@ -20,6 +20,7 @@
package com.sk89q.worldedit.world;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.implementation.ChunkPacket;
import com.boydti.fawe.beta.implementation.IChunkCache;
import com.boydti.fawe.object.extent.LightingExtent;
import com.sk89q.worldedit.EditSession;
@ -27,6 +28,7 @@ import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask;
@ -304,4 +306,11 @@ public interface World extends Extent, Keyed, IChunkCache<IChunkGet> {
@Override
IChunkGet get(int x, int z);
/**
* Send a fake chunk to a player/s
* @param player may be null to send to everyone
* @param packet the chunk packet
*/
void sendFakeChunk(@Nullable Player player, ChunkPacket packet);
}