From fdd3e2c53c65593c446588d15ff2759a79a35d6b Mon Sep 17 00:00:00 2001 From: TheMode Date: Wed, 4 May 2022 13:25:24 +0200 Subject: [PATCH] Seal snapshot interfaces Signed-off-by: TheMode --- .../minestom/server/ServerProcessImpl.java | 23 +- .../net/minestom/server/entity/Entity.java | 3 +- .../server/entity/EntitySnapshotImpl.java | 116 ---------- .../net/minestom/server/entity/Player.java | 4 +- .../server/instance/DynamicChunk.java | 3 +- .../minestom/server/instance/Instance.java | 7 +- .../server/instance/InstanceSnapshotImpl.java | 107 --------- .../server/snapshot/ChunkSnapshot.java | 3 +- .../server/snapshot/EntitySnapshot.java | 3 +- .../server/snapshot/InstanceSnapshot.java | 3 +- .../server/snapshot/PlayerSnapshot.java | 3 +- .../server/snapshot/ServerSnapshot.java | 3 +- .../server/snapshot/SnapshotImpl.java | 218 ++++++++++++++++++ 13 files changed, 238 insertions(+), 258 deletions(-) delete mode 100644 src/main/java/net/minestom/server/entity/EntitySnapshotImpl.java delete mode 100644 src/main/java/net/minestom/server/instance/InstanceSnapshotImpl.java create mode 100644 src/main/java/net/minestom/server/snapshot/SnapshotImpl.java diff --git a/src/main/java/net/minestom/server/ServerProcessImpl.java b/src/main/java/net/minestom/server/ServerProcessImpl.java index b471db108..91379c82f 100644 --- a/src/main/java/net/minestom/server/ServerProcessImpl.java +++ b/src/main/java/net/minestom/server/ServerProcessImpl.java @@ -23,10 +23,7 @@ import net.minestom.server.network.PacketProcessor; import net.minestom.server.network.socket.Server; import net.minestom.server.recipe.RecipeManager; import net.minestom.server.scoreboard.TeamManager; -import net.minestom.server.snapshot.EntitySnapshot; -import net.minestom.server.snapshot.InstanceSnapshot; -import net.minestom.server.snapshot.ServerSnapshot; -import net.minestom.server.snapshot.SnapshotUpdater; +import net.minestom.server.snapshot.*; import net.minestom.server.terminal.MinestomTerminal; import net.minestom.server.thread.Acquirable; import net.minestom.server.thread.ThreadDispatcher; @@ -36,14 +33,12 @@ import net.minestom.server.utils.collection.MappedCollection; import net.minestom.server.world.DimensionTypeManager; import net.minestom.server.world.biomes.BiomeManager; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.UnknownNullability; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.SocketAddress; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -274,21 +269,7 @@ final class ServerProcessImpl implements ServerProcess { entityRefs.put(entity.getEntityId(), updater.reference(entity)); } } - return new SnapshotImpl(MappedCollection.plainReferences(instanceRefs), entityRefs); - } - - record SnapshotImpl(Collection instances, - Int2ObjectOpenHashMap> entityRefs) implements ServerSnapshot { - @Override - public @NotNull Collection entities() { - return MappedCollection.plainReferences(entityRefs.values()); - } - - @Override - public @UnknownNullability EntitySnapshot entity(int id) { - var ref = entityRefs.get(id); - return ref != null ? ref.getPlain() : null; - } + return new SnapshotImpl.Server(MappedCollection.plainReferences(instanceRefs), entityRefs); } private final class TickerImpl implements Ticker { diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index defc4c21b..80ca9b4fc 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -41,6 +41,7 @@ import net.minestom.server.potion.Potion; import net.minestom.server.potion.PotionEffect; import net.minestom.server.potion.TimedPotion; import net.minestom.server.snapshot.EntitySnapshot; +import net.minestom.server.snapshot.SnapshotImpl; import net.minestom.server.snapshot.SnapshotUpdater; import net.minestom.server.snapshot.Snapshotable; import net.minestom.server.tag.TagHandler; @@ -1588,7 +1589,7 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev final int[] viewersId = this.viewEngine.viewableOption.bitSet.toIntArray(); final int[] passengersId = ArrayUtils.mapToIntArray(passengers, Entity::getEntityId); final Entity vehicle = this.vehicle; - return new EntitySnapshotImpl.Entity(entityType, uuid, id, position, velocity, + return new SnapshotImpl.Entity(entityType, uuid, id, position, velocity, updater.reference(instance), chunk.getChunkX(), chunk.getChunkZ(), viewersId, passengersId, vehicle == null ? -1 : vehicle.getEntityId(), tagHandler.readableCopy()); diff --git a/src/main/java/net/minestom/server/entity/EntitySnapshotImpl.java b/src/main/java/net/minestom/server/entity/EntitySnapshotImpl.java deleted file mode 100644 index 6203a7ae4..000000000 --- a/src/main/java/net/minestom/server/entity/EntitySnapshotImpl.java +++ /dev/null @@ -1,116 +0,0 @@ -package net.minestom.server.entity; - -import net.minestom.server.coordinate.Pos; -import net.minestom.server.coordinate.Vec; -import net.minestom.server.snapshot.ChunkSnapshot; -import net.minestom.server.snapshot.EntitySnapshot; -import net.minestom.server.snapshot.InstanceSnapshot; -import net.minestom.server.snapshot.PlayerSnapshot; -import net.minestom.server.tag.Tag; -import net.minestom.server.tag.TagReadable; -import net.minestom.server.utils.collection.IntMappedArray; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.UnknownNullability; - -import java.util.Collection; -import java.util.Objects; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicReference; - -final class EntitySnapshotImpl { - - record Entity(EntityType type, UUID uuid, int id, Pos position, Vec velocity, - AtomicReference instanceRef, int chunkX, int chunkZ, - int[] viewersId, int[] passengersId, int vehicleId, - TagReadable tagReadable) implements EntitySnapshot { - @Override - public @UnknownNullability T getTag(@NotNull Tag tag) { - return tagReadable.getTag(tag); - } - - @Override - public @NotNull InstanceSnapshot instance() { - return instanceRef.getPlain(); - } - - @Override - public @NotNull ChunkSnapshot chunk() { - return Objects.requireNonNull(instance().chunk(chunkX, chunkZ)); - } - - @Override - public @NotNull Collection<@NotNull PlayerSnapshot> viewers() { - return new IntMappedArray<>(viewersId, id -> (PlayerSnapshot) instance().server().entity(id)); - } - - @Override - public @NotNull Collection<@NotNull EntitySnapshot> passengers() { - return new IntMappedArray<>(passengersId, id -> instance().server().entity(id)); - } - - @Override - public @Nullable EntitySnapshot vehicle() { - if (vehicleId == -1) return null; - return instance().server().entity(vehicleId); - } - } - - record Player(EntitySnapshot snapshot, String username, - GameMode gameMode) implements PlayerSnapshot { - @Override - public @NotNull EntityType type() { - return snapshot.type(); - } - - @Override - public @NotNull UUID uuid() { - return snapshot.uuid(); - } - - @Override - public int id() { - return snapshot.id(); - } - - @Override - public @NotNull Pos position() { - return snapshot.position(); - } - - @Override - public @NotNull Vec velocity() { - return snapshot.velocity(); - } - - @Override - public @NotNull InstanceSnapshot instance() { - return snapshot.instance(); - } - - @Override - public @NotNull ChunkSnapshot chunk() { - return snapshot.chunk(); - } - - @Override - public @NotNull Collection<@NotNull PlayerSnapshot> viewers() { - return snapshot.viewers(); - } - - @Override - public @NotNull Collection<@NotNull EntitySnapshot> passengers() { - return snapshot.passengers(); - } - - @Override - public @Nullable EntitySnapshot vehicle() { - return snapshot.vehicle(); - } - - @Override - public @UnknownNullability T getTag(@NotNull Tag tag) { - return snapshot.getTag(tag); - } - } -} diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 754bb6539..bb1b94e3c 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -20,7 +20,6 @@ import net.minestom.server.adventure.AdventurePacketConvertor; import net.minestom.server.adventure.Localizable; import net.minestom.server.adventure.audience.Audiences; import net.minestom.server.attribute.Attribute; -import net.minestom.server.collision.BoundingBox; import net.minestom.server.command.CommandManager; import net.minestom.server.command.CommandSender; import net.minestom.server.coordinate.Point; @@ -67,6 +66,7 @@ import net.minestom.server.scoreboard.BelowNameTag; import net.minestom.server.scoreboard.Team; import net.minestom.server.snapshot.EntitySnapshot; import net.minestom.server.snapshot.PlayerSnapshot; +import net.minestom.server.snapshot.SnapshotImpl; import net.minestom.server.snapshot.SnapshotUpdater; import net.minestom.server.statistic.PlayerStatistic; import net.minestom.server.timer.Scheduler; @@ -1988,7 +1988,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, @Override public @NotNull PlayerSnapshot updateSnapshot(@NotNull SnapshotUpdater updater) { final EntitySnapshot snapshot = super.updateSnapshot(updater); - return new EntitySnapshotImpl.Player(snapshot, username, gameMode); + return new SnapshotImpl.Player(snapshot, username, gameMode); } /** diff --git a/src/main/java/net/minestom/server/instance/DynamicChunk.java b/src/main/java/net/minestom/server/instance/DynamicChunk.java index 8b17d1119..1c7aa8677 100644 --- a/src/main/java/net/minestom/server/instance/DynamicChunk.java +++ b/src/main/java/net/minestom/server/instance/DynamicChunk.java @@ -15,6 +15,7 @@ import net.minestom.server.network.packet.server.play.UpdateLightPacket; import net.minestom.server.network.packet.server.play.data.ChunkData; import net.minestom.server.network.packet.server.play.data.LightData; import net.minestom.server.snapshot.ChunkSnapshot; +import net.minestom.server.snapshot.SnapshotImpl; import net.minestom.server.snapshot.SnapshotUpdater; import net.minestom.server.utils.ArrayUtils; import net.minestom.server.utils.MathUtils; @@ -253,7 +254,7 @@ public class DynamicChunk extends Chunk { clonedSections[i] = sections.get(i).clone(); var entities = instance.getEntityTracker().chunkEntities(chunkX, chunkZ, EntityTracker.Target.ENTITIES); final int[] entityIds = ArrayUtils.mapToIntArray(entities, Entity::getEntityId); - return new InstanceSnapshotImpl.Chunk(minSection, chunkX, chunkZ, + return new SnapshotImpl.Chunk(minSection, chunkX, chunkZ, clonedSections, entries.clone(), entityIds, updater.reference(instance), tagHandler().readableCopy()); } diff --git a/src/main/java/net/minestom/server/instance/Instance.java b/src/main/java/net/minestom/server/instance/Instance.java index 798a49837..090a88b77 100644 --- a/src/main/java/net/minestom/server/instance/Instance.java +++ b/src/main/java/net/minestom/server/instance/Instance.java @@ -24,10 +24,7 @@ import net.minestom.server.instance.block.BlockHandler; import net.minestom.server.instance.generator.Generator; import net.minestom.server.network.packet.server.play.BlockActionPacket; import net.minestom.server.network.packet.server.play.TimeUpdatePacket; -import net.minestom.server.snapshot.ChunkSnapshot; -import net.minestom.server.snapshot.InstanceSnapshot; -import net.minestom.server.snapshot.SnapshotUpdater; -import net.minestom.server.snapshot.Snapshotable; +import net.minestom.server.snapshot.*; import net.minestom.server.tag.TagHandler; import net.minestom.server.tag.Taggable; import net.minestom.server.thread.ThreadDispatcher; @@ -641,7 +638,7 @@ public abstract class Instance implements Block.Getter, Block.Setter, public @NotNull InstanceSnapshot updateSnapshot(@NotNull SnapshotUpdater updater) { final Map> chunksMap = updater.referencesMapLong(getChunks(), ChunkUtils::getChunkIndex); final int[] entities = ArrayUtils.mapToIntArray(entityTracker.entities(), Entity::getEntityId); - return new InstanceSnapshotImpl.Instance(updater.reference(MinecraftServer.process()), + return new SnapshotImpl.Instance(updater.reference(MinecraftServer.process()), getDimensionType(), getWorldAge(), getTime(), chunksMap, entities, tagHandler.readableCopy()); } diff --git a/src/main/java/net/minestom/server/instance/InstanceSnapshotImpl.java b/src/main/java/net/minestom/server/instance/InstanceSnapshotImpl.java deleted file mode 100644 index 3d66c6973..000000000 --- a/src/main/java/net/minestom/server/instance/InstanceSnapshotImpl.java +++ /dev/null @@ -1,107 +0,0 @@ -package net.minestom.server.instance; - -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import net.minestom.server.MinecraftServer; -import net.minestom.server.instance.block.Block; -import net.minestom.server.snapshot.ChunkSnapshot; -import net.minestom.server.snapshot.EntitySnapshot; -import net.minestom.server.snapshot.InstanceSnapshot; -import net.minestom.server.snapshot.ServerSnapshot; -import net.minestom.server.tag.Tag; -import net.minestom.server.tag.TagReadable; -import net.minestom.server.utils.collection.IntMappedArray; -import net.minestom.server.utils.collection.MappedCollection; -import net.minestom.server.world.DimensionType; -import net.minestom.server.world.biomes.Biome; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.UnknownNullability; - -import java.util.Collection; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicReference; - -import static net.minestom.server.utils.chunk.ChunkUtils.*; - -final class InstanceSnapshotImpl { - - record Instance(AtomicReference serverRef, - DimensionType dimensionType, long worldAge, long time, - Map> chunksMap, - int[] entitiesIds, - TagReadable tagReadable) implements InstanceSnapshot { - @Override - public @Nullable ChunkSnapshot chunk(int chunkX, int chunkZ) { - var ref = chunksMap.get(getChunkIndex(chunkX, chunkZ)); - return Objects.requireNonNull(ref, "Chunk not found").getPlain(); - } - - @Override - public @NotNull Collection<@NotNull ChunkSnapshot> chunks() { - return MappedCollection.plainReferences(chunksMap.values()); - } - - @Override - public @NotNull Collection entities() { - return new IntMappedArray<>(entitiesIds, id -> server().entity(id)); - } - - @Override - public @NotNull ServerSnapshot server() { - return serverRef.getPlain(); - } - - @Override - public @UnknownNullability T getTag(@NotNull Tag tag) { - return tagReadable.getTag(tag); - } - } - - record Chunk(int minSection, int chunkX, int chunkZ, - Section[] sections, - Int2ObjectOpenHashMap blockEntries, - int[] entitiesIds, - AtomicReference instanceRef, - TagReadable tagReadable) implements ChunkSnapshot { - @Override - public @UnknownNullability Block getBlock(int x, int y, int z, @NotNull Condition condition) { - // Verify if the block object is present - if (condition != Condition.TYPE) { - final Block entry = !blockEntries.isEmpty() ? - blockEntries.get(getBlockIndex(x, y, z)) : null; - if (entry != null || condition == Condition.CACHED) { - return entry; - } - } - // Retrieve the block from state id - final Section section = sections[getChunkCoordinate(y) - minSection]; - final int blockStateId = section.blockPalette() - .get(toSectionRelativeCoordinate(x), toSectionRelativeCoordinate(y), toSectionRelativeCoordinate(z)); - return Objects.requireNonNullElse(Block.fromStateId((short) blockStateId), Block.AIR); - } - - @Override - public @NotNull Biome getBiome(int x, int y, int z) { - final Section section = sections[getChunkCoordinate(y) - minSection]; - final int id = section.biomePalette() - .get(toSectionRelativeCoordinate(x) / 4, toSectionRelativeCoordinate(y) / 4, toSectionRelativeCoordinate(z) / 4); - return MinecraftServer.getBiomeManager().getById(id); - } - - @Override - public @UnknownNullability T getTag(@NotNull Tag tag) { - return tagReadable.getTag(tag); - } - - @Override - public @NotNull InstanceSnapshot instance() { - return instanceRef.getPlain(); - } - - @Override - public @NotNull Collection<@NotNull EntitySnapshot> entities() { - return new IntMappedArray<>(entitiesIds, id -> instance().server().entity(id)); - } - } -} diff --git a/src/main/java/net/minestom/server/snapshot/ChunkSnapshot.java b/src/main/java/net/minestom/server/snapshot/ChunkSnapshot.java index bc058de3c..d3b933a1d 100644 --- a/src/main/java/net/minestom/server/snapshot/ChunkSnapshot.java +++ b/src/main/java/net/minestom/server/snapshot/ChunkSnapshot.java @@ -7,7 +7,8 @@ import org.jetbrains.annotations.NotNull; import java.util.Collection; -public interface ChunkSnapshot extends Snapshot, Block.Getter, Biome.Getter, TagReadable { +public sealed interface ChunkSnapshot extends Snapshot, Block.Getter, Biome.Getter, TagReadable + permits SnapshotImpl.Chunk { int chunkX(); int chunkZ(); diff --git a/src/main/java/net/minestom/server/snapshot/EntitySnapshot.java b/src/main/java/net/minestom/server/snapshot/EntitySnapshot.java index d7a98ffc9..7d8a9c810 100644 --- a/src/main/java/net/minestom/server/snapshot/EntitySnapshot.java +++ b/src/main/java/net/minestom/server/snapshot/EntitySnapshot.java @@ -10,7 +10,8 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.UUID; -public interface EntitySnapshot extends Snapshot, TagReadable { +public sealed interface EntitySnapshot extends Snapshot, TagReadable + permits PlayerSnapshot, SnapshotImpl.Entity { @NotNull EntityType type(); @NotNull UUID uuid(); diff --git a/src/main/java/net/minestom/server/snapshot/InstanceSnapshot.java b/src/main/java/net/minestom/server/snapshot/InstanceSnapshot.java index 8b8e2b4de..16b770d6e 100644 --- a/src/main/java/net/minestom/server/snapshot/InstanceSnapshot.java +++ b/src/main/java/net/minestom/server/snapshot/InstanceSnapshot.java @@ -14,7 +14,8 @@ import java.util.Objects; import static net.minestom.server.utils.chunk.ChunkUtils.getChunkCoordinate; -public interface InstanceSnapshot extends Snapshot, Block.Getter, Biome.Getter, TagReadable { +public sealed interface InstanceSnapshot extends Snapshot, Block.Getter, Biome.Getter, TagReadable + permits SnapshotImpl.Instance { @NotNull DimensionType dimensionType(); long worldAge(); diff --git a/src/main/java/net/minestom/server/snapshot/PlayerSnapshot.java b/src/main/java/net/minestom/server/snapshot/PlayerSnapshot.java index 5ac1b20b2..edf0f325d 100644 --- a/src/main/java/net/minestom/server/snapshot/PlayerSnapshot.java +++ b/src/main/java/net/minestom/server/snapshot/PlayerSnapshot.java @@ -3,7 +3,8 @@ package net.minestom.server.snapshot; import net.minestom.server.entity.GameMode; import org.jetbrains.annotations.NotNull; -public interface PlayerSnapshot extends EntitySnapshot { +public sealed interface PlayerSnapshot extends EntitySnapshot + permits SnapshotImpl.Player { @NotNull String username(); @NotNull GameMode gameMode(); diff --git a/src/main/java/net/minestom/server/snapshot/ServerSnapshot.java b/src/main/java/net/minestom/server/snapshot/ServerSnapshot.java index 6b402b19b..3c1dac2ce 100644 --- a/src/main/java/net/minestom/server/snapshot/ServerSnapshot.java +++ b/src/main/java/net/minestom/server/snapshot/ServerSnapshot.java @@ -12,7 +12,8 @@ import java.util.Collection; /** * Represents the complete state of the server at a given moment. */ -public interface ServerSnapshot extends Snapshot { +public sealed interface ServerSnapshot extends Snapshot + permits SnapshotImpl.Server { @NotNull Collection<@NotNull InstanceSnapshot> instances(); @NotNull Collection entities(); diff --git a/src/main/java/net/minestom/server/snapshot/SnapshotImpl.java b/src/main/java/net/minestom/server/snapshot/SnapshotImpl.java new file mode 100644 index 000000000..9d1e01ea8 --- /dev/null +++ b/src/main/java/net/minestom/server/snapshot/SnapshotImpl.java @@ -0,0 +1,218 @@ +package net.minestom.server.snapshot; + +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.minestom.server.MinecraftServer; +import net.minestom.server.coordinate.Pos; +import net.minestom.server.coordinate.Vec; +import net.minestom.server.entity.EntityType; +import net.minestom.server.entity.GameMode; +import net.minestom.server.instance.Section; +import net.minestom.server.instance.block.Block; +import net.minestom.server.tag.Tag; +import net.minestom.server.tag.TagReadable; +import net.minestom.server.utils.collection.IntMappedArray; +import net.minestom.server.utils.collection.MappedCollection; +import net.minestom.server.world.DimensionType; +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; + +import java.util.Collection; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; + +import static net.minestom.server.utils.chunk.ChunkUtils.*; + +@ApiStatus.Internal +public final class SnapshotImpl { + public record Server(Collection instances, + Int2ObjectOpenHashMap> entityRefs) implements ServerSnapshot { + @Override + public @NotNull Collection entities() { + return MappedCollection.plainReferences(entityRefs.values()); + } + + @Override + public @UnknownNullability EntitySnapshot entity(int id) { + var ref = entityRefs.get(id); + return ref != null ? ref.getPlain() : null; + } + } + + public record Instance(AtomicReference serverRef, + DimensionType dimensionType, long worldAge, long time, + Map> chunksMap, + int[] entitiesIds, + TagReadable tagReadable) implements InstanceSnapshot { + @Override + public @Nullable ChunkSnapshot chunk(int chunkX, int chunkZ) { + var ref = chunksMap.get(getChunkIndex(chunkX, chunkZ)); + return Objects.requireNonNull(ref, "Chunk not found").getPlain(); + } + + @Override + public @NotNull Collection<@NotNull ChunkSnapshot> chunks() { + return MappedCollection.plainReferences(chunksMap.values()); + } + + @Override + public @NotNull Collection entities() { + return new IntMappedArray<>(entitiesIds, id -> server().entity(id)); + } + + @Override + public @NotNull ServerSnapshot server() { + return serverRef.getPlain(); + } + + @Override + public @UnknownNullability T getTag(@NotNull Tag tag) { + return tagReadable.getTag(tag); + } + } + + public record Chunk(int minSection, int chunkX, int chunkZ, + Section[] sections, + Int2ObjectOpenHashMap blockEntries, + int[] entitiesIds, + AtomicReference instanceRef, + TagReadable tagReadable) implements ChunkSnapshot { + @Override + public @UnknownNullability Block getBlock(int x, int y, int z, @NotNull Condition condition) { + // Verify if the block object is present + if (condition != Condition.TYPE) { + final Block entry = !blockEntries.isEmpty() ? + blockEntries.get(getBlockIndex(x, y, z)) : null; + if (entry != null || condition == Condition.CACHED) { + return entry; + } + } + // Retrieve the block from state id + final Section section = sections[getChunkCoordinate(y) - minSection]; + final int blockStateId = section.blockPalette() + .get(toSectionRelativeCoordinate(x), toSectionRelativeCoordinate(y), toSectionRelativeCoordinate(z)); + return Objects.requireNonNullElse(Block.fromStateId((short) blockStateId), Block.AIR); + } + + @Override + public @NotNull Biome getBiome(int x, int y, int z) { + final Section section = sections[getChunkCoordinate(y) - minSection]; + final int id = section.biomePalette() + .get(toSectionRelativeCoordinate(x) / 4, toSectionRelativeCoordinate(y) / 4, toSectionRelativeCoordinate(z) / 4); + return MinecraftServer.getBiomeManager().getById(id); + } + + @Override + public @UnknownNullability T getTag(@NotNull Tag tag) { + return tagReadable.getTag(tag); + } + + @Override + public @NotNull InstanceSnapshot instance() { + return instanceRef.getPlain(); + } + + @Override + public @NotNull Collection<@NotNull EntitySnapshot> entities() { + return new IntMappedArray<>(entitiesIds, id -> instance().server().entity(id)); + } + } + + public record Entity(EntityType type, UUID uuid, int id, Pos position, Vec velocity, + AtomicReference instanceRef, int chunkX, int chunkZ, + int[] viewersId, int[] passengersId, int vehicleId, + TagReadable tagReadable) implements EntitySnapshot { + @Override + public @UnknownNullability T getTag(@NotNull Tag tag) { + return tagReadable.getTag(tag); + } + + @Override + public @NotNull InstanceSnapshot instance() { + return instanceRef.getPlain(); + } + + @Override + public @NotNull ChunkSnapshot chunk() { + return Objects.requireNonNull(instance().chunk(chunkX, chunkZ)); + } + + @Override + public @NotNull Collection<@NotNull PlayerSnapshot> viewers() { + return new IntMappedArray<>(viewersId, id -> (PlayerSnapshot) instance().server().entity(id)); + } + + @Override + public @NotNull Collection<@NotNull EntitySnapshot> passengers() { + return new IntMappedArray<>(passengersId, id -> instance().server().entity(id)); + } + + @Override + public @Nullable EntitySnapshot vehicle() { + if (vehicleId == -1) return null; + return instance().server().entity(vehicleId); + } + } + + public record Player(EntitySnapshot snapshot, String username, + GameMode gameMode) implements PlayerSnapshot { + @Override + public @NotNull EntityType type() { + return snapshot.type(); + } + + @Override + public @NotNull UUID uuid() { + return snapshot.uuid(); + } + + @Override + public int id() { + return snapshot.id(); + } + + @Override + public @NotNull Pos position() { + return snapshot.position(); + } + + @Override + public @NotNull Vec velocity() { + return snapshot.velocity(); + } + + @Override + public @NotNull InstanceSnapshot instance() { + return snapshot.instance(); + } + + @Override + public @NotNull ChunkSnapshot chunk() { + return snapshot.chunk(); + } + + @Override + public @NotNull Collection<@NotNull PlayerSnapshot> viewers() { + return snapshot.viewers(); + } + + @Override + public @NotNull Collection<@NotNull EntitySnapshot> passengers() { + return snapshot.passengers(); + } + + @Override + public @Nullable EntitySnapshot vehicle() { + return snapshot.vehicle(); + } + + @Override + public @UnknownNullability T getTag(@NotNull Tag tag) { + return snapshot.getTag(tag); + } + } +}