0.3.7-ALPHA Exterimental Light Engine (Reset mapping.json to use)

This commit is contained in:
LOOHP 2020-11-05 16:08:04 +08:00
parent 052d8bb021
commit 82e575e897
11 changed files with 489 additions and 12 deletions

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.loohp</groupId>
<artifactId>Limbo</artifactId>
<version>0.3.6-ALPHA</version>
<version>0.3.7-ALPHA</version>
<build>
<sourceDirectory>src</sourceDirectory>
<resources>
@ -64,6 +64,11 @@
</repositories>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
<dependency>
<groupId>com.github.Querz</groupId>
<artifactId>NBT</artifactId>

View File

@ -39,6 +39,7 @@ import com.loohp.limbo.Server.Packets.PacketPlayInRotation;
import com.loohp.limbo.Server.Packets.PacketPlayInTabComplete;
import com.loohp.limbo.Server.Packets.PacketPlayOutDeclareCommands;
import com.loohp.limbo.Server.Packets.PacketPlayOutDisconnect;
import com.loohp.limbo.Server.Packets.PacketPlayOutLightUpdate;
import com.loohp.limbo.Server.Packets.PacketPlayOutLogin;
import com.loohp.limbo.Server.Packets.PacketPlayOutMapChunk;
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerAbilities;
@ -300,11 +301,28 @@ public class ClientConnection extends Thread {
if (chunk != null) {
PacketPlayOutMapChunk chunkdata = new PacketPlayOutMapChunk(x, z, chunk, world.getEnvironment());
sendPacket(chunkdata);
//Limbo.getInstance().getConsole().sendMessage(x + ", " + z);
}
}
}
for (int x = 0; x < world.getChunks().length; x++) {
for (int z = 0; z < world.getChunks()[x].length; z++) {
List<Byte[]> blockChunk = world.getLightEngineBlock().getBlockLightBitMask(x, z);
if (blockChunk == null) {
blockChunk = new ArrayList<>();
}
List<Byte[]> skyChunk = null;
if (world.hasSkyLight()) {
skyChunk = world.getLightEngineSky().getSkyLightBitMask(x, z);
}
if (skyChunk == null) {
skyChunk = new ArrayList<>();
}
PacketPlayOutLightUpdate chunkdata = new PacketPlayOutLightUpdate(x, z, true, skyChunk, blockChunk);
sendPacket(chunkdata);
}
}
SkinResponse skinresponce = isBungeecord ? bungeeSkin : MojangAPIUtils.getSkinFromMojangServer(player.getName());
PlayerSkinProperty skin = skinresponce != null ? new PlayerSkinProperty(skinresponce.getSkin(), skinresponce.getSignature()) : null;
PacketPlayOutPlayerInfo info = new PacketPlayOutPlayerInfo(PlayerInfoAction.ADD_PLAYER, player.getUUID(), new PlayerInfoData.PlayerInfoDataAddPlayer(player.getName(), Optional.ofNullable(skin), p.getDefaultGamemode(), 0, false, Optional.empty()));

View File

@ -0,0 +1,111 @@
package com.loohp.limbo.Server.Packets;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.List;
import com.loohp.limbo.Utils.DataTypeIO;
public class PacketPlayOutLightUpdate extends PacketOut {
private int chunkX;
private int chunkZ;
private boolean trustEdges;
private int skyLightBitMask;
private int blockLightBitMask;
private List<Byte[]> skylightArrays;
private List<Byte[]> blocklightArrays;
public PacketPlayOutLightUpdate(int chunkX, int chunkZ, boolean trustEdges, List<Byte[]> skylightArrays, List<Byte[]> blocklightArrays) {
this.chunkX = chunkX;
this.chunkZ = chunkZ;
this.trustEdges = trustEdges;
this.skylightArrays = skylightArrays;
this.blocklightArrays = blocklightArrays;
skyLightBitMask = 0;
for (int i = Math.min(17, skylightArrays.size() - 1); i >= 0; i--) {
skyLightBitMask = skyLightBitMask >> 1;
if (skylightArrays.get(i) != null) {
skyLightBitMask |= 131072;
}
}
blockLightBitMask = 0;
for (int i = Math.min(17, blocklightArrays.size() - 1); i >= 0; i--) {
blockLightBitMask = blockLightBitMask >> 1;
if (blocklightArrays.get(i) != null) {
blockLightBitMask |= 131072;
}
}
}
public int getChunkX() {
return chunkX;
}
public int getChunkZ() {
return chunkZ;
}
public boolean isTrustEdges() {
return trustEdges;
}
public int getSkyLightBitMask() {
return skyLightBitMask;
}
public int getBlockLightBitMask() {
return blockLightBitMask;
}
public List<Byte[]> getSkylightArrays() {
return skylightArrays;
}
public List<Byte[]> getBlocklightArrays() {
return blocklightArrays;
}
@Override
public byte[] serializePacket() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
DataTypeIO.writeVarInt(output, chunkX);
DataTypeIO.writeVarInt(output, chunkZ);
output.writeBoolean(trustEdges);
DataTypeIO.writeVarInt(output, skyLightBitMask);
DataTypeIO.writeVarInt(output, blockLightBitMask);
DataTypeIO.writeVarInt(output, ~skyLightBitMask & 262143);
DataTypeIO.writeVarInt(output, ~blockLightBitMask & 262143);
for (int i = skylightArrays.size() - 1; i >= 0; i--) {
Byte[] array = skylightArrays.get(i);
if (array != null) {
DataTypeIO.writeVarInt(output, 2048);
//System.out.println(Arrays.toString(ArrayUtils.toPrimitive(array)));
for (int u = 0; u < array.length; u++) {
output.writeByte(array[u]);
}
}
}
for (int i = blocklightArrays.size() - 1; i >= 0; i--) {
Byte[] array = blocklightArrays.get(i);
if (array != null) {
DataTypeIO.writeVarInt(output, 2048);
//System.out.println(Arrays.toString(ArrayUtils.toPrimitive(array)));
for (int u = 0; u < array.length; u++) {
output.writeByte(array[u]);
}
}
}
return buffer.toByteArray();
}
}

