2019-09-15 23:34:14 +00:00
/ *
2020-01-09 03:05:42 +00:00
* Copyright ( c ) 2019 - 2020 GeyserMC . http : //geysermc.org
2019-09-15 23:34:14 +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 :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* 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 .
*
* @author GeyserMC
* @link https : //github.com/GeyserMC/Geyser
* /
package org.geysermc.connector.network.session.cache ;
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk ;
import com.github.steveice10.mc.protocol.data.game.chunk.Column ;
2020-10-13 14:44:47 +00:00
import it.unimi.dsi.fastutil.longs.Long2ObjectMap ;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap ;
2020-07-07 01:38:10 +00:00
import org.geysermc.connector.bootstrap.GeyserBootstrap ;
2019-09-15 23:34:14 +00:00
import org.geysermc.connector.network.session.GeyserSession ;
2020-04-29 20:01:53 +00:00
import org.geysermc.connector.network.translators.world.block.BlockTranslator ;
2020-10-15 06:30:25 +00:00
import org.geysermc.connector.utils.MathUtils ;
2019-09-15 23:34:14 +00:00
public class ChunkCache {
2020-07-07 01:38:10 +00:00
private final boolean cache ;
2019-09-15 23:34:14 +00:00
2020-10-13 14:44:47 +00:00
private final Long2ObjectMap < Column > chunks = new Long2ObjectOpenHashMap < > ( ) ;
2019-09-15 23:34:14 +00:00
public ChunkCache ( GeyserSession session ) {
2020-07-07 01:38:10 +00:00
if ( session . getConnector ( ) . getWorldManager ( ) . getClass ( ) = = GeyserBootstrap . DEFAULT_CHUNK_MANAGER . getClass ( ) ) {
this . cache = session . getConnector ( ) . getConfig ( ) . isCacheChunks ( ) ;
} else {
this . cache = false ; // To prevent Spigot from initializing
}
2019-09-15 23:34:14 +00:00
}
2020-10-15 06:30:25 +00:00
public Column addToCache ( Column chunk ) {
2020-04-29 20:01:53 +00:00
if ( ! cache ) {
2020-10-15 06:30:25 +00:00
return chunk ;
2020-04-29 20:01:53 +00:00
}
2020-10-13 14:44:47 +00:00
2020-10-15 06:30:25 +00:00
long chunkPosition = MathUtils . chunkPositionToLong ( chunk . getX ( ) , chunk . getZ ( ) ) ;
2020-10-13 14:44:47 +00:00
Column existingChunk ;
2020-10-15 06:30:25 +00:00
if ( chunk . getBiomeData ( ) = = null // Only consider merging columns if the new chunk isn't a full chunk
2020-10-13 14:44:47 +00:00
& & ( existingChunk = chunks . getOrDefault ( chunkPosition , null ) ) ! = null ) { // Column is already present in cache, we can merge with existing
2020-10-15 06:30:25 +00:00
boolean changed = false ;
2020-10-13 14:44:47 +00:00
for ( int i = 0 ; i < chunk . getChunks ( ) . length ; i + + ) { // The chunks member is final, so chunk.getChunks() will probably be inlined and then completely optimized away
if ( chunk . getChunks ( ) [ i ] ! = null ) {
existingChunk . getChunks ( ) [ i ] = chunk . getChunks ( ) [ i ] ;
2020-10-15 06:30:25 +00:00
changed = true ;
2020-09-03 23:00:36 +00:00
}
}
2020-10-15 06:30:25 +00:00
return changed ? existingChunk : null ;
2020-10-13 14:44:47 +00:00
} else {
chunks . put ( chunkPosition , chunk ) ;
2020-10-15 06:30:25 +00:00
return chunk ;
2020-09-03 23:00:36 +00:00
}
2019-09-15 23:34:14 +00:00
}
2020-10-13 14:44:47 +00:00
public Column getChunk ( int chunkX , int chunkZ ) {
2020-10-15 06:30:25 +00:00
long chunkPosition = MathUtils . chunkPositionToLong ( chunkX , chunkZ ) ;
2020-10-13 14:44:47 +00:00
return chunks . getOrDefault ( chunkPosition , null ) ;
}
public void updateBlock ( int x , int y , int z , int block ) {
2020-04-29 20:01:53 +00:00
if ( ! cache ) {
return ;
}
2020-10-13 14:44:47 +00:00
Column column = this . getChunk ( x > > 4 , z > > 4 ) ;
if ( column = = null ) {
2019-09-15 23:34:14 +00:00
return ;
2020-10-13 14:44:47 +00:00
}
2019-09-15 23:34:14 +00:00
2020-10-13 14:44:47 +00:00
Chunk chunk = column . getChunks ( ) [ y > > 4 ] ;
2019-09-15 23:34:14 +00:00
if ( chunk ! = null ) {
2020-10-13 14:44:47 +00:00
chunk . set ( x & 0xF , y & 0xF , z & 0xF , block ) ;
2019-09-15 23:34:14 +00:00
}
}
2020-10-13 14:44:47 +00:00
public int getBlockAt ( int x , int y , int z ) {
2020-04-29 20:01:53 +00:00
if ( ! cache ) {
return BlockTranslator . AIR ;
}
2020-10-13 14:44:47 +00:00
Column column = this . getChunk ( x > > 4 , z > > 4 ) ;
if ( column = = null ) {
2019-12-31 00:14:38 +00:00
return BlockTranslator . AIR ;
2020-10-13 14:44:47 +00:00
}
2019-09-15 23:34:14 +00:00
2020-10-13 14:44:47 +00:00
Chunk chunk = column . getChunks ( ) [ y > > 4 ] ;
2019-09-15 23:34:14 +00:00
if ( chunk ! = null ) {
2020-10-13 14:44:47 +00:00
return chunk . get ( x & 0xF , y & 0xF , z & 0xF ) ;
2019-09-15 23:34:14 +00:00
}
2019-12-31 00:14:38 +00:00
return BlockTranslator . AIR ;
2019-09-15 23:34:14 +00:00
}
2020-10-13 14:44:47 +00:00
public void removeChunk ( int chunkX , int chunkZ ) {
2020-04-29 20:01:53 +00:00
if ( ! cache ) {
2019-09-15 23:34:14 +00:00
return ;
2020-04-29 20:01:53 +00:00
}
2020-10-13 14:44:47 +00:00
2020-10-15 06:30:25 +00:00
long chunkPosition = MathUtils . chunkPositionToLong ( chunkX , chunkZ ) ;
2020-10-13 14:44:47 +00:00
chunks . remove ( chunkPosition ) ;
2019-09-15 23:34:14 +00:00
}
}