Skip to content
This repository was archived by the owner on Sep 14, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions demo/src/main/java/net/minestom/demo/PlayerInit.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ public class PlayerInit {
NoiseTestGenerator noiseTestGenerator = new NoiseTestGenerator();

InstanceContainer instanceContainer = instanceManager.createInstanceContainer(DimensionType.OVERWORLD);
instanceContainer.setupLightManager(true, true);
instanceContainer.setChunkGenerator(chunkGeneratorDemo);

if (false) {
Expand Down
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ adventure = "4.9.3"
kotlin = "1.6.10"
hydrazine = "1.7.2"
dependencyGetter = "v1.0.1"
minestomData = "895581d464"
minestomData = "cc58d6848671e8d48d240db7323a1d7ef8aefc4d"
hephaistos = "2.4.2"
jetbrainsAnnotations = "23.0.0"

Expand Down Expand Up @@ -53,7 +53,7 @@ kotlin-stdlib-jdk8 = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk
# Miscellaneous
hydrazine = { group = "com.github.MadMartian", name = "hydrazine-path-finding", version.ref = "hydrazine" }
dependencyGetter = { group = "com.github.Minestom", name = "DependencyGetter", version.ref = "dependencyGetter" }
minestomData = { group = "com.github.Minestom", name = "MinestomDataGenerator", version.ref = "minestomData" }
minestomData = { group = "com.github.RinesThaix", name = "MinestomDataGenerator", version.ref = "minestomData" }
jetbrainsAnnotations = { group = "org.jetbrains", name = "annotations", version.ref = "jetbrainsAnnotations" }

# Logging
Expand Down
17 changes: 10 additions & 7 deletions src/main/java/net/minestom/server/instance/AnvilLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import net.minestom.server.MinecraftServer;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.instance.light.ChunkLightData;
import net.minestom.server.tag.Tag;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.async.AsyncUtils;
Expand Down Expand Up @@ -82,6 +83,7 @@ public void loadInstance(@NotNull Instance instance) {
return CompletableFuture.completedFuture(null);

Chunk chunk = new DynamicChunk(instance, chunkX, chunkZ);
chunk.setStatus(ChunkStatus.READING);
if(fileChunk.getMinY() < instance.getDimensionType().getMinY()) {
throw new AnvilException(
String.format("Trying to load chunk with minY = %d, but instance dimension type (%s) has a minY of %d",
Expand Down Expand Up @@ -125,14 +127,15 @@ public void loadInstance(@NotNull Instance instance) {
loadBlocks(chunk, fileChunk);
loadTileEntities(chunk, fileChunk);
// Lights
for (int sectionY = chunk.getMinSection(); sectionY < chunk.getMaxSection(); sectionY++) {
var section = chunk.getSection(sectionY);
var chunkSection = fileChunk.getSection((byte) sectionY);
section.setSkyLight(chunkSection.getSkyLights());
section.setBlockLight(chunkSection.getBlockLights());
final ChunkLightData lightData = chunk.getLightData();
for (int sectionY = chunk.getMinSection(); sectionY <= chunk.getMaxSection(); sectionY++) {
final ChunkSection chunkSection = fileChunk.getSection((byte) sectionY);
lightData.setSkyLight(sectionY, chunkSection.getSkyLights());
lightData.setBlockLight(sectionY, chunkSection.getBlockLights());
}
mcaFile.forget(fileChunk);
return CompletableFuture.completedFuture(chunk);
chunk.setStatus(ChunkStatus.LIGHTING);
return lightData.lightChunk(true);
}

private @Nullable RegionFile getMCAFile(Instance instance, int chunkX, int chunkZ) {
Expand Down Expand Up @@ -277,7 +280,7 @@ private void loadTileEntities(Chunk loadedChunk, ChunkColumn fileChunk) {

private void save(Chunk chunk, ChunkColumn chunkColumn) {
chunkColumn.changeVersion(SupportedVersion.Companion.getLatest());
chunkColumn.setYRange(chunk.getMinSection()*16, chunk.getMaxSection()*16-1);
chunkColumn.setYRange(chunk.getMinSection() << 4, chunk.getMaxSection() << 4);
List<NBTCompound> tileEntities = new ArrayList<>();
chunkColumn.setGenerationStatus(ChunkColumn.GenerationStatus.Full);
for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
Expand Down
44 changes: 43 additions & 1 deletion src/main/java/net/minestom/server/instance/Chunk.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@
import net.minestom.server.entity.Player;
import net.minestom.server.entity.pathfinding.PFColumnarSpace;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.light.ChunkLightData;
import net.minestom.server.instance.light.InstanceLightManager;
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
import net.minestom.server.snapshot.Snapshotable;
import net.minestom.server.tag.Tag;
import net.minestom.server.tag.TagHandler;
import net.minestom.server.utils.chunk.ChunkSupplier;
import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.utils.time.Cooldown;
import net.minestom.server.utils.validate.Check;
import net.minestom.server.world.biomes.Biome;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;
Expand Down Expand Up @@ -47,6 +52,8 @@ public abstract class Chunk implements Block.Getter, Block.Setter, Biome.Getter,
protected final int chunkX, chunkZ;
protected final int minSection, maxSection;

private volatile ChunkStatus status = ChunkStatus.INITIALIZATION;

// Options
private final boolean shouldGenerate;
private boolean readOnly;
Expand All @@ -60,6 +67,9 @@ public abstract class Chunk implements Block.Getter, Block.Setter, Biome.Getter,
// Data
private final MutableNBTCompound nbt = new MutableNBTCompound();

private volatile ChunkLightData lightData;
private long lastLightUpdate;

public Chunk(@NotNull Instance instance, int chunkX, int chunkZ, boolean shouldGenerate) {
this.identifier = UUID.randomUUID();
this.instance = instance;
Expand All @@ -69,6 +79,17 @@ public Chunk(@NotNull Instance instance, int chunkX, int chunkZ, boolean shouldG
this.minSection = instance.getDimensionType().getMinY() / CHUNK_SECTION_SIZE;
this.maxSection = (instance.getDimensionType().getMinY() + instance.getDimensionType().getHeight()) / CHUNK_SECTION_SIZE;
this.viewers = new ChunkView(instance, toPosition());

instance.registerChunk(this);
}

public @NotNull ChunkStatus getStatus() {
return this.status;
}

public void setStatus(@NotNull ChunkStatus status) {
Check.argCondition(this.status.isOrAfter(status), "Can't switch chunk status from " + this.status + " to " + status);
this.status = status;
}

/**
Expand Down Expand Up @@ -106,7 +127,16 @@ public Chunk(@NotNull Instance instance, int chunkX, int chunkZ, boolean shouldG
* @param time the time of the update in milliseconds
*/
@Override
public abstract void tick(long time);
public void tick(long time) {
if (status.isOrAfter(ChunkStatus.LIGHTING)) {
final Instance instance = getInstance();
final InstanceLightManager lightManager = instance.getLightManager();
if (lightManager != null && !Cooldown.hasCooldown(time, lastLightUpdate, instance.getLightUpdate())) {
lastLightUpdate = time;
lightManager.runPendingTasks(this);
}
}
}

/**
* Gets the last time that this chunk changed.
Expand Down Expand Up @@ -299,4 +329,16 @@ public <T> void setTag(@NotNull Tag<T> tag, @Nullable T value) {
protected void unload() {
this.loaded = false;
}

@ApiStatus.Internal
public void setLightData(@NotNull ChunkLightData lightData) {
this.lightData = lightData;
}

public final @NotNull ChunkLightData getLightData() {
if (this.lightData == null) {
this.lightData = new ChunkLightData(this);
}
return this.lightData;
}
}
16 changes: 16 additions & 0 deletions src/main/java/net/minestom/server/instance/ChunkStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package net.minestom.server.instance;

import org.jetbrains.annotations.NotNull;

public enum ChunkStatus {
INITIALIZATION,
READING,
GENERATION,
POPULATION,
LIGHTING,
COMPLETE;

public boolean isOrAfter(@NotNull ChunkStatus status) {
return ordinal() >= status.ordinal();
}
}
62 changes: 38 additions & 24 deletions src/main/java/net/minestom/server/instance/DynamicChunk.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import net.minestom.server.entity.pathfinding.PFBlock;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.instance.light.ChunkLightData;
import net.minestom.server.instance.light.InstanceLightManager;
import net.minestom.server.network.packet.server.CachedPacket;
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
import net.minestom.server.network.packet.server.play.UpdateLightPacket;
Expand Down Expand Up @@ -53,7 +55,7 @@ public class DynamicChunk extends Chunk {

public DynamicChunk(@NotNull Instance instance, int chunkX, int chunkZ) {
super(instance, chunkX, chunkZ, true);
var sectionsTemp = new Section[maxSection - minSection];
var sectionsTemp = new Section[maxSection - minSection + 1];
Arrays.setAll(sectionsTemp, value -> new Section());
this.sections = List.of(sectionsTemp);
}
Expand Down Expand Up @@ -81,6 +83,11 @@ public void setBlock(int x, int y, int z, @NotNull Block block) {
} else {
this.entries.remove(index);
}
// Light
final InstanceLightManager lightManager = getInstance().getLightManager();
if (lightManager != null) {
lightManager.onBlockChange(this, x, y, z);
}
// Block tick
if (handler != null && handler.isTickable()) {
this.tickableMap.put(index, block);
Expand Down Expand Up @@ -111,15 +118,18 @@ public void setBiome(int x, int y, int z, @NotNull Biome biome) {

@Override
public void tick(long time) {
if (tickableMap.isEmpty()) return;
tickableMap.int2ObjectEntrySet().fastForEach(entry -> {
final int index = entry.getIntKey();
final Block block = entry.getValue();
final BlockHandler handler = block.handler();
if (handler == null) return;
final Point blockPosition = ChunkUtils.getBlockPosition(index, chunkX, chunkZ);
handler.tick(new BlockHandler.Tick(block, instance, blockPosition));
});
super.tick(time);
if (getStatus() == ChunkStatus.COMPLETE) {
if (tickableMap.isEmpty()) return;
tickableMap.int2ObjectEntrySet().fastForEach(entry -> {
final int index = entry.getIntKey();
final Block block = entry.getValue();
final BlockHandler handler = block.handler();
if (handler == null) return;
final Point blockPosition = ChunkUtils.getBlockPosition(index, chunkX, chunkZ);
handler.tick(new BlockHandler.Tick(block, instance, blockPosition));
});
}
}

@Override
Expand Down Expand Up @@ -169,14 +179,16 @@ public void sendChunk() {

@Override
public @NotNull Chunk copy(@NotNull Instance instance, int chunkX, int chunkZ) {
DynamicChunk dynamicChunk = new DynamicChunk(instance, chunkX, chunkZ);
final DynamicChunk dynamicChunk = new DynamicChunk(instance, chunkX, chunkZ);
dynamicChunk.setLightData(getLightData().copy(dynamicChunk));
dynamicChunk.sections = sections.stream().map(Section::clone).toList();
dynamicChunk.entries.putAll(entries);
return dynamicChunk;
}

@Override
public void reset() {
getLightData().clear();
for (Section section : sections) section.clear();
this.entries.clear();
}
Expand Down Expand Up @@ -220,22 +232,24 @@ private LightData createLightData() {
List<byte[]> skyLights = new ArrayList<>();
List<byte[]> blockLights = new ArrayList<>();

int index = 0;
for (Section section : sections) {
index++;
final byte[] skyLight = section.getSkyLight();
final byte[] blockLight = section.getBlockLight();
if (skyLight.length != 0) {
skyLights.add(skyLight);
skyMask.set(index);
final InstanceLightManager lightManager = getInstance().getLightManager();
final boolean hasSkyLight = lightManager != null && lightManager.hasSkyLight();
final boolean hasBlockLight = lightManager != null && lightManager.hasBlockLight();
final ChunkLightData lightData = getLightData();
for (int sectionY = getMinSection(), sectionIndex = 0; sectionY <= getMaxSection(); ++sectionY, ++sectionIndex) {
byte[] light = lightData.getSkyLight(sectionIndex);
if (hasSkyLight && light != null && light.length != 0) {
skyLights.add(light);
skyMask.set(sectionIndex);
} else {
emptySkyMask.set(index);
emptySkyMask.set(sectionIndex);
}
if (blockLight.length != 0) {
blockLights.add(blockLight);
blockMask.set(index);
light = lightData.getBlockLight(sectionIndex);
if (hasBlockLight && light != null && light.length != 0) {
blockLights.add(light);
blockMask.set(sectionIndex);
} else {
emptyBlockMask.set(index);
emptyBlockMask.set(sectionIndex);
}
}
return new LightData(true,
Expand Down
37 changes: 36 additions & 1 deletion src/main/java/net/minestom/server/instance/Instance.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import net.minestom.server.event.instance.InstanceTickEvent;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.instance.light.InstanceLightManager;
import net.minestom.server.network.packet.server.play.BlockActionPacket;
import net.minestom.server.network.packet.server.play.TimeUpdatePacket;
import net.minestom.server.snapshot.ChunkSnapshot;
Expand Down Expand Up @@ -99,6 +100,9 @@ public abstract class Instance implements Block.Getter, Block.Setter, Tickable,
// Adventure
private final Pointers pointers;

private InstanceLightManager lightManager;
private Duration lightUpdate = TimeUnit.SERVER_TICK.getDuration();

/**
* Creates a new instance.
*
Expand Down Expand Up @@ -141,6 +145,13 @@ public void scheduleNextTick(@NotNull Consumer<Instance> callback) {
@ApiStatus.Internal
public abstract boolean breakBlock(@NotNull Player player, @NotNull Point blockPosition);

protected abstract void cacheChunk(@NotNull Chunk chunk);

protected final void registerChunk(@NotNull Chunk chunk) {
cacheChunk(chunk);
MinecraftServer.process().dispatcher().createPartition(chunk);
}

/**
* Forces the generation of a {@link Chunk}, even if no file and {@link ChunkGenerator} are defined.
*
Expand Down Expand Up @@ -210,7 +221,11 @@ public void unloadChunk(int chunkX, int chunkZ) {
* @param chunkZ the chunk Z
* @return the chunk at the specified position, null if not loaded
*/
public abstract @Nullable Chunk getChunk(int chunkX, int chunkZ);
public @Nullable Chunk getChunk(int chunkX, int chunkZ) {
return getChunk(chunkX, chunkZ, ChunkStatus.COMPLETE);
}

public abstract @Nullable Chunk getChunk(int chunkX, int chunkZ, @NotNull ChunkStatus minStatus);

/**
* @param chunkX the chunk X
Expand Down Expand Up @@ -692,4 +707,24 @@ public void setExplosionSupplier(@Nullable ExplosionSupplier supplier) {
public @NotNull Pointers pointers() {
return this.pointers;
}

public final void setupLightManager(final boolean enableSkyLight, final boolean enableBlockLight) {
this.lightManager = new InstanceLightManager(this, enableSkyLight, enableBlockLight);
}

public final @Nullable InstanceLightManager getLightManager() {
return this.lightManager;
}

public final void setLightUpdate(@NotNull Duration lightUpdate) {
this.lightUpdate = lightUpdate;
}

final @NotNull Duration getLightUpdate() {
return this.lightUpdate;
}

public void onLightUpdate(final int chunkX, final int chunkZ, final int sectionIndex, final boolean skyLight) {

}
}
Loading