Use Hephaistos v2.4.0 to correctly handle world heights

Should fix https://github.com/Minestom/Minestom/issues/559
This commit is contained in:
jglrxavpok 2022-01-07 22:48:07 +01:00 committed by TheMode
parent c949bdd5ba
commit c46d7bf506
7 changed files with 77 additions and 13 deletions

View File

@ -1,5 +1,7 @@
package net.minestom.demo; package net.minestom.demo;
import demo.commands.GamemodeCommand;
import net.minestom.demo.commands.SaveCommand;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
@ -28,10 +30,14 @@ public class MainDemo {
GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler(); GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler();
globalEventHandler.addListener(PlayerLoginEvent.class, event -> { globalEventHandler.addListener(PlayerLoginEvent.class, event -> {
final Player player = event.getPlayer(); final Player player = event.getPlayer();
player.setPermissionLevel(2);
event.setSpawningInstance(instanceContainer); event.setSpawningInstance(instanceContainer);
player.setRespawnPoint(new Pos(0, 42, 0)); player.setRespawnPoint(new Pos(0, 42, 0));
}); });
MinecraftServer.getCommandManager().register(new SaveCommand());
MinecraftServer.getCommandManager().register(new GamemodeCommand());
// Start the server on port 25565 // Start the server on port 25565
minecraftServer.start("0.0.0.0", 25565); minecraftServer.start("0.0.0.0", 25565);
} }

View File

@ -0,0 +1,33 @@
package net.minestom.demo.commands;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.CommandContext;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
/**
* A simple shutdown command.
*/
public class SaveCommand extends Command {
public SaveCommand() {
super("save");
addSyntax(this::execute);
}
private void execute(@NotNull CommandSender commandSender, @NotNull CommandContext commandContext) {
for(var instance : MinecraftServer.getInstanceManager().getInstances()) {
CompletableFuture<Void> instanceSave = instance.saveInstance().thenCompose(v -> instance.saveChunksToStorage());
try {
instanceSave.get();
} catch (InterruptedException | ExecutionException e) {
MinecraftServer.getExceptionManager().handleException(e);
}
}
commandSender.sendMessage("Saving done!");
}
}

View File

@ -8,7 +8,7 @@ kotlin = "1.6.10"
hydrazine = "1.7.2" hydrazine = "1.7.2"
dependencyGetter = "v1.0.1" dependencyGetter = "v1.0.1"
minestomData = "801b8007cf" minestomData = "801b8007cf"
hephaistos = "2.3.2" hephaistos = "2.4.0"
jetbrainsAnnotations = "23.0.0" jetbrainsAnnotations = "23.0.0"
# Terminal / Logging # Terminal / Logging

View File

