Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-07 20:10:06 +01:00
set blocks
Dieser Commit ist enthalten in:
Ursprung
f96760b36c
Commit
adb2c37a02
@ -7,11 +7,14 @@ import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks;
|
||||
import com.boydti.fawe.beta.implementation.holder.ChunkHolder;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import net.jpountz.util.UnsafeUtils;
|
||||
import net.minecraft.server.v1_13_R2.Chunk;
|
||||
import net.minecraft.server.v1_13_R2.ChunkSection;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
public class BukkitChunkHolder<T extends Future<T>> extends ChunkHolder {
|
||||
@Override
|
||||
@ -33,20 +36,73 @@ public class BukkitChunkHolder<T extends Future<T>> extends ChunkHolder {
|
||||
int X = getX();
|
||||
int Z = getZ();
|
||||
|
||||
Chunk currentNmsChunk = extent.ensureLoaded(X, Z);
|
||||
ChunkSection[] sections = currentNmsChunk.getSections();
|
||||
World world = extent.getBukkitWorld();
|
||||
boolean hasSky = world.getEnvironment() == World.Environment.NORMAL;
|
||||
Chunk nmsChunk = extent.ensureLoaded(X, Z);
|
||||
try {
|
||||
synchronized (nmsChunk) {
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
World world = extent.getBukkitWorld();
|
||||
boolean hasSky = world.getEnvironment() == World.Environment.NORMAL;
|
||||
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (!set.hasSection(layer)) continue;
|
||||
char[] arr = set.blocks[layer];
|
||||
ChunkSection newSection = extent.newChunkSection(layer, hasSky, arr);
|
||||
sections[layer] = newSection;
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (!set.hasSection(layer)) continue;
|
||||
char[] setArr = set.blocks[layer];
|
||||
ChunkSection newSection;
|
||||
ChunkSection existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
newSection = extent.newChunkSection(layer, hasSky, setArr);
|
||||
if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) {
|
||||
continue;
|
||||
} else {
|
||||
existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
DelegateLock lock = BukkitQueue.applyLock(existingSection);
|
||||
synchronized (lock) {
|
||||
if (lock.isLocked()) {
|
||||
lock.lock();
|
||||
lock.unlock();
|
||||
}
|
||||
synchronized (get) {
|
||||
ChunkSection getSection;
|
||||
if (get.nmsChunk != nmsChunk) {
|
||||
get.nmsChunk = nmsChunk;
|
||||
get.sections = null;
|
||||
get.reset();
|
||||
System.out.println("chunk doesn't match");
|
||||
} else {
|
||||
getSection = get.getSections()[layer];
|
||||
if (getSection != existingSection) {
|
||||
get.sections[layer] = existingSection;
|
||||
get.reset();
|
||||
System.out.println("Section doesn't match");
|
||||
} else if (lock.isModified()) {
|
||||
System.out.println("lock is outdated");
|
||||
get.reset(layer);
|
||||
}
|
||||
}
|
||||
char[] getArr = get.load(layer);
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char value = setArr[i];
|
||||
if (value != 0) {
|
||||
getArr[i] = value;
|
||||
}
|
||||
}
|
||||
newSection = extent.newChunkSection(layer, hasSky, getArr);
|
||||
if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) {
|
||||
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
extent.returnToPool(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
- getBlocks
|
||||
|
@ -62,85 +62,97 @@ public class BukkitGetBlocks extends CharGetBlocks {
|
||||
if (data == null || data == FaweCache.EMPTY_CHAR_4096) {
|
||||
data = new char[4096];
|
||||
}
|
||||
DelegateLock lock = BukkitQueue.applyLock(section);
|
||||
synchronized (lock) {
|
||||
if (lock.isLocked()) {
|
||||
lock.lock();
|
||||
lock.unlock();
|
||||
}
|
||||
lock.setModified(false);
|
||||
// Efficiently convert ChunkSection to raw data
|
||||
try {
|
||||
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
final DataBits bits = (DataBits) BukkitQueue_1_13.fieldBits.get(blocks);
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitQueue_1_13.fieldPalette.get(blocks);
|
||||
final int bitsPerEntry = bits.c();
|
||||
|
||||
// Efficiently convert ChunkSection to raw data
|
||||
try {
|
||||
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
final DataBits bits = (DataBits) BukkitQueue_1_13.fieldBits.get(blocks);
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitQueue_1_13.fieldPalette.get(blocks);
|
||||
final int bitsPerEntry = bits.c();
|
||||
final long[] blockStates = bits.a();
|
||||
new BitArray4096(blockStates, bitsPerEntry).toRaw(data);
|
||||
|
||||
final long[] blockStates = bits.a();
|
||||
new BitArray4096(blockStates, bitsPerEntry).toRaw(data);
|
||||
int num_palette;
|
||||
if (palette instanceof DataPaletteLinear) {
|
||||
num_palette = ((DataPaletteLinear<IBlockData>) palette).b();
|
||||
} else if (palette instanceof DataPaletteHash) {
|
||||
num_palette = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
num_palette = 0;
|
||||
int[] paletteToBlockInts = FaweCache.PALETTE_TO_BLOCK.get();
|
||||
char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
char ordinal = paletteToBlockChars[paletteVal];
|
||||
if (ordinal == Character.MAX_VALUE) {
|
||||
paletteToBlockInts[num_palette++] = paletteVal;
|
||||
IBlockData ibd = palette.a(data[i]);
|
||||
if (ibd == null) {
|
||||
ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
} else {
|
||||
ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd);
|
||||
}
|
||||
paletteToBlockChars[paletteVal] = ordinal;
|
||||
}
|
||||
data[i] = ordinal;
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
int paletteVal = paletteToBlockInts[i];
|
||||
paletteToBlockChars[paletteVal] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
int num_palette;
|
||||
if (palette instanceof DataPaletteLinear) {
|
||||
num_palette = ((DataPaletteLinear<IBlockData>) palette).b();
|
||||
} else if (palette instanceof DataPaletteHash) {
|
||||
num_palette = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
num_palette = 0;
|
||||
int[] paletteToBlockInts = FaweCache.PALETTE_TO_BLOCK.get();
|
||||
char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
IBlockData ibd = palette.a(i);
|
||||
char ordinal;
|
||||
if (ibd == null) {
|
||||
ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
System.out.println("Invalid palette");
|
||||
} else {
|
||||
ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd);
|
||||
}
|
||||
paletteToBlockChars[i] = ordinal;
|
||||
}
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
char ordinal = paletteToBlockChars[paletteVal];
|
||||
if (ordinal == Character.MAX_VALUE) {
|
||||
paletteToBlockInts[num_palette++] = paletteVal;
|
||||
IBlockData ibd = palette.a(data[i]);
|
||||
if (ibd == null) {
|
||||
ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
} else {
|
||||
ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd);
|
||||
}
|
||||
paletteToBlockChars[paletteVal] = ordinal;
|
||||
}
|
||||
data[i] = ordinal;
|
||||
data[i] = paletteToBlockChars[paletteVal];
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
int paletteVal = paletteToBlockInts[i];
|
||||
paletteToBlockChars[paletteVal] = Character.MAX_VALUE;
|
||||
paletteToBlockChars[i] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
IBlockData ibd = palette.a(i);
|
||||
char ordinal;
|
||||
if (ibd == null) {
|
||||
ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
System.out.println("Invalid palette");
|
||||
} else {
|
||||
ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd);
|
||||
}
|
||||
paletteToBlockChars[i] = ordinal;
|
||||
}
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
data[i] = paletteToBlockChars[paletteVal];
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
paletteToBlockChars[i] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
return data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public ChunkSection[] getSections() {
|
||||
ChunkSection[] tmp = sections;
|
||||
if (tmp == null) {
|
||||
Chunk chunk = getChunk();
|
||||
sections = tmp = chunk.getSections();
|
||||
synchronized (this) {
|
||||
tmp = sections;
|
||||
if (tmp == null) {
|
||||
Chunk chunk = getChunk();
|
||||
sections = tmp = chunk.getSections().clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
@ -148,7 +160,12 @@ public class BukkitGetBlocks extends CharGetBlocks {
|
||||
public Chunk getChunk() {
|
||||
Chunk tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
nmsChunk = tmp = BukkitQueue.ensureLoaded(nmsWorld, X, Z);
|
||||
synchronized (this) {
|
||||
tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
nmsChunk = tmp = BukkitQueue.ensureLoaded(nmsWorld, X, Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.block.BlockID;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import net.jpountz.util.UnsafeUtils;
|
||||
import net.minecraft.server.v1_13_R2.Block;
|
||||
import net.minecraft.server.v1_13_R2.Chunk;
|
||||
import net.minecraft.server.v1_13_R2.ChunkCoordIntPair;
|
||||
@ -34,9 +35,13 @@ import org.bukkit.craftbukkit.v1_13_R2.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_13_R2.CraftWorld;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -99,6 +104,11 @@ public class BukkitQueue extends SimpleCharQueueExtent {
|
||||
public final static Field fieldTickingBlockCount;
|
||||
public final static Field fieldNonEmptyBlockCount;
|
||||
|
||||
private static final int CHUNKSECTION_BASE;
|
||||
private static final int CHUNKSECTION_SHIFT;
|
||||
|
||||
private static final Field fieldLock;
|
||||
|
||||
static {
|
||||
try {
|
||||
fieldSize = DataPaletteBlock.class.getDeclaredField("i");
|
||||
@ -114,6 +124,20 @@ public class BukkitQueue extends SimpleCharQueueExtent {
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount");
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
|
||||
fieldLock = DataPaletteBlock.class.getDeclaredField("j");
|
||||
fieldLock.setAccessible(true);
|
||||
Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||||
int modifiers = modifiersField.getInt(fieldLock);
|
||||
modifiers &= ~Modifier.FINAL;
|
||||
modifiersField.setInt(fieldLock, modifiers);
|
||||
|
||||
Unsafe unsafe = UnsafeUtils.getUNSAFE();
|
||||
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(ChunkSection[].class);
|
||||
int scale = unsafe.arrayIndexScale(ChunkSection[].class);
|
||||
if ((scale & (scale - 1)) != 0)
|
||||
throw new Error("data type scale not a power of two");
|
||||
CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale);
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Throwable rethrow) {
|
||||
@ -122,6 +146,32 @@ public class BukkitQueue extends SimpleCharQueueExtent {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean setSectionAtomic(ChunkSection[] sections, ChunkSection expected, ChunkSection value, int layer) {
|
||||
long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE;
|
||||
if (layer >= 0 && layer < sections.length) {
|
||||
return UnsafeUtils.getUNSAFE().compareAndSwapObject(sections, offset, expected, value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static DelegateLock applyLock(ChunkSection section) {
|
||||
try {
|
||||
synchronized (section) {
|
||||
DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
ReentrantLock currentLock = (ReentrantLock) fieldLock.get(blocks);
|
||||
if (currentLock instanceof DelegateLock) {
|
||||
return (DelegateLock) currentLock;
|
||||
}
|
||||
DelegateLock newLock = new DelegateLock(currentLock);
|
||||
fieldLock.set(blocks, newLock);
|
||||
return newLock;
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean PAPER = true;
|
||||
|
||||
public Chunk ensureLoaded(int X, int Z) {
|
||||
|
@ -13,6 +13,14 @@ public class DelegateLock extends ReentrantLock {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
return modified;
|
||||
}
|
||||
|
||||
public void setModified(boolean modified) {
|
||||
this.modified = modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
modified = true;
|
||||
@ -35,12 +43,16 @@ public class DelegateLock extends ReentrantLock {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unlock() {
|
||||
public void unlock() {
|
||||
modified = true;
|
||||
parent.unlock();
|
||||
this.notifyAll();
|
||||
}
|
||||
|
||||
public ReentrantLock getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Condition newCondition() {
|
||||
return parent.newCondition();
|
||||
|
@ -78,6 +78,10 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
// Pool discarded chunks for reuse (can safely be cleared by another thread)
|
||||
private static final ConcurrentLinkedQueue<IChunk> CHUNK_POOL = new ConcurrentLinkedQueue<>();
|
||||
|
||||
public void returnToPool(IChunk chunk) {
|
||||
CHUNK_POOL.add(chunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T submit(final IChunk<T> chunk) {
|
||||
if (chunk.isEmpty()) {
|
||||
@ -123,7 +127,6 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
private IChunk poolOrCreate(final int X, final int Z) {
|
||||
IChunk next = CHUNK_POOL.poll();
|
||||
if (next == null) {
|
||||
System.out.println("Create");
|
||||
next = create(false);
|
||||
}
|
||||
next.init(this, X, Z);
|
||||
|
@ -30,6 +30,10 @@ public class CharBlocks implements IBlocks {
|
||||
for (int i = 0; i < 16; i++) sections[i] = NULL;
|
||||
}
|
||||
|
||||
public void reset(int layer) {
|
||||
sections[layer] = NULL;
|
||||
}
|
||||
|
||||
protected char[] load(int layer) {
|
||||
return new char[4096];
|
||||
}
|
||||
|
@ -144,4 +144,8 @@ public enum UnsafeUtils {
|
||||
public static void writeShort(short[] dest, int destOff, int value) {
|
||||
UNSAFE.putShort(dest, SHORT_ARRAY_OFFSET + SHORT_ARRAY_SCALE * destOff, (short) value);
|
||||
}
|
||||
|
||||
public static Unsafe getUNSAFE() {
|
||||
return UNSAFE;
|
||||
}
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren