BeYkeRYkt / LightAPI

[ARCHIVED] Bukkit/Sponge library for create invisible light source
MIT License
56 stars 36 forks source link

Can not create light in empty chunk section surrounded by other empty sections. #15

Closed Qveshn closed 4 years ago

Qveshn commented 5 years ago

Exception occurs when creating light in chunk section (16x16x16) which is completely empty and all surrounded 26 ones are also completely empty.

LightAPI was built from the latest commit 3a1aacb. The method ru.beykerykt.minecraft.lightapi.common.LightAPI.createLight is calling with type=LightType.BLOCK. Exception:

java.lang.NullPointerException
    at net.minecraft.server.v1_14_R1.LightEngineStorage.i(SourceFile:93)
    at net.minecraft.server.v1_14_R1.LightEngineLayer.c(SourceFile:137)
    at net.minecraft.server.v1_14_R1.LightEngineGraph.a(SourceFile:123)
    at net.minecraft.server.v1_14_R1.LightEngineBlock.a(SourceFile:126)
    at ru.beykerykt.minecraft.lightapi.impl.bukkit.nms.NMS_v1_14_R1.setRawLightLevel(NMS_v1_14_R1.java:209)
    at ru.beykerykt.minecraft.lightapi.impl.bukkit.nms.NMS_v1_14_R1.createLight(NMS_v1_14_R1.java:128)
    at ru.beykerykt.minecraft.lightapi.impl.bukkit.NMSLightHandler.createLight(NMSLightHandler.java:60)
    at ru.beykerykt.minecraft.lightapi.impl.bukkit.NMSLightHandler.createLight(NMSLightHandler.java:55)
    at ru.beykerykt.minecraft.lightapi.common.LightAPI.createLight(LightAPI.java:67)
    at io.github.sipsi133.LightedLocations.creatLight(LightedLocations.java:248)
    at io.github.sipsi133.LightedLocations.flush(LightedLocations.java:189)
    at io.github.sipsi133.ShinyItems.lambda$onEnable$2(ShinyItems.java:119)
    at org.bukkit.craftbukkit.v1_14_R1.scheduler.CraftTask.run(CraftTask.java:81)
    at org.bukkit.craftbukkit.v1_14_R1.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:394)
    at net.minecraft.server.v1_14_R1.MinecraftServer.b(MinecraftServer.java:1008)
    at net.minecraft.server.v1_14_R1.DedicatedServer.b(DedicatedServer.java:396)
    at net.minecraft.server.v1_14_R1.MinecraftServer.a(MinecraftServer.java:956)
    at net.minecraft.server.v1_14_R1.MinecraftServer.run(MinecraftServer.java:801)
    at java.lang.Thread.run(Unknown Source)

Problem here: net.minecraft.server.v1_14_R1.LightEngineStorage.i

    protected int i(long var0) { // var0 - block position as long (bits of X,Y,Z)
        long var2 = SectionPosition.e(var0);
        NibbleArray var4 = this.a(var2, true);
        return var4.a(SectionPosition.b(BlockPosition.b(var0)), SectionPosition.b(BlockPosition.c(var0)), SectionPosition.b(BlockPosition.d(var0)));
    }

Possibly var4 is null.

I think this is because bukkit does not stores that empty section (memory optimization). Bukkit assumes that lights can be spawned only at non-air-blocks. And light source can be spread maximum with 15 blocks and affects maximum only neighbour sections. So, bukkit stores only those empty sections that have atleast one non-empty neighbour section and no more.

Could you find workaround for this problem?

There are two ways:

  1. Somehow to create that empty chunk section when setting light in it. But I do not know if it is possible at all and besides, the light will still not spread to neighboring sections without NibbleArray (I've checked it). Also, I think this will unreasonable increase storage in mca file
  2. To make the check and do not create light if there is no that NibbleArray in the section. But I do not know how to make the check more correct.

I think the second way is more realistic :smiley: ATM I use the second way, but with bad implementation. I use something like:

boolean result;
try {
    result = ru.beykerykt.minecraft.lightapi.common.LightAPI.createLight(
            location.getWorld().getName(),
            LightType.BLOCK,
            location.getBlockX(),
            location.getBlockY(),
            location.getBlockZ(),
            lightLevel);
} catch (NullPointerException ignore) {
    result = false;
}
Qveshn commented 5 years ago

Solution: check if NibbleArray is not nul at his position

    ...
    if (leb.a(SectionPosition.a(position)) != null) {
        leb.a(position, finalLightLevel);
    }
    ...

In addition: I have released 1.14 update for LightAPI in my fork. There you can see how I solved this and other problems (NibbleArray, client view distance, locking ThreadedMailbox). Here is nms engine for 1.14: https://github.com/Qveshn/LightAPI/blob/3.0/nms/v1_14_R1/src/main/java/ru/beykerykt/lightapi/server/nms/craftbukkit/CraftBukkit_v1_14_R1.java