View File

@ -60,4 +60,34 @@ public class BlockState {
properties.putString(key, ((T) value).toString());
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((tag == null) ? 0 : tag.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
BlockState other = (BlockState) obj;
if (tag == null) {
if (other.tag != null) {
return false;
}
} else if (!tag.equals(other.tag)) {
return false;
}
return true;
}
}

View File

@ -1,12 +1,17 @@
package com.loohp.limbo.World;
import java.util.HashSet;
import java.util.Set;
import com.loohp.limbo.Utils.NamespacedKey;
public class Environment {
public static final Environment NORMAL = new Environment(new NamespacedKey("minecraft:overworld"));
public static final Environment NETHER = new Environment(new NamespacedKey("minecraft:the_nether"));
public static final Environment END = new Environment(new NamespacedKey("minecraft:the_end"));
public static final Environment NORMAL = new Environment(new NamespacedKey("minecraft:overworld"), true);
public static final Environment NETHER = new Environment(new NamespacedKey("minecraft:the_nether"), false);
public static final Environment END = new Environment(new NamespacedKey("minecraft:the_end"), false);
public static final Set<Environment> REGISTERED_ENVIRONMENTS = new HashSet<>();
public static Environment fromNamespacedKey(NamespacedKey key) {
if (key.equals(NORMAL.getNamespacedKey())) {
@ -19,19 +24,71 @@ public class Environment {
return null;
}
@Deprecated
public static Environment createCustom(NamespacedKey key) {
return new Environment(key);
return createCustom(key, true);
}
public static Environment createCustom(NamespacedKey key, boolean hasSkyLight) {
if (REGISTERED_ENVIRONMENTS.stream().anyMatch(each -> each.getNamespacedKey().equals(key))) {
throw new IllegalArgumentException("An Environment is already created with this NamespacedKey");
}
return new Environment(key, hasSkyLight);
}
public static Environment getCustom(NamespacedKey key) {
return REGISTERED_ENVIRONMENTS.stream().filter(each -> each.getNamespacedKey().equals(key)).findFirst().orElse(null);
}
//=========================
private NamespacedKey key;
private boolean hasSkyLight;
private Environment(NamespacedKey key) {
private Environment(NamespacedKey key, boolean hasSkyLight) {
this.key = key;
this.hasSkyLight = hasSkyLight;
}
public NamespacedKey getNamespacedKey() {
return key;
}
public boolean hasSkyLight() {
return hasSkyLight;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (hasSkyLight ? 1231 : 1237);
result = prime * result + ((key == null) ? 0 : key.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Environment other = (Environment) obj;
if (hasSkyLight != other.hasSkyLight) {
return false;
}
if (key == null) {
if (other.key != null) {
return false;
}
} else if (!key.equals(other.key)) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,43 @@
package com.loohp.limbo.World;
import java.util.HashMap;
import java.util.Map;
public abstract class LightEngine {
private static Map<String, Byte> blockLightLevelMapping = new HashMap<>();
static {
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:torch", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
}
public static int getBlockLight(BlockState block) {
return blockLightLevelMapping.getOrDefault(block.getType().toString(), (byte) 0);
}
}

View File

@ -0,0 +1,75 @@
package com.loohp.limbo.World;
import java.util.ArrayList;
import java.util.List;
public class LightEngineBlock extends LightEngine {
private World world;
private byte[][][] blockLightArray;
public LightEngineBlock(World world) {
blockLightArray = new byte[world.getChunkWidth() * 16][16 * 18][world.getChunkLength() * 16];
this.world = world;
updateWorld();
}
public void updateWorld() {
blockLightArray = new byte[world.getChunkWidth() * 16][16 * 18][world.getChunkLength() * 16];
for (int x = 0; x < world.getWidth(); x++) {
for (int y = 0; y < 256; y++) {
for (int z = 0; z < world.getLength(); z++) {
updateBlock(x, y, z);
}
}
}
}
private void updateBlock(int x, int y, int z) {
BlockState block = world.getBlock(x, y, z);
int lightLevel = getBlockLight(block);
if (lightLevel > 0) {
propergate(lightLevel, x, y, z);
}
}
private void propergate(int level, int x, int y, int z) {
if (blockLightArray[x][y + 16][z] < level) {
blockLightArray[x][y + 16][z] = (byte) level;
if (level > 1) {
propergate(level - 1, x + 1, y, z);
propergate(level - 1, x - 1, y, z);
propergate(level - 1, x, y + 1, z);
propergate(level - 1, x, y - 1, z);
propergate(level - 1, x, y, z + 1);
propergate(level - 1, x, y, z - 1);
}
}
}
public List<Byte[]> getBlockLightBitMask(int chunkX, int chunkZ) {
List<Byte[]> subchunks = new ArrayList<>(18);
int startX = chunkX * 16;
int endingX = startX + 16;
int startZ = chunkZ * 16;
int endingZ = startZ + 16;
for (int sub = 17; sub >= 0; sub--) {
List<Byte> array = new ArrayList<>();
for (int y = sub * 16; y < (sub * 16) + 16; y++) {
for (int z = startZ; z < endingZ; z++) {
for (int x = startX; x < endingX; x += 2) {
int bit = blockLightArray[x][y][z];
bit = bit << 4;
bit |= blockLightArray[x + 1][y][z];
array.add((byte) bit);
}
}
}
subchunks.add(array.toArray(new Byte[2048]));
}
return subchunks;
}
}

View File

@ -0,0 +1,87 @@
package com.loohp.limbo.World;
import java.util.ArrayList;
import java.util.List;
public class LightEngineSky extends LightEngine {
private World world;
private byte[][][] skyLightArray;
public LightEngineSky(World world) {
skyLightArray = new byte[world.getChunkWidth() * 16][16 * 18][world.getChunkLength() * 16];
/*
for (byte[][] arrayarray : skyLightArray) {
for (byte[] array : arrayarray) {
Arrays.fill(array, (byte) 0);
}
}
*/
this.world = world;
updateWorld();
}
public void updateWorld() {
skyLightArray = new byte[world.getChunkWidth() * 16][16 * 18][world.getChunkLength() * 16];
for (int x = 0; x < world.getWidth(); x++) {
for (int z = 0; z < world.getLength(); z++) {
updateColumn(x, z);
}
}
}
private void updateColumn(int x, int z) {
for (int y = 272; y >= 256; y--) {
propergate(15, x, y, z);
}
for (int y = 255; y >= 0; y--) {
BlockState block = world.getBlock(x, y, z);
//System.out.println("X:" + x + " Y: " + y + " Z: " + z + " Block: " + block.getType().toString());
if (!block.getType().toString().equals("minecraft:air")) {
break;
}
propergate(15, x, y, z);
}
}
private void propergate(int level, int x, int y, int z) {
try {
if (skyLightArray[x][y + 16][z] < level) {
skyLightArray[x][y + 16][z] = (byte) level;
if (level > 1) {
propergate(level - 1, x + 1, y, z);
propergate(level - 1, x - 1, y, z);
propergate(level - 1, x, y + 1, z);
propergate(level - 1, x, y, z + 1);
propergate(level - 1, x, y, z - 1);
}
}
} catch (ArrayIndexOutOfBoundsException e) {}
}
public List<Byte[]> getSkyLightBitMask(int chunkX, int chunkZ) {
List<Byte[]> subchunks = new ArrayList<>(18);
int startX = chunkX * 16;
int endingX = startX + 16;
int startZ = chunkZ * 16;
int endingZ = startZ + 16;
for (int sub = 17; sub >= 0; sub--) {
List<Byte> array = new ArrayList<>();
for (int y = sub * 16; y < (sub * 16) + 16; y++) {
for (int z = startZ; z < endingZ; z++) {
for (int x = startX; x < endingX; x += 2) {
int bit = skyLightArray[x][y][z];
bit = bit << 4;
bit |= skyLightArray[x + 1][y][z];
array.add((byte) bit);
}
}
}
subchunks.add(array.toArray(new Byte[2048]));
}
return subchunks;
}
}

View File

@ -78,11 +78,16 @@ public class Schematic {
heightMap.putLongArray("MOTION_BLOCKING", new long[] {1371773531765642314L,1389823183635651148L,1371738278539598925L,1389823183635388492L,1353688558756731469L,1389823114781694027L,1317765589597723213L,1371773531899860042L,1389823183635651149L,1371773462911685197L,1389823183635650636L,1353688626805119565L,1371773531900123211L,1335639250618849869L,1371738278674077258L,1389823114781694028L,1353723811310638154L,1371738278674077259L,1335674228429068364L,1335674228429067338L,1335674228698027594L,1317624576693539402L,1335709481520370249L,1299610178184057417L,1335638906349064264L,1299574993811968586L,1299574924958011464L,1299610178184056904L,1299574924958011464L,1299610109330100296L,1299574924958011464L,1299574924823793736L,1299574924958011465L,1281525273222484040L,1299574924958011464L,1281525273222484040L,9548107335L});
chunk.setHeightMaps(heightMap);
chunk.setBiomes(new int[256]);
//chunk.cleanupPalettesAndBlockStates();
chunk.cleanupPalettesAndBlockStates();
}
}
}
world.getLightEngineBlock().updateWorld();
if (world.hasSkyLight()) {
world.getLightEngineSky().updateWorld();
}
return world;
}
}

View File

@ -13,11 +13,17 @@ public class World {
private String name;
private Environment environment;
private Chunk[][] chunks;
private int width;
private int length;
private LightEngineBlock lightEngineBlock;
private LightEngineSky lightEngineSky;
public World(String name, int width, int length, Environment environment) {
this.name = name;
this.environment = environment;
this.chunks = new Chunk[(width >> 4) + 1][(length >> 4) + 1];
this.width = width;
this.length = length;
for (int x = 0; x < chunks.length; x++) {
for (int z = 0; z < chunks[x].length; z++) {
@ -26,7 +32,7 @@ public class World {
chunk.cleanupPalettesAndBlockStates();
CompoundTag heightMap = new CompoundTag();
heightMap.putLongArray("MOTION_BLOCKING",
new long[] { 1371773531765642314L, 1389823183635651148L, 1371738278539598925L,
new long[] {1371773531765642314L, 1389823183635651148L, 1371738278539598925L,
1389823183635388492L, 1353688558756731469L, 1389823114781694027L, 1317765589597723213L,
1371773531899860042L, 1389823183635651149L, 1371773462911685197L, 1389823183635650636L,
1353688626805119565L, 1371773531900123211L, 1335639250618849869L, 1371738278674077258L,
@ -35,12 +41,29 @@ public class World {
1299610178184057417L, 1335638906349064264L, 1299574993811968586L, 1299574924958011464L,
1299610178184056904L, 1299574924958011464L, 1299610109330100296L, 1299574924958011464L,
1299574924823793736L, 1299574924958011465L, 1281525273222484040L, 1299574924958011464L,
1281525273222484040L, 9548107335L });
1281525273222484040L, 9548107335L});
chunk.setHeightMaps(heightMap);
chunk.setBiomes(new int[256]);
chunk.setTileEntities(new ListTag<CompoundTag>(CompoundTag.class));
}
}
this.lightEngineBlock = new LightEngineBlock(this);
if (environment.hasSkyLight()) {
this.lightEngineSky = new LightEngineSky(this);
}
}
public LightEngineBlock getLightEngineBlock() {
return lightEngineBlock;
}
public LightEngineSky getLightEngineSky() {
return lightEngineSky;
}
public boolean hasSkyLight() {
return lightEngineSky != null;
}
protected void setBlock(int x, int y, int z, String blockdata) {
@ -59,7 +82,13 @@ public class World {
chunk = Chunk.newChunk();
this.chunks[(x >> 4)][(z >> 4)] = chunk;
}
return new BlockState(chunk.getBlockStateAt(x % 16, y % 16, z % 16));
CompoundTag tag = chunk.getBlockStateAt(x, y, z);
if (tag == null) {
tag = new CompoundTag();
tag.putString("Name", "minecraft:air");
}
return new BlockState(tag);
}
public void setBlock(int x, int y, int z, BlockState state) {
@ -87,6 +116,22 @@ public class World {
return environment;
}
public int getWidth() {
return width;
}
public int getLength() {
return length;
}
public int getChunkWidth() {
return (width >> 4) + 1;
}
public int getChunkLength() {
return (length >> 4) + 1;
}
@Override
public int hashCode() {
final int prime = 31;

View File

@ -27,6 +27,7 @@
"PacketPlayOutChat": "0x0E",
"PacketPlayOutPlayerAbilities": "0x30",
"PacketPlayOutMapChunk": "0x20",
"PacketPlayOutLightUpdate": "0x23",
"PacketPlayOutKeepAlive": "0x1F",
"PacketPlayOutPlayerInfo": "0x32",
"PacketPlayOutUpdateViewPosition": "0x40",