@ -80,7 +80,7 @@ public class AnvilLoader implements IChunkLoader {
} }
private @NotNull CompletableFuture<@Nullable Chunk> loadMCA(Instance instance, int chunkX, int chunkZ) throws IOException, AnvilException { private @NotNull CompletableFuture<@Nullable Chunk> loadMCA(Instance instance, int chunkX, int chunkZ) throws IOException, AnvilException {
final RegionFile mcaFile = getMCAFile(chunkX, chunkZ); final RegionFile mcaFile = getMCAFile(instance, chunkX, chunkZ);
if (mcaFile == null) if (mcaFile == null)
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
final ChunkColumn fileChunk = mcaFile.getChunk(chunkX, chunkZ); final ChunkColumn fileChunk = mcaFile.getChunk(chunkX, chunkZ);
@ -113,8 +113,9 @@ public class AnvilLoader implements IChunkLoader {
loadBlocks(chunk, fileChunk); loadBlocks(chunk, fileChunk);
loadTileEntities(chunk, fileChunk); loadTileEntities(chunk, fileChunk);
// Lights // Lights
for (var chunkSection : fileChunk.getSections().values()) { for (int sectionY = chunk.getMinSection(); sectionY < chunk.getMaxSection(); sectionY++) {
Section section = chunk.getSection(chunkSection.getY()); var section = chunk.getSection(sectionY);
var chunkSection = fileChunk.getSection((byte) sectionY);
section.setSkyLight(chunkSection.getSkyLights()); section.setSkyLight(chunkSection.getSkyLights());
section.setBlockLight(chunkSection.getBlockLights()); section.setBlockLight(chunkSection.getBlockLights());
} }
@ -122,7 +123,7 @@ public class AnvilLoader implements IChunkLoader {
return CompletableFuture.completedFuture(chunk); return CompletableFuture.completedFuture(chunk);
} }
private @Nullable RegionFile getMCAFile(int chunkX, int chunkZ) { private @Nullable RegionFile getMCAFile(Instance instance, int chunkX, int chunkZ) {
final int regionX = CoordinatesKt.chunkToRegion(chunkX); final int regionX = CoordinatesKt.chunkToRegion(chunkX);
final int regionZ = CoordinatesKt.chunkToRegion(chunkZ); final int regionZ = CoordinatesKt.chunkToRegion(chunkZ);
return alreadyLoaded.computeIfAbsent(RegionFile.Companion.createFileName(regionX, regionZ), n -> { return alreadyLoaded.computeIfAbsent(RegionFile.Companion.createFileName(regionX, regionZ), n -> {
@ -131,7 +132,7 @@ public class AnvilLoader implements IChunkLoader {
if (!Files.exists(regionPath)) { if (!Files.exists(regionPath)) {
return null; return null;
} }
return new RegionFile(new RandomAccessFile(regionPath.toFile(), "rw"), regionX, regionZ); return new RegionFile(new RandomAccessFile(regionPath.toFile(), "rw"), regionX, regionZ, instance.getDimensionType().getMinY(), instance.getDimensionType().getMaxY()-1);
} catch (IOException | AnvilException e) { } catch (IOException | AnvilException e) {
EXCEPTION_MANAGER.handleException(e); EXCEPTION_MANAGER.handleException(e);
return null; return null;
@ -219,7 +220,7 @@ public class AnvilLoader implements IChunkLoader {
final int chunkZ = chunk.getChunkZ(); final int chunkZ = chunk.getChunkZ();
RegionFile mcaFile; RegionFile mcaFile;
synchronized (alreadyLoaded) { synchronized (alreadyLoaded) {
mcaFile = getMCAFile(chunkX, chunkZ); mcaFile = getMCAFile(chunk.instance, chunkX, chunkZ);
if (mcaFile == null) { if (mcaFile == null) {
final int regionX = CoordinatesKt.chunkToRegion(chunkX); final int regionX = CoordinatesKt.chunkToRegion(chunkX);
final int regionZ = CoordinatesKt.chunkToRegion(chunkZ); final int regionZ = CoordinatesKt.chunkToRegion(chunkZ);
@ -263,15 +264,17 @@ public class AnvilLoader implements IChunkLoader {
} }
private void save(Chunk chunk, ChunkColumn chunkColumn) { private void save(Chunk chunk, ChunkColumn chunkColumn) {
chunkColumn.changeVersion(SupportedVersion.Companion.getLatest());
chunkColumn.setYRange(chunk.getMinSection()*16, chunk.getMaxSection()*16-1);
List<NBTCompound> tileEntities = new ArrayList<>(); List<NBTCompound> tileEntities = new ArrayList<>();
chunkColumn.setGenerationStatus(ChunkColumn.GenerationStatus.Full); chunkColumn.setGenerationStatus(ChunkColumn.GenerationStatus.Full);
for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) { for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) { for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
for (int y = 0; y < 256; y++) { // TODO don't hardcode world height for (int y = chunkColumn.getMinY(); y < chunkColumn.getMaxY(); y++) {
final Block block = chunk.getBlock(x, y, z); final Block block = chunk.getBlock(x, y, z);
// Block // Block
chunkColumn.setBlockState(x, y, z, new BlockState(block.name(), block.properties())); chunkColumn.setBlockState(x, y, z, new BlockState(block.name(), block.properties()));
chunkColumn.setBiome(x, 0, z, chunk.getBiome(x, y, z).name().asString()); chunkColumn.setBiome(x, y, z, chunk.getBiome(x, y, z).name().asString());
// Tile entity // Tile entity
final BlockHandler handler = block.handler(); final BlockHandler handler = block.handler();

View File

@ -44,6 +44,7 @@ public abstract class Chunk implements Block.Getter, Block.Setter, Biome.Getter,
protected Instance instance; protected Instance instance;
protected final int chunkX, chunkZ; protected final int chunkX, chunkZ;
protected final int minSection, maxSection;
// Options // Options
private final boolean shouldGenerate; private final boolean shouldGenerate;
@ -64,6 +65,8 @@ public abstract class Chunk implements Block.Getter, Block.Setter, Biome.Getter,
this.chunkX = chunkX; this.chunkX = chunkX;
this.chunkZ = chunkZ; this.chunkZ = chunkZ;
this.shouldGenerate = shouldGenerate; this.shouldGenerate = shouldGenerate;
this.minSection = instance.getDimensionType().getMinY() / CHUNK_SECTION_SIZE;
this.maxSection = (instance.getDimensionType().getMinY() + instance.getDimensionType().getHeight()) / CHUNK_SECTION_SIZE;
final EntityTracker tracker = instance.getEntityTracker(); final EntityTracker tracker = instance.getEntityTracker();
this.viewers.updateTracker(toPosition(), tracker); this.viewers.updateTracker(toPosition(), tracker);
@ -181,6 +184,24 @@ public abstract class Chunk implements Block.Getter, Block.Setter, Biome.Getter,
return chunkZ; return chunkZ;
} }
/**
* Gets the lowest (inclusive) section Y available in this chunk
*
* @return the lowest (inclusive) section Y available in this chunk
*/
public int getMinSection() {
return minSection;
}
/**
* Gets the highest (exclusive) section Y available in this chunk
*
* @return the highest (exclusive) section Y available in this chunk
*/
public int getMaxSection() {
return maxSection;
}
/** /**
* Gets the world position of this chunk. * Gets the world position of this chunk.
* *

View File

@ -36,7 +36,6 @@ import static net.minestom.server.utils.chunk.ChunkUtils.toSectionRelativeCoordi
*/ */
public class DynamicChunk extends Chunk { public class DynamicChunk extends Chunk {
private final int minSection, maxSection;
private List<Section> sections; private List<Section> sections;
// Key = ChunkUtils#getBlockIndex // Key = ChunkUtils#getBlockIndex
@ -49,8 +48,6 @@ public class DynamicChunk extends Chunk {
public DynamicChunk(@NotNull Instance instance, int chunkX, int chunkZ) { public DynamicChunk(@NotNull Instance instance, int chunkX, int chunkZ) {
super(instance, chunkX, chunkZ, true); super(instance, chunkX, chunkZ, true);
this.minSection = instance.getDimensionType().getMinY() / CHUNK_SECTION_SIZE;
this.maxSection = (instance.getDimensionType().getMinY() + instance.getDimensionType().getHeight()) / CHUNK_SECTION_SIZE;
var sectionsTemp = new Section[maxSection - minSection]; var sectionsTemp = new Section[maxSection - minSection];
Arrays.setAll(sectionsTemp, value -> new Section()); Arrays.setAll(sectionsTemp, value -> new Section());
this.sections = List.of(sectionsTemp); this.sections = List.of(sectionsTemp);
@ -144,7 +141,7 @@ public class DynamicChunk extends Chunk {
public @NotNull Biome getBiome(int x, int y, int z) { public @NotNull Biome getBiome(int x, int y, int z) {
final Section section = getSectionAt(y); final Section section = getSectionAt(y);
final int id = section.biomePalette() final int id = section.biomePalette()
.get(toSectionRelativeCoordinate(x) / 4, y / 4, toSectionRelativeCoordinate(z) / 4); .get(toSectionRelativeCoordinate(x) / 4, toSectionRelativeCoordinate(y) / 4, toSectionRelativeCoordinate(z) / 4);
return MinecraftServer.getBiomeManager().getById(id); return MinecraftServer.getBiomeManager().getById(id);
} }

View File

@ -209,6 +209,10 @@ public class DimensionType {
return height; return height;
} }
public int getMaxY() {
return getMinY() + getHeight();
}
public int getLogicalHeight() { public int getLogicalHeight() {
return this.logicalHeight; return this.logicalHeight;
} }