2020-01-09 03:05:42 +00:00
/ *
* Copyright ( c ) 2019 - 2020 GeyserMC . http : //geysermc.org
*
2020-07-30 20:10:15 +00:00
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
2020-04-29 20:01:53 +00:00
*
2020-07-30 20:10:15 +00:00
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
2020-04-29 20:01:53 +00:00
*
2020-07-30 20:10:15 +00:00
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
2020-01-09 03:05:42 +00:00
*
2020-07-30 20:10:15 +00:00
* @author GeyserMC
* @link https : //github.com/GeyserMC/Geyser
2020-01-09 03:05:42 +00:00
* /
2020-04-29 20:01:53 +00:00
package org.geysermc.connector.network.translators.world.chunk ;
2019-08-30 21:47:33 +00:00
import com.nukkitx.network.VarInts ;
import io.netty.buffer.ByteBuf ;
2019-11-30 19:26:51 +00:00
import it.unimi.dsi.fastutil.ints.IntArrayList ;
import it.unimi.dsi.fastutil.ints.IntList ;
2020-10-15 06:30:25 +00:00
import lombok.Getter ;
2020-11-17 17:03:12 +00:00
import org.geysermc.connector.network.translators.world.block.BlockTranslator ;
2020-04-29 20:01:53 +00:00
import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArray ;
import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArrayVersion ;
2019-08-30 21:47:33 +00:00
2019-11-30 19:26:51 +00:00
import java.util.function.IntConsumer ;
2020-10-15 06:30:25 +00:00
@Getter
2019-08-30 21:47:33 +00:00
public class BlockStorage {
2020-10-15 06:30:25 +00:00
public static final int SIZE = 4096 ;
2019-08-30 21:47:33 +00:00
2019-11-30 19:26:51 +00:00
private final IntList palette ;
2019-09-10 21:50:34 +00:00
private BitArray bitArray ;
2019-08-30 21:47:33 +00:00
public BlockStorage ( ) {
2019-09-10 21:50:34 +00:00
this ( BitArrayVersion . V2 ) ;
2019-08-30 21:47:33 +00:00
}
2019-09-10 21:50:34 +00:00
public BlockStorage ( BitArrayVersion version ) {
2020-10-15 06:30:25 +00:00
this . bitArray = version . createArray ( SIZE ) ;
2019-11-30 19:26:51 +00:00
this . palette = new IntArrayList ( 16 ) ;
2020-11-17 17:03:12 +00:00
this . palette . add ( BlockTranslator . BEDROCK_AIR_ID ) ; // Air is at the start of every palette and controls what the default block is in second-layer non-air block spaces.
2019-08-30 21:47:33 +00:00
}
2020-10-15 06:30:25 +00:00
public BlockStorage ( BitArray bitArray , IntList palette ) {
2019-08-30 21:47:33 +00:00
this . palette = palette ;
2019-09-10 21:50:34 +00:00
this . bitArray = bitArray ;
2019-08-30 21:47:33 +00:00
}
2019-09-10 21:50:34 +00:00
private static int getPaletteHeader ( BitArrayVersion version , boolean runtime ) {
return ( version . getId ( ) < < 1 ) | ( runtime ? 1 : 0 ) ;
}
private static BitArrayVersion getVersionFromHeader ( byte header ) {
return BitArrayVersion . get ( header > > 1 , true ) ;
}
2020-10-15 06:30:25 +00:00
public int getFullBlock ( int index ) {
2019-12-21 05:05:20 +00:00
return this . palette . getInt ( this . bitArray . get ( index ) ) ;
2019-08-30 21:47:33 +00:00
}
2020-10-15 06:30:25 +00:00
public void setFullBlock ( int index , int runtimeId ) {
2019-12-21 05:05:20 +00:00
int idx = this . idFor ( runtimeId ) ;
2019-09-10 21:50:34 +00:00
this . bitArray . set ( index , idx ) ;
2019-08-30 21:47:33 +00:00
}
2020-10-15 06:30:25 +00:00
public void writeToNetwork ( ByteBuf buffer ) {
2019-09-10 21:50:34 +00:00
buffer . writeByte ( getPaletteHeader ( bitArray . getVersion ( ) , true ) ) ;
2019-08-30 21:47:33 +00:00
2019-09-10 21:50:34 +00:00
for ( int word : bitArray . getWords ( ) ) {
2019-08-30 21:47:33 +00:00
buffer . writeIntLE ( word ) ;
}
2019-09-13 09:08:48 +00:00
VarInts . writeInt ( buffer , palette . size ( ) ) ;
2019-11-30 19:26:51 +00:00
palette . forEach ( ( IntConsumer ) id - > VarInts . writeInt ( buffer , id ) ) ;
2019-08-30 21:47:33 +00:00
}
2020-10-15 06:30:25 +00:00
public int estimateNetworkSize ( ) {
int size = 1 ; // Palette header
size + = this . bitArray . getWords ( ) . length * 4 ;
// We assume that none of the VarInts will be larger than 3 bytes
size + = 3 ; // Palette size
size + = this . palette . size ( ) * 3 ;
return size ;
}
2019-09-10 21:50:34 +00:00
private void onResize ( BitArrayVersion version ) {
2020-10-15 06:30:25 +00:00
BitArray newBitArray = version . createArray ( SIZE ) ;
2019-08-30 21:47:33 +00:00
for ( int i = 0 ; i < SIZE ; i + + ) {
2019-09-10 21:50:34 +00:00
newBitArray . set ( i , this . bitArray . get ( i ) ) ;
2019-08-30 21:47:33 +00:00
}
2019-09-10 21:50:34 +00:00
this . bitArray = newBitArray ;
2019-08-30 21:47:33 +00:00
}
2019-12-21 05:05:20 +00:00
private int idFor ( int runtimeId ) {
2019-09-10 21:50:34 +00:00
int index = this . palette . indexOf ( runtimeId ) ;
2019-08-30 21:47:33 +00:00
if ( index ! = - 1 ) {
return index ;
}
2019-09-10 21:50:34 +00:00
index = this . palette . size ( ) ;
this . palette . add ( runtimeId ) ;
BitArrayVersion version = this . bitArray . getVersion ( ) ;
2019-08-30 21:47:33 +00:00
if ( index > version . getMaxEntryValue ( ) ) {
2019-09-10 21:50:34 +00:00
BitArrayVersion next = version . next ( ) ;
2019-08-30 21:47:33 +00:00
if ( next ! = null ) {
this . onResize ( next ) ;
}
}
return index ;
}
public boolean isEmpty ( ) {
2019-09-10 21:50:34 +00:00
if ( this . palette . size ( ) = = 1 ) {
return true ;
}
for ( int word : this . bitArray . getWords ( ) ) {
if ( Integer . toUnsignedLong ( word ) ! = 0L ) {
2019-08-30 21:47:33 +00:00
return false ;
}
}
return true ;
}
public BlockStorage copy ( ) {
2019-11-30 19:26:51 +00:00
return new BlockStorage ( this . bitArray . copy ( ) , new IntArrayList ( this . palette ) ) ;
2019-08-30 21:47:33 +00:00
}
2019-09-10 21:50:34 +00:00
}