Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-09-06 16:12:51 +02:00
Fix relight and removelight (#475)
* Start work on lighting engine (does not build) * Implement getLighting * Setting, flushing light etc works. Getting light should be working..? * Better queue/chunk handling * Use correct location for lighting update * Correct set location, remove debug * cleanup a little * Fix fixlight * Apply to all versions for the numpties * Remove lighting extent if not using * Actually bitmask blocks when setting in chunks * Initialise Maps and Dequeues with inital size * format * Documentation maybe
Dieser Commit ist enthalten in:
Ursprung
1ff5e7761b
Commit
bdc14c10c7
@ -30,6 +30,7 @@ import net.minecraft.server.v1_14_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_14_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_14_R1.GameProfileSerializer;
|
||||
import net.minecraft.server.v1_14_R1.IBlockData;
|
||||
import net.minecraft.server.v1_14_R1.PacketPlayOutLightUpdate;
|
||||
import net.minecraft.server.v1_14_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_14_R1.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_14_R1.World;
|
||||
@ -167,7 +168,7 @@ public final class BukkitAdapter_1_14 extends NMSAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendChunk(net.minecraft.server.v1_14_R1.WorldServer nmsWorld, int X, int Z, int mask) {
|
||||
public static void sendChunk(net.minecraft.server.v1_14_R1.WorldServer nmsWorld, int X, int Z, int mask, boolean lighting) {
|
||||
PlayerChunk playerChunk = getPlayerChunk(nmsWorld, X, Z);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
@ -187,6 +188,15 @@ public final class BukkitAdapter_1_14 extends NMSAdapter {
|
||||
|
||||
fieldDirtyBits.set(playerChunk, dirtyBits);
|
||||
fieldDirtyCount.set(playerChunk, 64);
|
||||
|
||||
if (lighting) {
|
||||
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(X, Z);
|
||||
PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine());
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(packet);
|
||||
});
|
||||
}
|
||||
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -54,10 +54,13 @@ import net.minecraft.server.v1_14_R1.DataPaletteHash;
|
||||
import net.minecraft.server.v1_14_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_14_R1.Entity;
|
||||
import net.minecraft.server.v1_14_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_14_R1.EnumSkyBlock;
|
||||
import net.minecraft.server.v1_14_R1.IBlockData;
|
||||
import net.minecraft.server.v1_14_R1.LightEngineThreaded;
|
||||
import net.minecraft.server.v1_14_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_14_R1.NBTTagInt;
|
||||
import net.minecraft.server.v1_14_R1.NibbleArray;
|
||||
import net.minecraft.server.v1_14_R1.SectionPosition;
|
||||
import net.minecraft.server.v1_14_R1.TileEntity;
|
||||
import net.minecraft.server.v1_14_R1.WorldServer;
|
||||
import org.bukkit.World;
|
||||
@ -72,6 +75,8 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
||||
public Chunk nmsChunk;
|
||||
public WorldServer world;
|
||||
public int X, Z;
|
||||
public NibbleArray[] blockLight = new NibbleArray[16];
|
||||
public NibbleArray[] skyLight = new NibbleArray[16];
|
||||
|
||||
public BukkitGetBlocks_1_14(World world, int X, int Z) {
|
||||
this(((CraftWorld) world).getHandle(), X, Z);
|
||||
@ -119,6 +124,26 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (skyLight[layer] == null) {
|
||||
skyLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(SectionPosition.a(nmsChunk.getPos(), layer));
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (blockLight[layer] == null) {
|
||||
blockLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(SectionPosition.a(nmsChunk.getPos(), layer));
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
Entity entity = world.getEntity(uuid);
|
||||
@ -322,6 +347,29 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
||||
}
|
||||
}
|
||||
|
||||
boolean lightUpdate = false;
|
||||
|
||||
// Lighting
|
||||
char[][] light = set.getLight();
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.BLOCK);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
char[][] skyLight = set.getSkyLight();
|
||||
if (skyLight != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(skyLight, EnumSkyBlock.SKY);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Runnable[] syncTasks = null;
|
||||
|
||||
int bx = X << 4;
|
||||
@ -427,24 +475,19 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
||||
};
|
||||
}
|
||||
|
||||
{//Lighting
|
||||
// TODO optimize, cause this is really slow
|
||||
LightEngineThreaded engine = (LightEngineThreaded) nmsChunk.e();
|
||||
engine.a(nmsChunk, false);
|
||||
}
|
||||
|
||||
Runnable callback;
|
||||
if (bitMask == 0 && biomes == null) {
|
||||
if (bitMask == 0 && biomes == null && !lightUpdate) {
|
||||
callback = null;
|
||||
} else {
|
||||
int finalMask = bitMask;
|
||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||
boolean finalLightUpdate = lightUpdate;
|
||||
callback = () -> {
|
||||
// Set Modified
|
||||
nmsChunk.d(true); // Set Modified
|
||||
nmsChunk.mustNotSave = false;
|
||||
nmsChunk.markDirty();
|
||||
// send to player
|
||||
BukkitAdapter_1_14.sendChunk(nmsWorld, X, Z, finalMask);
|
||||
BukkitAdapter_1_14.sendChunk(nmsWorld, X, Z, finalMask, finalLightUpdate);
|
||||
if (finalizer != null) finalizer.run();
|
||||
};
|
||||
}
|
||||
@ -617,6 +660,25 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void fillLightNibble(char[][] light, EnumSkyBlock skyBlock) {
|
||||
for (int Y = 0; Y < 16; Y++) {
|
||||
if (light[Y] == null) {
|
||||
continue;
|
||||
}
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(SectionPosition.a(nmsChunk.getPos(), Y));
|
||||
if (nibble == null) {
|
||||
continue;
|
||||
}
|
||||
synchronized (nibble) {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
if (light[Y][i] < 16) {
|
||||
nibble.a(i, light[Y][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return getSections()[layer] != null;
|
||||
|
@ -24,6 +24,7 @@ import net.minecraft.server.v1_15_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_15_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_15_R1.GameProfileSerializer;
|
||||
import net.minecraft.server.v1_15_R1.IBlockData;
|
||||
import net.minecraft.server.v1_15_R1.PacketPlayOutLightUpdate;
|
||||
import net.minecraft.server.v1_15_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_15_R1.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_15_R1.World;
|
||||
@ -85,6 +86,8 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
|
||||
fieldDirtyBits = PlayerChunk.class.getDeclaredField("r");
|
||||
fieldDirtyBits.setAccessible(true);
|
||||
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
|
||||
Method declaredGetVisibleChunk = PlayerChunkMap.class.getDeclaredMethod("getVisibleChunk", long.class);
|
||||
declaredGetVisibleChunk.setAccessible(true);
|
||||
methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk);
|
||||
@ -165,7 +168,7 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendChunk(net.minecraft.server.v1_15_R1.WorldServer nmsWorld, int X, int Z, int mask) {
|
||||
public static void sendChunk(net.minecraft.server.v1_15_R1.WorldServer nmsWorld, int X, int Z, int mask, boolean lighting) {
|
||||
PlayerChunk playerChunk = getPlayerChunk(nmsWorld, X, Z);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
@ -185,6 +188,15 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
|
||||
|
||||
fieldDirtyBits.set(playerChunk, dirtyBits);
|
||||
fieldDirtyCount.set(playerChunk, 64);
|
||||
|
||||
if (lighting) {
|
||||
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(X, Z);
|
||||
PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine());
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(packet);
|
||||
});
|
||||
}
|
||||
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -55,10 +55,13 @@ import net.minecraft.server.v1_15_R1.DataPaletteHash;
|
||||
import net.minecraft.server.v1_15_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_15_R1.Entity;
|
||||
import net.minecraft.server.v1_15_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_15_R1.EnumSkyBlock;
|
||||
import net.minecraft.server.v1_15_R1.IBlockData;
|
||||
import net.minecraft.server.v1_15_R1.LightEngineThreaded;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagInt;
|
||||
import net.minecraft.server.v1_15_R1.NibbleArray;
|
||||
import net.minecraft.server.v1_15_R1.SectionPosition;
|
||||
import net.minecraft.server.v1_15_R1.TileEntity;
|
||||
import net.minecraft.server.v1_15_R1.WorldServer;
|
||||
import org.bukkit.World;
|
||||
@ -75,6 +78,8 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
|
||||
public Chunk nmsChunk;
|
||||
public WorldServer world;
|
||||
public int X, Z;
|
||||
public NibbleArray[] blockLight = new NibbleArray[16];
|
||||
public NibbleArray[] skyLight = new NibbleArray[16];
|
||||
|
||||
public BukkitGetBlocks_1_15(World world, int X, int Z) {
|
||||
this(((CraftWorld) world).getHandle(), X, Z);
|
||||
@ -127,6 +132,26 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
|
||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (skyLight[layer] == null) {
|
||||
skyLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(SectionPosition.a(nmsChunk.getPos(), layer));
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (blockLight[layer] == null) {
|
||||
blockLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(SectionPosition.a(nmsChunk.getPos(), layer));
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
Entity entity = world.getEntity(uuid);
|
||||
@ -335,6 +360,29 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
|
||||
}
|
||||
}
|
||||
|
||||
boolean lightUpdate = false;
|
||||
|
||||
// Lighting
|
||||
char[][] light = set.getLight();
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.BLOCK);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
char[][] skyLight = set.getSkyLight();
|
||||
if (skyLight != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(skyLight, EnumSkyBlock.SKY);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Runnable[] syncTasks = null;
|
||||
|
||||
int bx = X << 4;
|
||||
@ -440,25 +488,19 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
|
||||
};
|
||||
}
|
||||
|
||||
//Lighting
|
||||
// TODO optimize, cause this is really slow
|
||||
LightEngineThreaded engine = (LightEngineThreaded) nmsChunk.e();
|
||||
//lightChunk()
|
||||
engine.a(nmsChunk, false);
|
||||
|
||||
Runnable callback;
|
||||
if (bitMask == 0 && biomes == null) {
|
||||
if (bitMask == 0 && biomes == null && !lightUpdate) {
|
||||
callback = null;
|
||||
} else {
|
||||
int finalMask = bitMask;
|
||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||
boolean finalLightUpdate = lightUpdate;
|
||||
callback = () -> {
|
||||
// Set Modified
|
||||
//setLastSaveHadEntities
|
||||
nmsChunk.d(true); // Set Modified
|
||||
nmsChunk.mustNotSave = false;
|
||||
nmsChunk.markDirty();
|
||||
// send to player
|
||||
BukkitAdapter_1_15.sendChunk(nmsWorld, X, Z, finalMask);
|
||||
BukkitAdapter_1_15.sendChunk(nmsWorld, X, Z, finalMask, finalLightUpdate);
|
||||
if (finalizer != null) finalizer.run();
|
||||
};
|
||||
}
|
||||
@ -637,6 +679,25 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void fillLightNibble(char[][] light, EnumSkyBlock skyBlock) {
|
||||
for (int Y = 0; Y < 16; Y++) {
|
||||
if (light[Y] == null) {
|
||||
continue;
|
||||
}
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(SectionPosition.a(nmsChunk.getPos(), Y));
|
||||
if (nibble == null) {
|
||||
continue;
|
||||
}
|
||||
synchronized (nibble) {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
if (light[Y][i] < 16) {
|
||||
nibble.a(i, light[Y][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return getSections()[layer] != null;
|
||||
|
@ -13,12 +13,6 @@ import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import net.jpountz.util.UnsafeUtils;
|
||||
import net.minecraft.server.v1_15_R1.Block;
|
||||
import net.minecraft.server.v1_15_R1.Chunk;
|
||||
@ -30,6 +24,11 @@ import net.minecraft.server.v1_15_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_15_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_15_R1.GameProfileSerializer;
|
||||
import net.minecraft.server.v1_15_R1.IBlockData;
|
||||
import net.minecraft.server.v1_15_R1.LightEngine;
|
||||
import net.minecraft.server.v1_15_R1.LightEngineLayer;
|
||||
import net.minecraft.server.v1_15_R1.LightEngineStorage;
|
||||
import net.minecraft.server.v1_15_R1.NibbleArray;
|
||||
import net.minecraft.server.v1_15_R1.PacketPlayOutLightUpdate;
|
||||
import net.minecraft.server.v1_15_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_15_R1.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_15_R1.World;
|
||||
@ -38,9 +37,15 @@ import org.bukkit.craftbukkit.v1_15_R1.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class BukkitAdapter_1_15_2 extends NMSAdapter {
|
||||
@ -60,6 +65,8 @@ public final class BukkitAdapter_1_15_2 extends NMSAdapter {
|
||||
|
||||
private final static MethodHandle methodGetVisibleChunk;
|
||||
|
||||
public final static MethodHandle methodSetLightNibbleArray;
|
||||
|
||||
private static final int CHUNKSECTION_BASE;
|
||||
private static final int CHUNKSECTION_SHIFT;
|
||||
|
||||
@ -90,6 +97,10 @@ public final class BukkitAdapter_1_15_2 extends NMSAdapter {
|
||||
declaredGetVisibleChunk.setAccessible(true);
|
||||
methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk);
|
||||
|
||||
Method declaredSetLightNibbleArray = LightEngineStorage.class.getDeclaredMethod("a", long.class, NibbleArray.class);
|
||||
declaredSetLightNibbleArray.setAccessible(true);
|
||||
methodSetLightNibbleArray = MethodHandles.lookup().unreflect(declaredSetLightNibbleArray);
|
||||
|
||||
Field tmp = DataPaletteBlock.class.getDeclaredField("j");
|
||||
ReflectionUtils.setAccessibleNonFinal(tmp);
|
||||
fieldLock = tmp;
|
||||
@ -167,7 +178,7 @@ public final class BukkitAdapter_1_15_2 extends NMSAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendChunk(WorldServer nmsWorld, int X, int Z, int mask) {
|
||||
public static void sendChunk(WorldServer nmsWorld, int X, int Z, int mask, boolean lighting) {
|
||||
PlayerChunk playerChunk = getPlayerChunk(nmsWorld, X, Z);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
@ -187,6 +198,15 @@ public final class BukkitAdapter_1_15_2 extends NMSAdapter {
|
||||
|
||||
fieldDirtyBits.set(playerChunk, dirtyBits);
|
||||
fieldDirtyCount.set(playerChunk, 64);
|
||||
|
||||
if (lighting) {
|
||||
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(X, Z);
|
||||
PacketPlayOutLightUpdate packet = new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine());
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(packet);
|
||||
});
|
||||
}
|
||||
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -38,10 +38,12 @@ import net.minecraft.server.v1_15_R1.DataPaletteHash;
|
||||
import net.minecraft.server.v1_15_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_15_R1.Entity;
|
||||
import net.minecraft.server.v1_15_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_15_R1.EnumSkyBlock;
|
||||
import net.minecraft.server.v1_15_R1.IBlockData;
|
||||
import net.minecraft.server.v1_15_R1.LightEngineThreaded;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagInt;
|
||||
import net.minecraft.server.v1_15_R1.NibbleArray;
|
||||
import net.minecraft.server.v1_15_R1.SectionPosition;
|
||||
import net.minecraft.server.v1_15_R1.TileEntity;
|
||||
import net.minecraft.server.v1_15_R1.WorldServer;
|
||||
import org.bukkit.World;
|
||||
@ -80,6 +82,8 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
|
||||
public Chunk nmsChunk;
|
||||
public WorldServer world;
|
||||
public int X, Z;
|
||||
public NibbleArray[] blockLight = new NibbleArray[16];
|
||||
public NibbleArray[] skyLight = new NibbleArray[16];
|
||||
|
||||
public BukkitGetBlocks_1_15_2(World world, int X, int Z) {
|
||||
this(((CraftWorld) world).getHandle(), X, Z);
|
||||
@ -132,6 +136,26 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
|
||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (skyLight[layer] == null) {
|
||||
skyLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(SectionPosition.a(nmsChunk.getPos(), layer));
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (blockLight[layer] == null) {
|
||||
blockLight[layer] = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(SectionPosition.a(nmsChunk.getPos(), layer));
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
Entity entity = world.getEntity(uuid);
|
||||
@ -347,6 +371,29 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
|
||||
}
|
||||
}
|
||||
|
||||
boolean lightUpdate = false;
|
||||
|
||||
// Lighting
|
||||
char[][] light = set.getLight();
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.BLOCK);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
char[][] skyLight = set.getSkyLight();
|
||||
if (skyLight != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(skyLight, EnumSkyBlock.SKY);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Runnable[] syncTasks = null;
|
||||
|
||||
int bx = X << 4;
|
||||
@ -452,23 +499,19 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
|
||||
};
|
||||
}
|
||||
|
||||
//Lighting
|
||||
// TODO optimize, cause this is really slow
|
||||
LightEngineThreaded engine = (LightEngineThreaded) nmsChunk.e();
|
||||
engine.a(nmsChunk, false);
|
||||
|
||||
Runnable callback;
|
||||
if (bitMask == 0 && biomes == null) {
|
||||
if (bitMask == 0 && biomes == null && !lightUpdate) {
|
||||
callback = null;
|
||||
} else {
|
||||
int finalMask = bitMask;
|
||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||
boolean finalLightUpdate = lightUpdate;
|
||||
callback = () -> {
|
||||
// Set Modified
|
||||
nmsChunk.d(true); // Set Modified
|
||||
nmsChunk.mustNotSave = false;
|
||||
nmsChunk.markDirty();
|
||||
// send to player
|
||||
BukkitAdapter_1_15_2.sendChunk(nmsWorld, X, Z, finalMask);
|
||||
BukkitAdapter_1_15_2.sendChunk(nmsWorld, X, Z, finalMask, finalLightUpdate);
|
||||
if (finalizer != null) finalizer.run();
|
||||
};
|
||||
}
|
||||
@ -641,6 +684,25 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void fillLightNibble(char[][] light, EnumSkyBlock skyBlock) {
|
||||
for (int Y = 0; Y < 16; Y++) {
|
||||
if (light[Y] == null) {
|
||||
continue;
|
||||
}
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(SectionPosition.a(nmsChunk.getPos(), Y));
|
||||
if (nibble == null) {
|
||||
continue;
|
||||
}
|
||||
synchronized (nibble) {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
if (light[Y][i] < 16) {
|
||||
nibble.a(i, light[Y][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return getSections()[layer] != null;
|
||||
@ -648,6 +710,8 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
skyLight = new NibbleArray[16];
|
||||
blockLight = new NibbleArray[16];
|
||||
if (aggressive) {
|
||||
sections = null;
|
||||
nmsChunk = null;
|
||||
|
@ -2,8 +2,11 @@ package com.boydti.fawe;
|
||||
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.lighting.NMSRelighter;
|
||||
import com.boydti.fawe.beta.implementation.queue.ParallelQueueExtent;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.RelightMode;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.object.changeset.SimpleChangeSetSummary;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
@ -28,10 +31,13 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
|
||||
import com.sk89q.worldedit.internal.registry.AbstractFactory;
|
||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
@ -43,7 +49,6 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The FaweAPI class offers a few useful functions.<br>
|
||||
@ -387,12 +392,52 @@ public class FaweAPI {
|
||||
* - Relights in parallel (if enabled) for best performance<br>
|
||||
* - Also resends chunks<br>
|
||||
*
|
||||
* @param world
|
||||
* @param selection (assumes cuboid)
|
||||
* @return
|
||||
* @param world World to relight in
|
||||
* @param selection Region to relight
|
||||
* @param queue Queue to relight in/from
|
||||
* @param mode The mode to relight with
|
||||
* @return Chunks changed
|
||||
*/
|
||||
public static int fixLighting(World world, Region selection, @Nullable IQueueExtent queue) {
|
||||
throw new UnsupportedOperationException();
|
||||
public static int fixLighting(World world, Region selection, @Nullable IQueueExtent<IQueueChunk> queue, final RelightMode mode) {
|
||||
final BlockVector3 bot = selection.getMinimumPoint();
|
||||
final BlockVector3 top = selection.getMaximumPoint();
|
||||
|
||||
final int minX = bot.getBlockX() >> 4;
|
||||
final int minZ = bot.getBlockZ() >> 4;
|
||||
|
||||
final int maxX = top.getBlockX() >> 4;
|
||||
final int maxZ = top.getBlockZ() >> 4;
|
||||
|
||||
int count = 0;
|
||||
|
||||
if (queue == null) {
|
||||
World unwrapped = WorldWrapper.unwrap(world);
|
||||
if (unwrapped instanceof IQueueExtent) {
|
||||
queue = (IQueueExtent) unwrapped;
|
||||
} else if (Settings.IMP.QUEUE.PARALLEL_THREADS > 1) {
|
||||
ParallelQueueExtent parallel =
|
||||
new ParallelQueueExtent(Fawe.get().getQueueHandler(), world, true);
|
||||
queue = parallel.getExtent();
|
||||
} else {
|
||||
queue = Fawe.get().getQueueHandler().getQueue(world);
|
||||
}
|
||||
}
|
||||
|
||||
NMSRelighter relighter = new NMSRelighter(queue);
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
relighter.addChunk(x, z, null, 65535);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (mode != RelightMode.NONE) {
|
||||
relighter.fixSkyLighting();
|
||||
relighter.fixBlockLighting();
|
||||
} else {
|
||||
relighter.removeLighting();
|
||||
}
|
||||
relighter.sendChunks();
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,6 +26,12 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput {
|
||||
@Override
|
||||
BlockState getBlock(int x, int y, int z);
|
||||
|
||||
@Override
|
||||
int getSkyLight(int x, int y, int z);
|
||||
|
||||
@Override
|
||||
int getEmmittedLight(int x, int y, int z);
|
||||
|
||||
default void optimize() {
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,20 @@ public interface IChunkSet extends IBlocks, OutputExtent {
|
||||
@Override
|
||||
boolean setTile(int x, int y, int z, CompoundTag tile);
|
||||
|
||||
@Override
|
||||
void setBlockLight(int x, int y, int z, int value);
|
||||
|
||||
@Override
|
||||
void setSkyLight(int x, int y, int z, int value);
|
||||
|
||||
void setLightLayer(int layer, char[] toSet);
|
||||
|
||||
void setSkyLightLayer(int layer, char[] toSet);
|
||||
|
||||
void removeSectionLighting(int layer, boolean sky);
|
||||
|
||||
void setFullBright(int layer);
|
||||
|
||||
void setEntity(CompoundTag tag);
|
||||
|
||||
void removeEntity(UUID uuid);
|
||||
@ -40,12 +54,27 @@ public interface IChunkSet extends IBlocks, OutputExtent {
|
||||
return getBiomes() != null;
|
||||
}
|
||||
|
||||
char[][] getLight();
|
||||
|
||||
char[][] getSkyLight();
|
||||
|
||||
default boolean hasLight() {
|
||||
return getLight() != null;
|
||||
}
|
||||
|
||||
// Default to avoid tricky child classes. We only need it in a few cases anyway.
|
||||
default void setFastMode(boolean fastMode){}
|
||||
|
||||
default boolean isFastMode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
//default to avoid tricky child classes. We only need it in a few cases anyway.
|
||||
default void setFastMode(boolean fastMode){}
|
||||
// Allow setting for bitmask for flushing lighting. Default to avoid tricky child classes.
|
||||
default void setBitMask(int bitMask){}
|
||||
|
||||
default int getBitMask(){
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
IChunkSet reset();
|
||||
|
@ -55,4 +55,40 @@ public interface IChunkExtent<T extends IChunk> extends Extent {
|
||||
final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4);
|
||||
return chunk.getBiomeType(x & 15, y, z & 15);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void setSkyLight(int x, int y, int z, int value) {
|
||||
final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4);
|
||||
chunk.setSkyLight(x & 15, y, z & 15, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void setBlockLight(int x, int y, int z, int value) {
|
||||
final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4);
|
||||
chunk.setSkyLight(x & 15, y, z & 15, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getSkyLight(int x, int y, int z) {
|
||||
final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4);
|
||||
return chunk.getSkyLight(x & 15, y, z & 15);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getEmmittedLight(int x, int y, int z) {
|
||||
final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4);
|
||||
return chunk.getEmmittedLight(x & 15, y, z & 15);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getBrightness(int x, int y, int z) {
|
||||
final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4);
|
||||
return chunk.getBrightness(x & 15, y, z & 15);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getOpacity(int x, int y, int z) {
|
||||
final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4);
|
||||
return chunk.getOpacity(x & 15, y, z & 15);
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +66,18 @@ public class BitSetBlocks implements IChunkSet {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public void setBlockLight(int x, int y, int z, int value) {}
|
||||
|
||||
@Override public void setSkyLight(int x, int y, int z, int value) {}
|
||||
|
||||
@Override public void setLightLayer(int layer, char[] toSet) {}
|
||||
|
||||
@Override public void setSkyLightLayer(int layer, char[] toSet) {}
|
||||
|
||||
@Override public void removeSectionLighting(int layer, boolean sky) {}
|
||||
|
||||
@Override public void setFullBright(int layer) {}
|
||||
|
||||
@Override
|
||||
public void setEntity(CompoundTag tag) {
|
||||
}
|
||||
@ -118,6 +130,14 @@ public class BitSetBlocks implements IChunkSet {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public char[][] getLight() {
|
||||
return new char[0][];
|
||||
}
|
||||
|
||||
@Override public char[][] getSkyLight() {
|
||||
return new char[0][];
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
return null;
|
||||
|
@ -5,24 +5,21 @@ import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.queue.Pool;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.BlockVector3ChunkMap;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.IntStream;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
private static final Pool<CharSetBlocks> POOL = FaweCache.IMP.registerPool(CharSetBlocks.class, CharSetBlocks::new, Settings.IMP.QUEUE.POOL);
|
||||
@ -31,10 +28,13 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
}
|
||||
|
||||
public BiomeType[] biomes;
|
||||
public char[][] light;
|
||||
public char[][] skyLight;
|
||||
public BlockVector3ChunkMap<CompoundTag> tiles;
|
||||
public HashSet<CompoundTag> entities;
|
||||
public HashSet<UUID> entityRemoves;
|
||||
private boolean fastMode = false;
|
||||
private int bitMask = -1;
|
||||
|
||||
private CharSetBlocks() {}
|
||||
|
||||
@ -111,6 +111,80 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public void setBlockLight(int x, int y, int z, int value) {
|
||||
if (light == null) {
|
||||
light = new char[16][];
|
||||
}
|
||||
final int layer = y >> 4;
|
||||
if (light[layer] == null) {
|
||||
char[] c = new char[4096];
|
||||
Arrays.fill(c, (char) 16);
|
||||
light[layer] = c;
|
||||
}
|
||||
final int index = (y & 15) << 8 | (z & 15) << 4 | (x & 15);
|
||||
light[y >> 4][index] = (char) value;
|
||||
}
|
||||
|
||||
@Override public void setSkyLight(int x, int y, int z, int value) {
|
||||
if (skyLight == null) {
|
||||
skyLight = new char[16][];
|
||||
}
|
||||
final int layer = y >> 4;
|
||||
if (skyLight[layer] == null) {
|
||||
char[] c = new char[4096];
|
||||
Arrays.fill(c, (char) 16);
|
||||
skyLight[layer] = c;
|
||||
}
|
||||
final int index = (y & 15) << 8 | (z & 15) << 4 | (x & 15);
|
||||
skyLight[y >> 4][index] = (char) value;
|
||||
}
|
||||
|
||||
@Override public void setLightLayer(int layer, char[] toSet) {
|
||||
if (light == null) {
|
||||
light = new char[16][];
|
||||
}
|
||||
light[layer] = toSet;
|
||||
}
|
||||
|
||||
@Override public void setSkyLightLayer(int layer, char[] toSet) {
|
||||
if (skyLight == null) {
|
||||
skyLight = new char[16][];
|
||||
}
|
||||
skyLight[layer] = toSet;
|
||||
}
|
||||
|
||||
@Override public char[][] getLight() {
|
||||
return light;
|
||||
}
|
||||
|
||||
@Override public char[][] getSkyLight() {
|
||||
return skyLight;
|
||||
}
|
||||
|
||||
@Override public void removeSectionLighting(int layer, boolean sky) {
|
||||
if (light == null) {
|
||||
light = new char[16][];
|
||||
}
|
||||
if (light[layer] == null) {
|
||||
light[layer] = new char[4096];
|
||||
}
|
||||
Arrays.fill(light[layer], (char) 0);
|
||||
if (sky) {
|
||||
if (skyLight == null) {
|
||||
skyLight = new char[16][];
|
||||
}
|
||||
if (skyLight[layer] == null) {
|
||||
skyLight[layer] = new char[4096];
|
||||
}
|
||||
Arrays.fill(skyLight[layer], (char) 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void setFullBright(int layer) {
|
||||
Arrays.fill(light[layer], (char) 15);
|
||||
Arrays.fill(skyLight[layer], (char) 15);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(BlockVector2 position, BiomeType biome) {
|
||||
return setBiome(position.getX(),0, position.getZ(), biome);
|
||||
@ -142,9 +216,19 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
return fastMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBitMask(int bitMask) {
|
||||
this.bitMask = bitMask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBitMask() {
|
||||
return bitMask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
if (biomes != null) {
|
||||
if (biomes != null || light != null || skyLight != null) {
|
||||
return false;
|
||||
}
|
||||
return IntStream.range(0, 16).noneMatch(this::hasSection);
|
||||
|
@ -41,6 +41,14 @@ public class FallbackChunkGet implements IChunkGet {
|
||||
return extent.getBlock(bx + x, y, bz + z);
|
||||
}
|
||||
|
||||
@Override public int getSkyLight(int x, int y, int z) {
|
||||
return extent.getSkyLight(bx + x, y, bz + z);
|
||||
}
|
||||
|
||||
@Override public int getEmmittedLight(int x, int y, int z) {
|
||||
return extent.getEmmittedLight(bx + x, y, bz + z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getTile(int x, int y, int z) {
|
||||
return extent.getFullBlock(bx + x, y, bz + z).getNbtData();
|
||||
|
@ -12,7 +12,6 @@ import com.sk89q.worldedit.world.block.BaseBlock
|
||||
import com.sk89q.worldedit.world.block.BlockState
|
||||
import com.sk89q.worldedit.world.block.BlockTypes
|
||||
|
||||
import java.util.Collections
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.Future
|
||||
|
||||
@ -66,6 +65,14 @@ object NullChunkGet : IChunkGet {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getEmmittedLight(x: Int, y: Int, z: Int): Int {
|
||||
return 15
|
||||
}
|
||||
|
||||
override fun getSkyLight(x: Int, y: Int, z: Int): Int {
|
||||
return 15
|
||||
}
|
||||
|
||||
override fun reset(): IBlocks? {
|
||||
return null
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package com.boydti.fawe.beta.implementation.chunk;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.implementation.filter.block.ChunkFilterBlock;
|
||||
import com.boydti.fawe.beta.Filter;
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.filter.block.ChunkFilterBlock;
|
||||
import com.boydti.fawe.beta.implementation.queue.Pool;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
@ -17,17 +17,18 @@ import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
import javax.annotation.Nullable;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
/**
|
||||
* An abstract {@link IChunk} class that implements basic get/set blocks
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
|
||||
private static final Pool<ChunkHolder> POOL = FaweCache.IMP.registerPool(ChunkHolder.class, ChunkHolder::new, Settings.IMP.QUEUE.POOL);
|
||||
@ -43,6 +44,8 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
private int chunkX;
|
||||
private int chunkZ;
|
||||
private boolean fastmode;
|
||||
private int bitMask = -1; // Allow forceful setting of bitmask (for lighting)
|
||||
private boolean isInit = false; // Lighting handles queue differently. It relies on the chunk cache and not doing init.
|
||||
|
||||
private ChunkHolder() {
|
||||
this.delegate = NULL;
|
||||
@ -91,6 +94,14 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
return delegate.set(this).getBiomes(); // TODO return get?
|
||||
}
|
||||
|
||||
@Override public char[][] getLight() {
|
||||
return delegate.set(this).getLight();
|
||||
}
|
||||
|
||||
@Override public char[][] getSkyLight() {
|
||||
return delegate.set(this).getSkyLight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlocks(int layer, char[] data) {
|
||||
delegate.set(this).setBlocks(layer, data);
|
||||
@ -111,6 +122,18 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
this.fastmode = fastmode;
|
||||
}
|
||||
|
||||
public void setBitMask(int bitMask) {
|
||||
this.bitMask = bitMask;
|
||||
}
|
||||
|
||||
public int getBitMask() {
|
||||
return bitMask;
|
||||
}
|
||||
|
||||
public boolean isInit() {
|
||||
return isInit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
return delegate.get(this).getEntity(uuid);
|
||||
@ -139,6 +162,36 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
return chunk.chunkSet.setBlock(x, y, z, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLight(ChunkHolder chunk, int x, int y, int z, int value) {
|
||||
chunk.chunkSet.setSkyLight(x, y, z, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockLight(ChunkHolder chunk, int x, int y, int z, int value) {
|
||||
chunk.chunkSet.setBlockLight(x, y, z, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(ChunkHolder chunk, int layer, boolean sky) {
|
||||
chunk.chunkSet.removeSectionLighting(layer, sky);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFullBright(ChunkHolder chunk, int layer){
|
||||
chunk.chunkSet.setFullBright(layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightLayer(ChunkHolder chunk, int layer, char[] toSet) {
|
||||
chunk.chunkSet.setLightLayer(layer, toSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightLayer(ChunkHolder chunk, int layer, char[] toSet) {
|
||||
chunk.chunkSet.setSkyLightLayer(layer, toSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiome(ChunkHolder chunk, int x, int y, int z) {
|
||||
return chunk.chunkExisting.getBiomeType(x, y, z);
|
||||
@ -154,6 +207,44 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
int z) {
|
||||
return chunk.chunkExisting.getFullBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(ChunkHolder chunk, int x, int y, int z) {
|
||||
if (chunk.chunkSet.getSkyLight() != null) {
|
||||
int layer = y >> 4;
|
||||
if (chunk.chunkSet.getSkyLight()[layer] != null) {
|
||||
int setLightValue = chunk.chunkSet.getSkyLight()[layer][(y & 15) << 8 | (z & 15) << 4 | (x & 15)];
|
||||
if (setLightValue < 16) {
|
||||
return setLightValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return chunk.chunkExisting.getSkyLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(ChunkHolder chunk, int x, int y, int z) {
|
||||
if (chunk.chunkSet.getLight() != null) {
|
||||
int layer = y >> 4;
|
||||
if (chunk.chunkSet.getLight()[layer] != null) {
|
||||
int setLightValue = chunk.chunkSet.getLight()[layer][(y & 15) << 8 | (z & 15) << 4 | (x & 15)];
|
||||
if (setLightValue < 16) {
|
||||
return setLightValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return chunk.chunkExisting.getEmmittedLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightness(ChunkHolder chunk, int x, int y, int z) {
|
||||
return chunk.chunkExisting.getBrightness(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity(ChunkHolder chunk, int x, int y, int z) {
|
||||
return chunk.chunkExisting.getOpacity(x, y, z);
|
||||
}
|
||||
};
|
||||
|
||||
private static final IBlockDelegate GET = new IBlockDelegate() {
|
||||
@ -185,6 +276,48 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
return chunk.setBlock(x, y, z, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLight(ChunkHolder chunk, int x, int y, int z, int value) {
|
||||
chunk.getOrCreateSet();
|
||||
chunk.delegate = BOTH;
|
||||
chunk.setSkyLight(x, y, z, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockLight(ChunkHolder chunk, int x, int y, int z, int value) {
|
||||
chunk.getOrCreateSet();
|
||||
chunk.delegate = BOTH;
|
||||
chunk.setBlockLight(x, y, z, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(ChunkHolder chunk, int layer, boolean sky) {
|
||||
chunk.getOrCreateSet();
|
||||
chunk.delegate = BOTH;
|
||||
chunk.removeSectionLighting(layer, sky);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFullBright(ChunkHolder chunk, int layer){
|
||||
chunk.getOrCreateSet();
|
||||
chunk.delegate = BOTH;
|
||||
chunk.setFullBright(layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightLayer(ChunkHolder chunk, int layer, char[] toSet) {
|
||||
chunk.getOrCreateSet();
|
||||
chunk.delegate = BOTH;
|
||||
chunk.setLightLayer(layer, toSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightLayer(ChunkHolder chunk, int layer, char[] toSet) {
|
||||
chunk.getOrCreateSet();
|
||||
chunk.delegate = BOTH;
|
||||
chunk.setSkyLightLayer(layer, toSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiome(ChunkHolder chunk, int x, int y, int z) {
|
||||
return chunk.chunkExisting.getBiomeType(x, y, z);
|
||||
@ -200,6 +333,26 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
int z) {
|
||||
return chunk.chunkExisting.getFullBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(ChunkHolder chunk, int x, int y, int z) {
|
||||
return chunk.chunkExisting.getSkyLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(ChunkHolder chunk, int x, int y, int z) {
|
||||
return chunk.chunkExisting.getEmmittedLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightness(ChunkHolder chunk, int x, int y, int z) {
|
||||
return chunk.chunkExisting.getBrightness(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity(ChunkHolder chunk, int x, int y, int z) {
|
||||
return chunk.chunkExisting.getOpacity(x, y, z);
|
||||
}
|
||||
};
|
||||
|
||||
private static final IBlockDelegate SET = new IBlockDelegate() {
|
||||
@ -226,6 +379,36 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
return chunk.chunkSet.setBlock(x, y, z, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLight(ChunkHolder chunk, int x, int y, int z, int value) {
|
||||
chunk.chunkSet.setSkyLight(x, y, z, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockLight(ChunkHolder chunk, int x, int y, int z, int value) {
|
||||
chunk.chunkSet.setBlockLight(x, y, z, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(ChunkHolder chunk, int layer, boolean sky) {
|
||||
chunk.chunkSet.removeSectionLighting(layer, sky);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFullBright(ChunkHolder chunk, int layer){
|
||||
chunk.chunkSet.setFullBright(layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightLayer(ChunkHolder chunk, int layer, char[] toSet) {
|
||||
chunk.chunkSet.setLightLayer(layer, toSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightLayer(ChunkHolder chunk, int layer, char[] toSet) {
|
||||
chunk.chunkSet.setSkyLightLayer(layer, toSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiome(ChunkHolder chunk, int x, int y, int z) {
|
||||
chunk.getOrCreateGet();
|
||||
@ -247,6 +430,52 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
chunk.delegate = BOTH;
|
||||
return chunk.getFullBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(ChunkHolder chunk, int x, int y, int z) {
|
||||
if (chunk.chunkSet.getSkyLight() != null) {
|
||||
int layer = y >> 4;
|
||||
if (chunk.chunkSet.getSkyLight()[layer] != null) {
|
||||
int setLightValue = chunk.chunkSet.getSkyLight()[layer][(y & 15) << 8 | (z & 15) << 4 | (x & 15)];
|
||||
if (setLightValue < 16) {
|
||||
return setLightValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
chunk.getOrCreateGet();
|
||||
chunk.delegate = BOTH;
|
||||
return chunk.getSkyLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(ChunkHolder chunk, int x, int y, int z) {
|
||||
if (chunk.chunkSet.getLight() != null) {
|
||||
int layer = y >> 4;
|
||||
if (chunk.chunkSet.getLight()[layer] != null) {
|
||||
int setLightValue = chunk.chunkSet.getLight()[layer][(y & 15) << 8 | (z & 15) << 4 | (x & 15)];
|
||||
if (setLightValue < 16) {
|
||||
return setLightValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
chunk.getOrCreateGet();
|
||||
chunk.delegate = BOTH;
|
||||
return chunk.getEmmittedLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightness(ChunkHolder chunk, int x, int y, int z) {
|
||||
chunk.getOrCreateGet();
|
||||
chunk.delegate = BOTH;
|
||||
return chunk.getBrightness(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity(ChunkHolder chunk, int x, int y, int z) {
|
||||
chunk.getOrCreateGet();
|
||||
chunk.delegate = BOTH;
|
||||
return chunk.getOpacity(x, y, z);
|
||||
}
|
||||
};
|
||||
|
||||
private static final IBlockDelegate NULL = new IBlockDelegate() {
|
||||
@ -303,6 +532,80 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
chunk.chunkExisting.trim(false);
|
||||
return chunk.getFullBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLight(ChunkHolder chunk, int x, int y, int z, int value) {
|
||||
chunk.getOrCreateSet();
|
||||
chunk.delegate = SET;
|
||||
chunk.setSkyLight(x, y, z, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockLight(ChunkHolder chunk, int x, int y, int z, int value) {
|
||||
chunk.getOrCreateSet();
|
||||
chunk.delegate = SET;
|
||||
chunk.setBlockLight(x, y, z, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(ChunkHolder chunk, int layer, boolean sky) {
|
||||
chunk.getOrCreateSet();
|
||||
chunk.delegate = SET;
|
||||
chunk.removeSectionLighting(layer, sky);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFullBright(ChunkHolder chunk, int layer){
|
||||
chunk.getOrCreateSet();
|
||||
chunk.delegate = SET;
|
||||
chunk.setFullBright(layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightLayer(ChunkHolder chunk, int layer, char[] toSet) {
|
||||
chunk.getOrCreateSet();
|
||||
chunk.delegate = SET;
|
||||
chunk.setLightLayer(layer, toSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightLayer(ChunkHolder chunk, int layer, char[] toSet) {
|
||||
chunk.getOrCreateSet();
|
||||
chunk.delegate = SET;
|
||||
chunk.setSkyLightLayer(layer, toSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(ChunkHolder chunk, int x, int y, int z) {
|
||||
chunk.getOrCreateGet();
|
||||
chunk.delegate = GET;
|
||||
chunk.chunkExisting.trim(false);
|
||||
return chunk.getSkyLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(ChunkHolder chunk, int x, int y, int z) {
|
||||
chunk.getOrCreateGet();
|
||||
chunk.delegate = GET;
|
||||
chunk.chunkExisting.trim(false);
|
||||
return chunk.getEmmittedLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightness(ChunkHolder chunk, int x, int y, int z) {
|
||||
chunk.getOrCreateGet();
|
||||
chunk.delegate = GET;
|
||||
chunk.chunkExisting.trim(false);
|
||||
return chunk.getBrightness(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity(ChunkHolder chunk, int x, int y, int z) {
|
||||
chunk.getOrCreateGet();
|
||||
chunk.delegate = GET;
|
||||
chunk.chunkExisting.trim(false);
|
||||
return chunk.getOpacity(x, y, z);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
@ -416,11 +719,13 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
delegate = NULL;
|
||||
}
|
||||
chunkExisting = null;
|
||||
isInit = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized T call() {
|
||||
if (chunkSet != null) {
|
||||
chunkSet.setBitMask(bitMask);
|
||||
return this.call(chunkSet, this::recycle);
|
||||
}
|
||||
return null;
|
||||
@ -481,6 +786,54 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
return delegate.getFullBlock(this, x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLight(int x, int y, int z, int value) {
|
||||
delegate.setSkyLight(this, x, y, z, value);
|
||||
}
|
||||
|
||||
@Override public void removeSectionLighting(int layer, boolean sky) {
|
||||
delegate.removeSectionLighting(this, layer, sky);
|
||||
}
|
||||
|
||||
@Override public void setFullBright(int layer) {
|
||||
delegate.setFullBright(this, layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockLight(int x, int y, int z, int value) {
|
||||
delegate.setBlockLight(this, x, y, z, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightLayer(int layer, char[] toSet) {
|
||||
delegate.setLightLayer(this, layer, toSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightLayer(int layer, char[] toSet) {
|
||||
delegate.setSkyLightLayer(this, layer, toSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
return delegate.getSkyLight(this, x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
return delegate.getEmmittedLight(this, x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightness(int x, int y, int z) {
|
||||
return delegate.getBrightness(this, x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity(int x, int y, int z) {
|
||||
return delegate.getOpacity(this, x, y, z);
|
||||
}
|
||||
|
||||
public interface IBlockDelegate {
|
||||
<C extends Future<C>> IChunkGet get(ChunkHolder<C> chunk);
|
||||
IChunkSet set(ChunkHolder chunk);
|
||||
@ -494,5 +847,25 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
BlockState getBlock(ChunkHolder chunk, int x, int y, int z);
|
||||
|
||||
BaseBlock getFullBlock(ChunkHolder chunk, int x, int y, int z);
|
||||
|
||||
void setSkyLight(ChunkHolder chunk, int x, int y, int z, int value);
|
||||
|
||||
void setBlockLight(ChunkHolder chunk, int x, int y, int z, int value);
|
||||
|
||||
void removeSectionLighting(ChunkHolder chunk, int layer, boolean sky);
|
||||
|
||||
void setFullBright(ChunkHolder chunk, int layer);
|
||||
|
||||
void setLightLayer(ChunkHolder chunk, int layer, char[] toSet);
|
||||
|
||||
void setSkyLightLayer(ChunkHolder chunk, int layer, char[] toSet);
|
||||
|
||||
int getSkyLight(ChunkHolder chunk, int x, int y, int z);
|
||||
|
||||
int getEmmittedLight(ChunkHolder chunk, int x, int y, int z);
|
||||
|
||||
int getBrightness(ChunkHolder chunk, int x, int y, int z);
|
||||
|
||||
int getOpacity(ChunkHolder chunk, int x, int y, int z);
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +62,46 @@ object NullChunk : IQueueChunk<Nothing> {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getSkyLight(x: Int, y: Int, z: Int): Int {
|
||||
return 15
|
||||
}
|
||||
|
||||
override fun getLight(): Array<CharArray> {
|
||||
return emptyArray()
|
||||
}
|
||||
|
||||
override fun getSkyLight(): Array<CharArray> {
|
||||
return emptyArray()
|
||||
}
|
||||
|
||||
override fun getEmmittedLight(x: Int, y: Int, z: Int): Int {
|
||||
return 15
|
||||
}
|
||||
|
||||
override fun setSkyLight(x: Int, y: Int, z: Int, value: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun setBlockLight(x: Int, y: Int, z: Int, value: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun setFullBright(layer: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun removeSectionLighting(layer: Int, sky: Boolean) {
|
||||
|
||||
}
|
||||
|
||||
override fun setSkyLightLayer(layer: Int, toSet: CharArray?) {
|
||||
|
||||
}
|
||||
|
||||
override fun setLightLayer(layer: Int, toSet: CharArray?) {
|
||||
|
||||
}
|
||||
|
||||
override fun getBiomes(): Array<BiomeType>? {
|
||||
return null
|
||||
}
|
||||
|
@ -0,0 +1,645 @@
|
||||
package com.boydti.fawe.beta.implementation.lighting;
|
||||
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.chunk.ChunkHolder;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.collection.BlockVectorSet;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.math.MutableBlockVector3;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class NMSRelighter implements Relighter {
|
||||
private final IQueueExtent<IQueueChunk> queue;
|
||||
|
||||
private final Map<Long, RelightSkyEntry> skyToRelight;
|
||||
private final Object present = new Object();
|
||||
private final Map<Long, Integer> chunksToSend;
|
||||
private final ConcurrentLinkedQueue<RelightSkyEntry> extentdSkyToRelight = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private final Map<Long, long[][][] /* z y x */ > lightQueue;
|
||||
private final AtomicBoolean lightLock = new AtomicBoolean(false);
|
||||
private final ConcurrentHashMap<Long, long[][][]> concurrentLightQueue;
|
||||
|
||||
private final int maxY;
|
||||
|
||||
public final MutableBlockVector3 mutableBlockPos = new MutableBlockVector3(0, 0, 0);
|
||||
|
||||
private static final int DISPATCH_SIZE = 64;
|
||||
private boolean removeFirst;
|
||||
|
||||
public NMSRelighter(IQueueExtent<IQueueChunk> queue) {
|
||||
this.queue = queue;
|
||||
this.skyToRelight = new Long2ObjectOpenHashMap<>(12);
|
||||
this.lightQueue = new Long2ObjectOpenHashMap<>(12);
|
||||
this.chunksToSend = new Long2ObjectOpenHashMap<>(12);
|
||||
this.concurrentLightQueue = new ConcurrentHashMap<>(12);
|
||||
this.maxY = queue.getMaxY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return skyToRelight.isEmpty() && lightQueue.isEmpty() && extentdSkyToRelight.isEmpty() && concurrentLightQueue.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void removeAndRelight(boolean sky) {
|
||||
removeFirst = true;
|
||||
fixLightingSafe(sky);
|
||||
removeFirst = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to reduce duplicated code to ensure values are written to long[][][] without NPEs
|
||||
*
|
||||
* @param x x coordinate
|
||||
* @param y y coordinate
|
||||
* @param z z coordinate
|
||||
* @param map long[][][] to add values to
|
||||
*/
|
||||
private void set(int x, int y, int z, long[][][] map) {
|
||||
long[][] m1 = map[z];
|
||||
if (m1 == null) {
|
||||
m1 = map[z] = new long[16][];
|
||||
}
|
||||
long[] m2 = m1[x];
|
||||
if (m2 == null) {
|
||||
m2 = m1[x] = new long[4];
|
||||
}
|
||||
long value = m2[y >> 6] |= 1l << y;
|
||||
}
|
||||
|
||||
public void addLightUpdate(int x, int y, int z) {
|
||||
long index = MathMan.pairInt(x >> 4, z >> 4);
|
||||
if (lightLock.compareAndSet(false, true)) {
|
||||
synchronized (lightQueue) {
|
||||
try {
|
||||
long[][][] currentMap = lightQueue.get(index);
|
||||
if (currentMap == null) {
|
||||
currentMap = new long[16][][];
|
||||
this.lightQueue.put(index, currentMap);
|
||||
}
|
||||
set(x & 15, y, z & 15, currentMap);
|
||||
} finally {
|
||||
lightLock.set(false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
long[][][] currentMap = concurrentLightQueue.get(index);
|
||||
if (currentMap == null) {
|
||||
currentMap = new long[16][][];
|
||||
this.concurrentLightQueue.put(index, currentMap);
|
||||
}
|
||||
set(x & 15, y, z & 15, currentMap);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void clear() {
|
||||
extentdSkyToRelight.clear();
|
||||
skyToRelight.clear();
|
||||
chunksToSend.clear();
|
||||
lightQueue.clear();
|
||||
}
|
||||
|
||||
public boolean addChunk(int cx, int cz, byte[] fix, int bitmask) {
|
||||
RelightSkyEntry toPut = new RelightSkyEntry(cx, cz, fix, bitmask);
|
||||
extentdSkyToRelight.add(toPut);
|
||||
return true;
|
||||
}
|
||||
|
||||
private synchronized Map<Long, RelightSkyEntry> getSkyMap() {
|
||||
RelightSkyEntry entry;
|
||||
while ((entry = extentdSkyToRelight.poll()) != null) {
|
||||
long pair = MathMan.pairInt(entry.x, entry.z);
|
||||
RelightSkyEntry existing = skyToRelight.put(pair, entry);
|
||||
if (existing != null) {
|
||||
entry.bitmask |= existing.bitmask;
|
||||
if (entry.fix != null) {
|
||||
for (int i = 0; i < entry.fix.length; i++) {
|
||||
entry.fix[i] &= existing.fix[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return skyToRelight;
|
||||
}
|
||||
|
||||
public synchronized void removeLighting() {
|
||||
Iterator<Map.Entry<Long, RelightSkyEntry>> iter = getSkyMap().entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Map.Entry<Long, RelightSkyEntry> entry = iter.next();
|
||||
RelightSkyEntry chunk = entry.getValue();
|
||||
long pair = entry.getKey();
|
||||
Integer existing = chunksToSend.get(pair);
|
||||
chunksToSend.put(pair, chunk.bitmask | (existing != null ? existing : 0));
|
||||
ChunkHolder iChunk = (ChunkHolder) queue.getOrCreateChunk(chunk.x, chunk.z);
|
||||
if (!iChunk.isInit()) {
|
||||
iChunk.init(queue, chunk.x, chunk.z);
|
||||
}
|
||||
for (int i = 0; i < 16; i++) {
|
||||
iChunk.removeSectionLighting(i, true);
|
||||
}
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateBlockLight(Map<Long, long[][][]> map) {
|
||||
int size = map.size();
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
Queue<MutableBlockVector3> lightPropagationQueue = new ArrayDeque<>(32);
|
||||
Queue<Object[]> lightRemovalQueue = new ArrayDeque<>(32);
|
||||
Map<MutableBlockVector3, Object> visited = new HashMap<>(32);
|
||||
Map<MutableBlockVector3, Object> removalVisited = new HashMap<>(32);
|
||||
|
||||
Iterator<Map.Entry<Long, long[][][]>> iter = map.entrySet().iterator();
|
||||
while (iter.hasNext() && size-- > 0) {
|
||||
Map.Entry<Long, long[][][]> entry = iter.next();
|
||||
long index = entry.getKey();
|
||||
long[][][] blocks = entry.getValue();
|
||||
int chunkX = MathMan.unpairIntX(index);
|
||||
int chunkZ = MathMan.unpairIntY(index);
|
||||
int bx = chunkX << 4;
|
||||
int bz = chunkZ << 4;
|
||||
ChunkHolder iChunk = (ChunkHolder) queue.getOrCreateChunk(chunkX, chunkZ);
|
||||
if (!iChunk.isInit()) {
|
||||
iChunk.init(queue, chunkX, chunkZ);
|
||||
}
|
||||
for (int lz = 0; lz < blocks.length; lz++) {
|
||||
long[][] m1 = blocks[lz];
|
||||
if (m1 == null) continue;
|
||||
for (int lx = 0; lx < m1.length; lx++) {
|
||||
long[] m2 = m1[lx];
|
||||
if (m2 == null) continue;
|
||||
for (int i = 0; i < m2.length; i++) {
|
||||
int yStart = i << 6;
|
||||
long value = m2[i];
|
||||
if (value != 0) {
|
||||
for (int j = 0; j < 64; j++) {
|
||||
if (((value >> j) & 1) == 1) {
|
||||
int x = lx + bx;
|
||||
int y = yStart + j;
|
||||
int z = lz + bz;
|
||||
int oldLevel = iChunk.getEmmittedLight(lx, y, lz);
|
||||
int newLevel = iChunk.getBrightness(lx, y, lz);
|
||||
if (oldLevel != newLevel) {
|
||||
iChunk.setBlockLight(lx, y, lz, newLevel);
|
||||
MutableBlockVector3 node = new MutableBlockVector3(x, y, z);
|
||||
if (newLevel < oldLevel) {
|
||||
removalVisited.put(node, present);
|
||||
lightRemovalQueue.add(new Object[]{node, oldLevel});
|
||||
} else {
|
||||
visited.put(node, present);
|
||||
lightPropagationQueue.add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
iter.remove();
|
||||
}
|
||||
|
||||
while (!lightRemovalQueue.isEmpty()) {
|
||||
Object[] val = lightRemovalQueue.poll();
|
||||
MutableBlockVector3 node = (MutableBlockVector3) val[0];
|
||||
int lightLevel = (int) val[1];
|
||||
|
||||
this.computeRemoveBlockLight(node.getX() - 1, node.getY(), node.getZ(), lightLevel, lightRemovalQueue, lightPropagationQueue, removalVisited, visited);
|
||||
this.computeRemoveBlockLight(node.getX() + 1, node.getY(), node.getZ(), lightLevel, lightRemovalQueue, lightPropagationQueue, removalVisited, visited);
|
||||
if (node.getY() > 0) {
|
||||
this.computeRemoveBlockLight(node.getX(), node.getY() - 1, node.getZ(), lightLevel, lightRemovalQueue, lightPropagationQueue, removalVisited, visited);
|
||||
}
|
||||
if (node.getY() < 255) {
|
||||
this.computeRemoveBlockLight(node.getX(), node.getY() + 1, node.getZ(), lightLevel, lightRemovalQueue, lightPropagationQueue, removalVisited, visited);
|
||||
}
|
||||
this.computeRemoveBlockLight(node.getX(), node.getY(), node.getZ() - 1, lightLevel, lightRemovalQueue, lightPropagationQueue, removalVisited, visited);
|
||||
this.computeRemoveBlockLight(node.getX(), node.getY(), node.getZ() + 1, lightLevel, lightRemovalQueue, lightPropagationQueue, removalVisited, visited);
|
||||
}
|
||||
|
||||
while (!lightPropagationQueue.isEmpty()) {
|
||||
MutableBlockVector3 node = lightPropagationQueue.poll();
|
||||
ChunkHolder iChunk = (ChunkHolder) queue.getOrCreateChunk(node.getX() >> 4, node.getZ() >> 4);
|
||||
if (!iChunk.isInit()) {
|
||||
iChunk.init(queue, node.getX() >> 4, node.getZ() >> 4);
|
||||
}
|
||||
int lightLevel = iChunk.getEmmittedLight(node.getX() & 15, node.getY(), node.getZ() & 15);
|
||||
if (lightLevel > 1) {
|
||||
this.computeSpreadBlockLight(node.getX() - 1, node.getY(), node.getZ(), lightLevel, lightPropagationQueue, visited);
|
||||
this.computeSpreadBlockLight(node.getX() + 1, node.getY(), node.getZ(), lightLevel, lightPropagationQueue, visited);
|
||||
if (node.getY() > 0) {
|
||||
this.computeSpreadBlockLight(node.getX(), node.getY() - 1, node.getZ(), lightLevel, lightPropagationQueue, visited);
|
||||
}
|
||||
if (node.getY() < 255) {
|
||||
this.computeSpreadBlockLight(node.getX(), node.getY() + 1, node.getZ(), lightLevel, lightPropagationQueue, visited);
|
||||
}
|
||||
this.computeSpreadBlockLight(node.getX(), node.getY(), node.getZ() - 1, lightLevel, lightPropagationQueue, visited);
|
||||
this.computeSpreadBlockLight(node.getX(), node.getY(), node.getZ() + 1, lightLevel, lightPropagationQueue, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void computeRemoveBlockLight(int x, int y, int z, int currentLight, Queue<Object[]> queue, Queue<MutableBlockVector3> spreadQueue, Map<MutableBlockVector3, Object> visited,
|
||||
Map<MutableBlockVector3, Object> spreadVisited) {
|
||||
ChunkHolder iChunk = (ChunkHolder) this.queue.getOrCreateChunk(x >> 4, z >> 4);
|
||||
if (!iChunk.isInit()) {
|
||||
iChunk.init(this.queue, x >> 4, z >> 4);
|
||||
}
|
||||
int current = iChunk.getEmmittedLight(x & 15, y, z & 15);
|
||||
if (current != 0 && current < currentLight) {
|
||||
iChunk.setBlockLight(x, y, z, 0);
|
||||
if (current > 1) {
|
||||
if (!visited.containsKey(mutableBlockPos)) {
|
||||
MutableBlockVector3 index = new MutableBlockVector3(x, y, z);
|
||||
visited.put(index, present);
|
||||
queue.add(new Object[]{index, current});
|
||||
}
|
||||
}
|
||||
} else if (current >= currentLight) {
|
||||
mutableBlockPos.setComponents(x, y, z);
|
||||
if (!spreadVisited.containsKey(mutableBlockPos)) {
|
||||
MutableBlockVector3 index = new MutableBlockVector3(x, y, z);
|
||||
spreadVisited.put(index, present);
|
||||
spreadQueue.add(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void computeSpreadBlockLight(int x, int y, int z, int currentLight, Queue<MutableBlockVector3> queue, Map<MutableBlockVector3, Object> visited) {
|
||||
currentLight = currentLight - Math.max(1, this.queue.getOpacity(x, y, z));
|
||||
if (currentLight > 0) {
|
||||
ChunkHolder iChunk = (ChunkHolder) this.queue.getOrCreateChunk(x >> 4, z >> 4);
|
||||
if (!iChunk.isInit()) {
|
||||
iChunk.init(this.queue, x >> 4, z >> 4);
|
||||
}
|
||||
int current = iChunk.getEmmittedLight(x & 15, y, z & 15);
|
||||
if (current < currentLight) {
|
||||
iChunk.setBlockLight(x, y, z, currentLight);
|
||||
mutableBlockPos.setComponents(x, y, z);
|
||||
if (!visited.containsKey(mutableBlockPos)) {
|
||||
visited.put(new MutableBlockVector3(x, y, z), present);
|
||||
if (currentLight > 1) {
|
||||
queue.add(new MutableBlockVector3(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void fixLightingSafe(boolean sky) {
|
||||
if (isEmpty()) return;
|
||||
try {
|
||||
if (sky) {
|
||||
fixSkyLighting();
|
||||
} else {
|
||||
synchronized (this) {
|
||||
Map<Long, RelightSkyEntry> map = getSkyMap();
|
||||
Iterator<Map.Entry<Long, RelightSkyEntry>> iter = map.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Map.Entry<Long, RelightSkyEntry> entry = iter.next();
|
||||
chunksToSend.put(entry.getKey(), entry.getValue().bitmask);
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
fixBlockLighting();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void fixBlockLighting() {
|
||||
synchronized (lightQueue) {
|
||||
while (!lightLock.compareAndSet(false, true));
|
||||
try {
|
||||
updateBlockLight(this.lightQueue);
|
||||
} finally {
|
||||
lightLock.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void sendChunks() {
|
||||
Iterator<Map.Entry<Long, Integer>> iter = chunksToSend.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Map.Entry<Long, Integer> entry = iter.next();
|
||||
long pair = entry.getKey();
|
||||
int bitMask = entry.getValue();
|
||||
int x = MathMan.unpairIntX(pair);
|
||||
int z = MathMan.unpairIntY(pair);
|
||||
ChunkHolder chunk = (ChunkHolder) queue.getOrCreateChunk(x, z);
|
||||
chunk.setBitMask(bitMask);
|
||||
iter.remove();
|
||||
}
|
||||
if (Settings.IMP.LIGHTING.ASYNC) {
|
||||
queue.flush();
|
||||
} else {
|
||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||
@Override public void run(Object value) {
|
||||
queue.flush();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void fixSkyLighting() {
|
||||
// Order chunks
|
||||
Map<Long, RelightSkyEntry> map = getSkyMap();
|
||||
ArrayList<RelightSkyEntry> chunksList = new ArrayList<>(map.size());
|
||||
Iterator<Map.Entry<Long, RelightSkyEntry>> iter = map.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Map.Entry<Long, RelightSkyEntry> entry = iter.next();
|
||||
chunksToSend.put(entry.getKey(), entry.getValue().bitmask);
|
||||
chunksList.add(entry.getValue());
|
||||
iter.remove();
|
||||
}
|
||||
Collections.sort(chunksList);
|
||||
int size = chunksList.size();
|
||||
if (size > DISPATCH_SIZE) {
|
||||
int amount = (size + DISPATCH_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);
|
||||
}
|
||||
}
|
||||
|
||||
public void fill(byte[] mask, int chunkX, int y, int chunkZ, byte reason) {
|
||||
if (y >= 16) {
|
||||
Arrays.fill(mask, (byte) 15);
|
||||
return;
|
||||
}
|
||||
switch (reason) {
|
||||
case SkipReason.SOLID: {
|
||||
Arrays.fill(mask, (byte) 0);
|
||||
return;
|
||||
}
|
||||
case SkipReason.AIR: {
|
||||
int bx = chunkX << 4;
|
||||
int bz = chunkZ << 4;
|
||||
int index = 0;
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
mask[index++] = (byte) queue.getSkyLight(bx + x, y, bz + z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fixSkyLighting(List<RelightSkyEntry> sorted) {
|
||||
RelightSkyEntry[] chunks = sorted.toArray(new RelightSkyEntry[sorted.size()]);
|
||||
boolean remove = this.removeFirst;
|
||||
BlockVectorSet chunkSet = null;
|
||||
if (remove) {
|
||||
chunkSet = new BlockVectorSet();
|
||||
BlockVectorSet tmpSet = new BlockVectorSet();
|
||||
for (RelightSkyEntry chunk : chunks) {
|
||||
tmpSet.add(chunk.x, 0, chunk.z);
|
||||
}
|
||||
for (RelightSkyEntry chunk : chunks) {
|
||||
int x = chunk.x;
|
||||
int z = chunk.z;
|
||||
if (tmpSet.contains(x + 1, 0, z) && tmpSet.contains(x - 1, 0, z) && tmpSet.contains(x, 0, z + 1) && tmpSet.contains(x, 0, z - 1)) {
|
||||
chunkSet.add(x, 0, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int y = 255; y > 0; y--) {
|
||||
for (RelightSkyEntry chunk : chunks) { // Propogate skylight
|
||||
int layer = y >> 4;
|
||||
byte[] mask = chunk.mask;
|
||||
if ((y & 15) == 15 && chunk.fix[layer] != SkipReason.NONE) {
|
||||
if ((y & 15) == 0 && layer != 0 && chunk.fix[layer - 1] == SkipReason.NONE) {
|
||||
fill(mask, chunk.x, y, chunk.z, chunk.fix[layer]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
int bx = chunk.x << 4;
|
||||
int bz = chunk.z << 4;
|
||||
ChunkHolder iChunk = (ChunkHolder) queue.getOrCreateChunk(chunk.x, chunk.z);
|
||||
if (!iChunk.isInit()) {
|
||||
iChunk.init(queue, chunk.x, chunk.z);
|
||||
}
|
||||
chunk.smooth = false;
|
||||
|
||||
if (remove && (y & 15) == 15 && chunkSet.contains(chunk.x, 0, chunk.z)) {
|
||||
iChunk.removeSectionLighting(y >> 4, true);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 256; j++) {
|
||||
int x = j & 15;
|
||||
int z = j >> 4;
|
||||
byte value = mask[j];
|
||||
byte pair = MathMan.pair16(iChunk.getOpacity(x, y, z), iChunk.getBrightness(x, y, z));
|
||||
int opacity = MathMan.unpair16x(pair);
|
||||
int brightness = MathMan.unpair16y(pair);
|
||||
if (brightness > 1) {
|
||||
addLightUpdate(bx + x, y, bz + z);
|
||||
}
|
||||
switch (value) {
|
||||
case 0:
|
||||
if (opacity > 1) {
|
||||
iChunk.setSkyLight(x, y, z, 0);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
if (opacity >= value) {
|
||||
mask[j] = 0;
|
||||
iChunk.setSkyLight(x, y, z, 0);
|
||||
continue;
|
||||
}
|
||||
if (opacity <= 1) {
|
||||
mask[j] = --value;
|
||||
} else {
|
||||
mask[j] = value = (byte) Math.max(0, value - opacity);
|
||||
}
|
||||
break;
|
||||
case 15:
|
||||
if (opacity > 1) {
|
||||
value -= opacity;
|
||||
mask[j] = value;
|
||||
}
|
||||
iChunk.setSkyLight(x, y, z, value);
|
||||
continue;
|
||||
}
|
||||
chunk.smooth = true;
|
||||
iChunk.setSkyLight(x, y, z, value);
|
||||
}
|
||||
}
|
||||
for (RelightSkyEntry chunk : chunks) { // Smooth forwards
|
||||
if (chunk.smooth) {
|
||||
smoothSkyLight(chunk, y, true);
|
||||
}
|
||||
}
|
||||
for (int i = chunks.length - 1; i >= 0; i--) { // Smooth backwards
|
||||
RelightSkyEntry chunk = chunks[i];
|
||||
if (chunk.smooth) {
|
||||
smoothSkyLight(chunk, y, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void smoothSkyLight(RelightSkyEntry chunk, int y, boolean direction) {
|
||||
byte[] mask = chunk.mask;
|
||||
ChunkHolder iChunk = (ChunkHolder) queue.getOrCreateChunk(chunk.x, chunk.z);
|
||||
ChunkHolder iChunkx;
|
||||
ChunkHolder iChunkz;
|
||||
if (!iChunk.isInit()) {
|
||||
iChunk.init(queue, chunk.x, chunk.z);
|
||||
}
|
||||
if (direction) {
|
||||
iChunkx = (ChunkHolder) queue.getOrCreateChunk(chunk.x - 1, chunk.z);
|
||||
iChunkz = (ChunkHolder) queue.getOrCreateChunk(chunk.x, chunk.z - 1);
|
||||
if (!iChunkx.isInit()) {
|
||||
iChunkx.init(queue, chunk.x - 1, chunk.z);
|
||||
}
|
||||
if (!iChunkz.isInit()) {
|
||||
iChunkz.init(queue, chunk.x, chunk.z - 1);
|
||||
}
|
||||
for (int j = 0; j < 256; j++) {
|
||||
int x = j & 15;
|
||||
int z = j >> 4;
|
||||
if (mask[j] >= 14 || (mask[j] == 0 && iChunk.getOpacity(x, y, z) > 1)) {
|
||||
continue;
|
||||
}
|
||||
byte value = mask[j];
|
||||
if (x != 0 && z != 0) {
|
||||
if ((value = (byte) Math.max(iChunk.getSkyLight(x - 1, y, z) - 1, value)) >= 14) ;
|
||||
else if ((value = (byte) Math.max(iChunk.getSkyLight(x, y, z - 1) - 1, value)) >= 14) ;
|
||||
if (value > mask[j]) iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
} else if (x == 0 && z == 0) {
|
||||
if ((value = (byte) Math.max(iChunkx.getSkyLight(15, y, z) - 1, value)) >= 14) ;
|
||||
else if ((value = (byte) Math.max(iChunkz.getSkyLight(x, y, 15) - 1, value)) >= 14) ;
|
||||
if (value > mask[j]) iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
} else if (x == 0) {
|
||||
if ((value = (byte) Math.max(iChunkx.getSkyLight(15, y, z) - 1, value)) >= 14) ;
|
||||
else if ((value = (byte) Math.max(iChunk.getSkyLight(x, y, z - 1) - 1, value)) >= 14) ;
|
||||
if (value > mask[j]) iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
} else {
|
||||
if ((value = (byte) Math.max(iChunk.getSkyLight(x - 1, y, z) - 1, value)) >= 14) ;
|
||||
else if ((value = (byte) Math.max(iChunkz.getSkyLight(x, y, 15) - 1, value)) >= 14) ;
|
||||
if (value > mask[j]) iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
iChunkx = (ChunkHolder) queue.getOrCreateChunk(chunk.x + 1, chunk.z);
|
||||
iChunkz = (ChunkHolder) queue.getOrCreateChunk(chunk.x, chunk.z + 1);
|
||||
if (!iChunkx.isInit()) {
|
||||
iChunkx.init(queue, chunk.x - 1, chunk.z);
|
||||
}
|
||||
if (!iChunkz.isInit()) {
|
||||
iChunkz.init(queue, chunk.x, chunk.z - 1);
|
||||
}
|
||||
for (int j = 255; j >= 0; j--) {
|
||||
int x = j & 15;
|
||||
int z = j >> 4;
|
||||
if (mask[j] >= 14 || (mask[j] == 0 && iChunk.getOpacity(x, y, z) > 1)) {
|
||||
continue;
|
||||
}
|
||||
byte value = mask[j];
|
||||
if ( x != 15 && z != 15) {
|
||||
if ((value = (byte) Math.max(iChunk.getSkyLight(x + 1, y, z) - 1, value)) >= 14) ;
|
||||
else if ((value = (byte) Math.max(iChunk.getSkyLight(x, y, z + 1) - 1, value)) >= 14) ;
|
||||
if (value > mask[j]) iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
} else if (x == 15 && z == 15) {
|
||||
if ((value = (byte) Math.max(iChunkx.getSkyLight(0, y, z) - 1, value)) >= 14) ;
|
||||
else if ((value = (byte) Math.max(iChunkz.getSkyLight(x, y, 0) - 1, value)) >= 14) ;
|
||||
if (value > mask[j]) iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
} else if (x == 15) {
|
||||
if ((value = (byte) Math.max(iChunkx.getSkyLight(0, y, z) - 1, value)) >= 14) ;
|
||||
else if ((value = (byte) Math.max(iChunk.getSkyLight(x, y, z + 1) - 1, value)) >= 14) ;
|
||||
if (value > mask[j]) iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
} else {
|
||||
if ((value = (byte) Math.max(iChunk.getSkyLight(x + 1, y, z) - 1, value)) >= 14) ;
|
||||
else if ((value = (byte) Math.max(iChunkz.getSkyLight(x, y, 0) - 1, value)) >= 14) ;
|
||||
if (value > mask[j]) iChunk.setSkyLight(x, y, z, mask[j] = value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class RelightSkyEntry implements Comparable {
|
||||
public final int x;
|
||||
public final int z;
|
||||
public final byte[] mask;
|
||||
public final byte[] fix;
|
||||
public int bitmask;
|
||||
public boolean smooth;
|
||||
|
||||
public RelightSkyEntry(int x, int z, byte[] fix, int bitmask) {
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
byte[] array = new byte[256];
|
||||
Arrays.fill(array, (byte) 15);
|
||||
this.mask = array;
|
||||
this.bitmask = bitmask;
|
||||
if (fix == null) {
|
||||
this.fix = new byte[(maxY + 1) >> 4];
|
||||
Arrays.fill(this.fix, SkipReason.NONE);
|
||||
} else {
|
||||
this.fix = fix;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return x + "," + z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Object o) {
|
||||
RelightSkyEntry other = (RelightSkyEntry) o;
|
||||
if (other.x < x) {
|
||||
return 1;
|
||||
}
|
||||
if (other.x > x) {
|
||||
return -1;
|
||||
}
|
||||
if (other.z < z) {
|
||||
return 1;
|
||||
}
|
||||
if (other.z > z) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.boydti.fawe.beta.implementation.lighting;
|
||||
|
||||
public class NullRelighter implements Relighter {
|
||||
|
||||
public static NullRelighter INSTANCE = new NullRelighter();
|
||||
|
||||
private NullRelighter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addChunk(int cx, int cz, byte[] fix, int bitmask) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLightUpdate(int x, int y, int z) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fixLightingSafe(boolean sky) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLighting() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fixBlockLighting() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fixSkyLighting() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package com.boydti.fawe.beta.implementation.lighting;
|
||||
|
||||
public interface Relighter {
|
||||
|
||||
/**
|
||||
* Add a chunk to be relit when {@link Relighter#removeLighting} etc are called
|
||||
*
|
||||
* @param cx chunk x
|
||||
* @param cz chunk z
|
||||
* @param skipReason byte array of {@link SkipReason} for each chunksection in the chunk. Use case? No idea.
|
||||
* @param bitmask Initial bitmask of the chunk (if being editited beforehand)
|
||||
* @return Was the chunk added
|
||||
*/
|
||||
boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask);
|
||||
|
||||
/**
|
||||
* Add a block to be relit
|
||||
*
|
||||
* @param x block x
|
||||
* @param y block y
|
||||
* @param z block z
|
||||
*/
|
||||
void addLightUpdate(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Safely? Fix block lighting
|
||||
*
|
||||
* @param sky whether to also relight sky light values
|
||||
*/
|
||||
void fixLightingSafe(boolean sky);
|
||||
|
||||
/**
|
||||
* Remove lighting and then relight safely
|
||||
*
|
||||
* @param sky whether to also relight sky light values
|
||||
*/
|
||||
default void removeAndRelight(boolean sky) {
|
||||
removeLighting();
|
||||
fixLightingSafe(sky);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all chunks and blocks to be relit
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Remove all block and sky light values (set to 0 light) in all chunks added to relighter
|
||||
*/
|
||||
void removeLighting();
|
||||
|
||||
/**
|
||||
* Fix block light values in all chunks added to relighter
|
||||
*/
|
||||
void fixBlockLighting();
|
||||
|
||||
/**
|
||||
* Fix sky light values in all chunks added to relighter
|
||||
*/
|
||||
void fixSkyLighting();
|
||||
|
||||
/**
|
||||
* Are there any block or chunk added to be relit
|
||||
*
|
||||
* @return is the relight stuff to be relit empty
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
public static class SkipReason {
|
||||
public static final byte NONE = 0;
|
||||
public static final byte AIR = 1;
|
||||
public static final byte SOLID = 2;
|
||||
}
|
||||
}
|
@ -436,6 +436,24 @@ public class MCAChunk implements IChunk {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public void setBlockLight(int x, int y, int z, int value) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void setSkyLight(int x, int y, int z, int value) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void removeSectionLighting(int layer, boolean sky) {}
|
||||
|
||||
@Override public void setFullBright(int layer) {}
|
||||
|
||||
@Override
|
||||
public void setLightLayer(int layer, char[] toSet) {}
|
||||
|
||||
@Override
|
||||
public void setSkyLightLayer(int layer, char[] toSet) {}
|
||||
|
||||
@Override
|
||||
public void setEntity(CompoundTag entityTag) {
|
||||
setModified();
|
||||
@ -454,6 +472,14 @@ public class MCAChunk implements IChunk {
|
||||
return this.biomes;
|
||||
}
|
||||
|
||||
@Override public char[][] getLight() {
|
||||
return new char[0][];
|
||||
}
|
||||
|
||||
@Override public char[][] getSkyLight() {
|
||||
return new char[0][];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(BlockVector2 pos, BiomeType biome) {
|
||||
return this.setBiome(pos.getX(), 0, pos.getZ(), biome);
|
||||
@ -499,6 +525,15 @@ public class MCAChunk implements IChunk {
|
||||
return BlockState.getFromOrdinal(ordinal);
|
||||
}
|
||||
|
||||
//TODO implement lighting
|
||||
@Override public int getSkyLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public int getEmmittedLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
BlockState block = getBlock(x, y, z);
|
||||
|
@ -0,0 +1,7 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
public enum RelightMode {
|
||||
NONE, // no relighting
|
||||
OPTIMAL, // relight changed light sources and changed blocks
|
||||
ALL // relight every single block
|
||||
}
|
@ -1,27 +1,26 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBatchProcessor;
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.lighting.NMSRelighter;
|
||||
import com.boydti.fawe.beta.implementation.lighting.NullRelighter;
|
||||
import com.boydti.fawe.beta.implementation.lighting.Relighter;
|
||||
import com.boydti.fawe.beta.implementation.processors.LimitProcessor;
|
||||
import com.boydti.fawe.beta.implementation.queue.ParallelQueueExtent;
|
||||
import com.sk89q.worldedit.util.Identifiable;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.HistoryExtent;
|
||||
import com.boydti.fawe.object.NullChangeSet;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.RelightMode;
|
||||
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
|
||||
import com.boydti.fawe.object.changeset.AbstractChangeSet;
|
||||
import com.boydti.fawe.object.changeset.BlockBagChangeSet;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.object.changeset.AbstractChangeSet;
|
||||
import com.boydti.fawe.object.changeset.MemoryOptimizedHistory;
|
||||
import com.boydti.fawe.object.extent.FaweRegionExtent;
|
||||
import com.boydti.fawe.object.extent.MultiRegionExtent;
|
||||
@ -37,12 +36,17 @@ import com.sk89q.worldedit.event.extent.EditSessionEvent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.Identifiable;
|
||||
import com.sk89q.worldedit.util.eventbus.EventBus;
|
||||
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class EditSessionBuilder {
|
||||
@NotNull
|
||||
private World world;
|
||||
@ -60,6 +64,7 @@ public class EditSessionBuilder {
|
||||
private boolean threaded = true;
|
||||
private EditSessionEvent event;
|
||||
private String command;
|
||||
private RelightMode relightMode;
|
||||
|
||||
/**
|
||||
* An EditSession builder<br>
|
||||
@ -80,7 +85,7 @@ public class EditSessionBuilder {
|
||||
checkNotNull(world);
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
|
||||
public EditSessionBuilder player(@Nullable Player player) {
|
||||
this.player = player;
|
||||
return setDirty();
|
||||
@ -172,6 +177,11 @@ public class EditSessionBuilder {
|
||||
return setDirty();
|
||||
}
|
||||
|
||||
public EditSessionBuilder relightMode(@Nullable RelightMode relightMode) {
|
||||
this.relightMode = relightMode;
|
||||
return setDirty();
|
||||
}
|
||||
|
||||
public EditSessionBuilder checkMemory(@Nullable Boolean checkMemory) {
|
||||
this.checkMemory = checkMemory;
|
||||
return setDirty();
|
||||
@ -402,7 +412,7 @@ public class EditSessionBuilder {
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
|
||||
public Extent getExtent() {
|
||||
return extent != null ? extent : world;
|
||||
}
|
||||
@ -410,7 +420,7 @@ public class EditSessionBuilder {
|
||||
public boolean isWrapped() {
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
|
||||
public Extent getBypassHistory() {
|
||||
return bypassHistory;
|
||||
}
|
||||
|
@ -27,9 +27,11 @@ import static com.sk89q.worldedit.regions.Regions.asFlatRegion;
|
||||
import static com.sk89q.worldedit.regions.Regions.maximumBlockY;
|
||||
import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.config.Caption;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.RelightMode;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
@ -139,16 +141,15 @@ public class RegionCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.light.fix")
|
||||
public void fixLighting(Player player) throws WorldEditException {
|
||||
player.print(TextComponent.of("Temporarily not working"));
|
||||
// final Location loc = player.getLocation();
|
||||
// Region selection = player.getSelection();
|
||||
// if (selection == null) {
|
||||
// final int cx = loc.getBlockX() >> 4;
|
||||
// final int cz = loc.getBlockZ() >> 4;
|
||||
// selection = new CuboidRegion(BlockVector3.at(cx - 8, 0, cz - 8).multiply(16), BlockVector3.at(cx + 8, 0, cz + 8).multiply(16));
|
||||
// }
|
||||
// int count = FaweAPI.fixLighting(player.getWorld(), selection,null);
|
||||
// player.print(Caption.of("fawe.info.lighting.propagate.selection" , count));
|
||||
final Location loc = player.getLocation();
|
||||
Region selection = player.getSelection();
|
||||
if (selection == null) {
|
||||
final int cx = loc.getBlockX() >> 4;
|
||||
final int cz = loc.getBlockZ() >> 4;
|
||||
selection = new CuboidRegion(BlockVector3.at(cx - 8, 0, cz - 8).multiply(16), BlockVector3.at(cx + 8, 0, cz + 8).multiply(16));
|
||||
}
|
||||
int count = FaweAPI.fixLighting(player.getWorld(), selection,null, RelightMode.ALL);
|
||||
player.print(Caption.of("fawe.info.lighting.propagate.selection" , count));
|
||||
}
|
||||
|
||||
// @Command(
|
||||
@ -163,22 +164,21 @@ public class RegionCommands {
|
||||
// player.print(TextComponent.of("Light: " + block + " | " + sky));
|
||||
// }
|
||||
|
||||
// @Command(
|
||||
// name = "/removelighting",
|
||||
// desc = "Removing lighting in a selection"
|
||||
// )
|
||||
// @CommandPermissions("worldedit.light.remove")
|
||||
// public void removeLighting(Player player) {
|
||||
// player.print(TextComponent.of("Temporarily not working"));
|
||||
// Region selection = player.getSelection();
|
||||
// if (selection == null) {
|
||||
// final int cx = player.getLocation().getBlockX() >> 4;
|
||||
// final int cz = player.getLocation().getBlockZ() >> 4;
|
||||
// selection = new CuboidRegion(BlockVector3.at(cx - 8, 0, cz - 8).multiply(16), BlockVector3.at(cx + 8, 0, cz + 8).multiply(16));
|
||||
// }
|
||||
// int count = FaweAPI.fixLighting(player.getWorld(), selection, null);
|
||||
// player.print(Caption.of("fawe.info.updated.lighting.selection" , count));
|
||||
// }
|
||||
@Command(
|
||||
name = "/removelighting",
|
||||
desc = "Removing lighting in a selection"
|
||||
)
|
||||
@CommandPermissions("worldedit.light.remove")
|
||||
public void removeLighting(Player player) {
|
||||
Region selection = player.getSelection();
|
||||
if (selection == null) {
|
||||
final int cx = player.getLocation().getBlockX() >> 4;
|
||||
final int cz = player.getLocation().getBlockZ() >> 4;
|
||||
selection = new CuboidRegion(BlockVector3.at(cx - 8, 0, cz - 8).multiply(16), BlockVector3.at(cx + 8, 0, cz + 8).multiply(16));
|
||||
}
|
||||
int count = FaweAPI.fixLighting(player.getWorld(), selection, null, RelightMode.NONE);
|
||||
player.print(Caption.of("fawe.info.updated.lighting.selection" , count));
|
||||
}
|
||||
|
||||
@Command(
|
||||
name = "/nbtinfo",
|
||||
|
@ -205,6 +205,46 @@ public class AbstractDelegateExtent implements Extent {
|
||||
public boolean setBiome(BlockVector2 position, BiomeType biome) {
|
||||
return extent.setBiome(position.getX(), 0, position.getZ(), biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean relight(int x, int y, int z) {
|
||||
return extent.relight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean relightBlock(int x, int y, int z) {
|
||||
return extent.relightBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean relightSky(int x, int y, int z) {
|
||||
return extent.relightSky(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLight(int x, int y, int z, int value) {
|
||||
extent.setSkyLight(x, y, z, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockLight(int x, int y, int z, int value) {
|
||||
extent.setSkyLight(x, y, z, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
return extent.getSkyLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
return extent.getEmmittedLight(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightness(int x, int y, int z) {
|
||||
return extent.getBrightness(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -651,6 +651,18 @@ public interface Extent extends InputExtent, OutputExtent {
|
||||
return count;
|
||||
}
|
||||
|
||||
default boolean relight(int x, int y, int z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean relightBlock(int x, int y, int z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean relightSky(int x, int y, int z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Have an extent processed
|
||||
* - Either block (Extent) processing or chunk processing
|
||||
|
@ -85,4 +85,48 @@ public interface InputExtent {
|
||||
default BiomeType getBiomeType(int x, int y, int z) {
|
||||
return getBiome(MutableBlockVector2.get(x, z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the light level at the given location
|
||||
*
|
||||
* @param position location
|
||||
* @return the light level at the location
|
||||
*/
|
||||
default int getEmmittedLight(MutableBlockVector3 position) {
|
||||
return getEmmittedLight(position.getX(), position.getY(), position.getZ());
|
||||
}
|
||||
|
||||
default int getEmmittedLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sky light level at the given location
|
||||
*
|
||||
* @param position location
|
||||
* @return the sky light level at the location
|
||||
*/
|
||||
default int getSkyLight(MutableBlockVector3 position) {
|
||||
return getSkyLight(position.getX(), position.getY(), position.getZ());
|
||||
}
|
||||
|
||||
default int getSkyLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
default int getBrightness(MutableBlockVector3 position) {
|
||||
return getBrightness(position.getX(), position.getY(), position.getZ());
|
||||
}
|
||||
|
||||
default int getBrightness(int x, int y, int z) {
|
||||
return getFullBlock(x, y, z).getMaterial().getLightValue();
|
||||
}
|
||||
|
||||
default int getOpacity(MutableBlockVector3 position) {
|
||||
return getOpacity(position.getX(), position.getY(), position.getZ());
|
||||
}
|
||||
|
||||
default int getOpacity(int x, int y, int z) {
|
||||
return getFullBlock(x, y, z).getMaterial().getLightOpacity();
|
||||
}
|
||||
}
|
||||
|
@ -82,6 +82,30 @@ public interface OutputExtent {
|
||||
return setBiome(MutableBlockVector2.get(x, z), biome);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the light value
|
||||
*
|
||||
* @param position position of the block
|
||||
* @param value light level to set
|
||||
*/
|
||||
default void setBlockLight(BlockVector3 position, int value) {
|
||||
setBlockLight(position.getX(), position.getY(), position.getZ(), value);
|
||||
}
|
||||
|
||||
default void setBlockLight(int x, int y, int z, int value) {}
|
||||
|
||||
/**
|
||||
* Set the sky light value
|
||||
*
|
||||
* @param position position of the block
|
||||
* @param value light level to set
|
||||
*/
|
||||
default void setSkyLight(BlockVector3 position, int value) {
|
||||
setSkyLight(position.getX(), position.getY(), position.getZ(), value);
|
||||
}
|
||||
|
||||
default void setSkyLight(int x, int y, int z, int value) {}
|
||||
|
||||
/**
|
||||
* Return an {@link Operation} that should be called to tie up loose ends
|
||||
* (such as to commit changes in a buffer).
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren