use of org.lanternpowered.server.data.persistence.nbt.NbtDataContainerOutputStream in project LanternServer by LanternPowered.
the class AnvilChunkIOService method write.
@Override
public void write(LanternChunk chunk) throws IOException {
final int x = chunk.getX();
final int z = chunk.getZ();
final RegionFile region = this.cache.getRegionFileByChunk(x, z);
final int regionX = x & REGION_MASK;
final int regionZ = z & REGION_MASK;
final DataContainer rootView = DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED);
final DataView levelDataView = rootView.createView(LEVEL);
// Core properties
levelDataView.set(VERSION, (byte) 1);
levelDataView.set(X, chunk.getX());
levelDataView.set(Z, chunk.getZ());
levelDataView.set(TERRAIN_POPULATED, (byte) (chunk.isPopulated() ? 1 : 0));
levelDataView.set(LIGHT_POPULATED, (byte) (chunk.isLightPopulated() ? 1 : 0));
levelDataView.set(LAST_UPDATE, 0L);
levelDataView.set(INHABITED_TIME, chunk.getLongInhabitedTime());
// Chunk sections
final ChunkSectionSnapshot[] sections = chunk.getSectionSnapshots(true);
final List<DataView> sectionDataViews = new ArrayList<>();
final List<DataView> tileEntityDataViews = new ArrayList<>();
for (byte i = 0; i < sections.length; ++i) {
final ChunkSectionSnapshot section = sections[i];
if (section == null) {
continue;
}
final DataContainer sectionDataView = DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED);
sectionDataView.set(Y, i);
final byte[] rawTypes = new byte[section.types.length];
final short[] types = section.types;
NibbleArray extTypes = null;
final NibbleArray data = new NibbleArray(rawTypes.length);
for (int j = 0; j < rawTypes.length; j++) {
rawTypes[j] = (byte) ((types[j] >> 4) & 0xff);
byte extType = (byte) (types[j] >> 12);
if (extType != 0) {
if (extTypes == null) {
extTypes = new NibbleArray(rawTypes.length);
}
extTypes.set(j, extType);
}
data.set(j, (byte) (types[j] & 0xf));
}
sectionDataView.set(BLOCKS, rawTypes);
if (extTypes != null) {
sectionDataView.set(BLOCKS_EXTRA, extTypes.getPackedArray());
}
sectionDataView.set(DATA, data.getPackedArray());
sectionDataView.set(BLOCK_LIGHT, section.lightFromBlock);
final byte[] lightFromSky = section.lightFromSky;
if (lightFromSky != null) {
sectionDataView.set(SKY_LIGHT, lightFromSky);
}
sectionDataViews.add(sectionDataView);
// noinspection unchecked
final ObjectSerializer<LanternTileEntity> tileEntitySerializer = ObjectSerializerRegistry.get().get(LanternTileEntity.class).get();
// Serialize the tile entities
for (Short2ObjectMap.Entry<LanternTileEntity> tileEntityEntry : section.tileEntities.short2ObjectEntrySet()) {
if (!tileEntityEntry.getValue().isValid()) {
continue;
}
final DataView dataView = tileEntitySerializer.serialize(tileEntityEntry.getValue());
final short pos = tileEntityEntry.getShortKey();
dataView.set(TILE_ENTITY_X, x * 16 + (pos & 0xf));
dataView.set(TILE_ENTITY_Y, (i << 4) | (pos >> 8));
dataView.set(TILE_ENTITY_Z, z * 16 + ((pos >> 4) & 0xf));
tileEntityDataViews.add(dataView);
}
}
levelDataView.set(TILE_ENTITIES, tileEntityDataViews);
levelDataView.set(SECTIONS, sectionDataViews);
levelDataView.set(HEIGHT_MAP, chunk.getHeightMap());
// noinspection unchecked
final Short2ObjectMap<LanternChunk.TrackerData>[] trackerData = chunk.getTrackerData().getRawObjects();
final List<DataView> trackerDataViews = new ArrayList<>();
for (int i = 0; i < trackerData.length; i++) {
final Short2ObjectMap<LanternChunk.TrackerData> trackerDataSection = trackerData[i];
for (Short2ObjectMap.Entry<LanternChunk.TrackerData> entry : trackerDataSection.short2ObjectEntrySet()) {
// index = y << 8 | z << 4 | x
int index = entry.getShortKey() & 0xffff;
// Convert the index to the column based system
// index = z << 12 | y << 4 | x
index = ((index >> 4) & 0xf) << 12 | i << 8 | (index >> 4) & 0xf0 | index & 0xf;
final DataView trackerDataView = DataContainer.createNew(DataView.SafetyMode.NO_DATA_CLONED);
trackerDataView.set(TRACKER_BLOCK_POS, (short) index);
trackerDataView.set(TRACKER_ENTRY_NOTIFIER, entry.getValue().getNotifierId());
trackerDataView.set(TRACKER_ENTRY_CREATOR, entry.getValue().getCreatorId());
trackerDataViews.add(trackerDataView);
}
}
if (!trackerDataViews.isEmpty()) {
levelDataView.createView(DataQueries.SPONGE_DATA).set(TRACKER_DATA_TABLE, trackerDataViews);
}
final short[] biomes = chunk.getBiomes();
final byte[] biomes0 = new byte[biomes.length];
byte[] biomes1 = null;
for (int i = 0; i < biomes.length; i++) {
biomes0[i] = (byte) (biomes[i] & 0xff);
byte value = (byte) ((biomes[i] >> 4) & 0xff);
if (value != 0) {
if (biomes1 == null) {
biomes1 = new byte[biomes0.length];
}
biomes1[i] = value;
}
}
levelDataView.set(BIOMES, biomes0);
if (biomes1 != null) {
levelDataView.set(BIOMES_EXTRA, biomes1);
}
// noinspection unchecked
final List<LanternEntity> entities = new ArrayList(chunk.getEntities(entity -> !(entity instanceof Player)));
final ObjectSerializer<LanternEntity> entitySerializer = ObjectSerializerRegistry.get().get(LanternEntity.class).get();
final List<DataView> entityViews = new ArrayList<>();
for (LanternEntity entity : entities) {
if (entity.getRemoveState() == LanternEntity.RemoveState.DESTROYED) {
continue;
}
final DataView entityView = entitySerializer.serialize(entity);
entityViews.add(entityView);
}
levelDataView.set(ENTITIES, entityViews);
try (NbtDataContainerOutputStream nbt = new NbtDataContainerOutputStream(region.getChunkDataOutputStream(regionX, regionZ))) {
nbt.write(rootView);
nbt.flush();
}
}
Aggregations