2018-11-13 11:39:28 +01:00
package de.ellpeck.naturesaura.chunk ;
2018-10-21 12:51:13 +02:00
2018-11-12 22:04:40 +01:00
import de.ellpeck.naturesaura.api.NaturesAuraAPI ;
2018-11-11 13:26:19 +01:00
import de.ellpeck.naturesaura.api.aura.chunk.IAuraChunk ;
import de.ellpeck.naturesaura.api.aura.chunk.IDrainSpotEffect ;
2020-01-23 16:05:52 +01:00
import de.ellpeck.naturesaura.api.aura.chunk.IDrainSpotEffect.ActiveType ;
2018-11-12 01:29:33 +01:00
import de.ellpeck.naturesaura.api.aura.type.IAuraType ;
2020-12-07 01:06:22 +01:00
import de.ellpeck.naturesaura.api.misc.IWorldData ;
import de.ellpeck.naturesaura.misc.WorldData ;
2020-01-22 23:21:52 +01:00
import de.ellpeck.naturesaura.packet.PacketAuraChunk ;
import de.ellpeck.naturesaura.packet.PacketHandler ;
2019-10-20 22:30:49 +02:00
import net.minecraft.entity.player.PlayerEntity ;
2019-02-09 21:55:40 +01:00
import net.minecraft.item.ItemStack ;
2019-10-20 22:30:49 +02:00
import net.minecraft.nbt.CompoundNBT ;
2020-01-21 21:04:44 +01:00
import net.minecraft.nbt.INBT ;
2019-10-20 22:30:49 +02:00
import net.minecraft.nbt.ListNBT ;
2019-02-09 21:55:40 +01:00
import net.minecraft.util.ResourceLocation ;
import net.minecraft.util.Tuple ;
2018-10-21 12:51:13 +02:00
import net.minecraft.util.math.BlockPos ;
2020-01-22 23:21:52 +01:00
import net.minecraft.util.math.ChunkPos ;
2018-10-21 12:51:13 +02:00
import net.minecraft.world.World ;
import net.minecraft.world.chunk.Chunk ;
import org.apache.commons.lang3.mutable.MutableInt ;
2018-12-03 00:45:34 +01:00
import java.util.ArrayList ;
import java.util.List ;
import java.util.Map ;
import java.util.concurrent.ConcurrentHashMap ;
2018-10-21 12:51:13 +02:00
import java.util.function.BiConsumer ;
2018-11-13 11:39:28 +01:00
import java.util.function.Supplier ;
2018-10-21 12:51:13 +02:00
2018-11-11 13:26:19 +01:00
public class AuraChunk implements IAuraChunk {
2018-10-21 12:51:13 +02:00
private final Chunk chunk ;
2018-11-12 01:29:33 +01:00
private final IAuraType type ;
2018-12-03 00:45:34 +01:00
private final Map < BlockPos , MutableInt > drainSpots = new ConcurrentHashMap < > ( ) ;
2018-10-25 18:49:42 +02:00
private final List < IDrainSpotEffect > effects = new ArrayList < > ( ) ;
2018-10-21 12:51:13 +02:00
private boolean needsSync ;
2018-11-12 01:29:33 +01:00
public AuraChunk ( Chunk chunk , IAuraType type ) {
2018-10-21 12:51:13 +02:00
this . chunk = chunk ;
2018-11-07 23:42:13 +01:00
this . type = type ;
2018-11-13 11:39:28 +01:00
for ( Supplier < IDrainSpotEffect > supplier : NaturesAuraAPI . DRAIN_SPOT_EFFECTS . values ( ) ) {
IDrainSpotEffect effect = supplier . get ( ) ;
2018-11-13 18:21:41 +01:00
if ( effect . appliesHere ( this . chunk , this , this . type ) )
2018-11-13 11:39:28 +01:00
this . effects . add ( effect ) ;
}
2018-10-21 12:51:13 +02:00
}
2018-11-11 13:26:19 +01:00
@Override
2018-11-24 17:32:39 +01:00
public int drainAura ( BlockPos pos , int amount , boolean aimForZero , boolean simulate ) {
2018-11-18 19:49:30 +01:00
if ( amount < = 0 )
2018-11-18 20:34:57 +01:00
return 0 ;
2020-12-07 01:06:22 +01:00
MutableInt spot = this . getActualDrainSpot ( pos , ! simulate ) ;
int curr = spot ! = null ? spot . intValue ( ) : 0 ;
2019-01-27 19:12:48 +01:00
if ( curr < 0 & & curr - amount > 0 ) // Underflow protection
2018-12-03 14:40:53 +01:00
return this . drainAura ( pos . up ( ) , amount , aimForZero , simulate ) ;
2018-11-18 20:34:57 +01:00
if ( aimForZero ) {
if ( curr > 0 & & curr - amount < 0 )
amount = curr ;
}
2018-11-24 17:32:39 +01:00
if ( ! simulate ) {
spot . subtract ( amount ) ;
2018-12-03 00:45:34 +01:00
if ( spot . intValue ( ) = = 0 )
this . drainSpots . remove ( pos ) ;
2018-11-24 17:32:39 +01:00
this . markDirty ( ) ;
}
2018-11-18 20:34:57 +01:00
return amount ;
2018-10-21 12:51:13 +02:00
}
2018-11-11 13:26:19 +01:00
@Override
2018-11-18 20:34:57 +01:00
public int drainAura ( BlockPos pos , int amount ) {
2018-11-24 17:32:39 +01:00
return this . drainAura ( pos , amount , false , false ) ;
2018-11-18 20:34:57 +01:00
}
@Override
2018-11-24 17:32:39 +01:00
public int storeAura ( BlockPos pos , int amount , boolean aimForZero , boolean simulate ) {
2018-11-18 19:49:30 +01:00
if ( amount < = 0 )
2018-11-18 20:34:57 +01:00
return 0 ;
2020-12-07 01:06:22 +01:00
MutableInt spot = this . getActualDrainSpot ( pos , ! simulate ) ;
int curr = spot ! = null ? spot . intValue ( ) : 0 ;
2018-12-02 01:36:41 +01:00
if ( curr > 0 & & curr + amount < 0 ) // Overflow protection
2018-12-03 14:40:53 +01:00
return this . storeAura ( pos . up ( ) , amount , aimForZero , simulate ) ;
2018-11-18 20:34:57 +01:00
if ( aimForZero ) {
if ( curr < 0 & & curr + amount > 0 ) {
amount = - curr ;
}
}
2018-11-24 17:32:39 +01:00
if ( ! simulate ) {
spot . add ( amount ) ;
2018-12-03 00:45:34 +01:00
if ( spot . intValue ( ) = = 0 )
this . drainSpots . remove ( pos ) ;
2018-11-24 17:32:39 +01:00
this . markDirty ( ) ;
}
2018-11-18 20:34:57 +01:00
return amount ;
}
@Override
public int storeAura ( BlockPos pos , int amount ) {
2018-11-24 17:32:39 +01:00
return this . storeAura ( pos , amount , true , false ) ;
2018-10-21 12:51:13 +02:00
}
2018-12-02 01:36:41 +01:00
private MutableInt getActualDrainSpot ( BlockPos pos , boolean make ) {
2018-10-24 13:06:24 +02:00
MutableInt spot = this . drainSpots . get ( pos ) ;
2018-12-02 01:36:41 +01:00
if ( spot = = null & & make ) {
2018-10-24 13:06:24 +02:00
spot = new MutableInt ( ) ;
2018-11-23 20:36:31 +01:00
this . addDrainSpot ( pos , spot ) ;
2018-10-21 12:51:13 +02:00
}
return spot ;
}
2018-12-02 01:36:41 +01:00
@Override
public int getDrainSpot ( BlockPos pos ) {
MutableInt spot = this . getActualDrainSpot ( pos , false ) ;
return spot = = null ? 0 : spot . intValue ( ) ;
}
2018-11-23 20:36:31 +01:00
private void addDrainSpot ( BlockPos pos , MutableInt spot ) {
int expX = pos . getX ( ) > > 4 ;
int expZ = pos . getZ ( ) > > 4 ;
2020-01-22 23:21:52 +01:00
ChunkPos myPos = this . chunk . getPos ( ) ;
if ( expX ! = myPos . x | | expZ ! = myPos . z )
throw new IllegalArgumentException ( " Tried to add drain spot " + pos + " to chunk at " + myPos . x + " , " + myPos . z + " when it should've been added to chunk at " + expX + " , " + expZ ) ;
2018-11-23 20:36:31 +01:00
this . drainSpots . put ( pos , spot ) ;
}
2018-10-24 13:06:24 +02:00
public void setSpots ( Map < BlockPos , MutableInt > spots ) {
2018-10-21 12:51:13 +02:00
this . drainSpots . clear ( ) ;
2018-11-23 20:36:31 +01:00
for ( Map . Entry < BlockPos , MutableInt > entry : spots . entrySet ( ) )
this . addDrainSpot ( entry . getKey ( ) , entry . getValue ( ) ) ;
2020-12-07 01:06:22 +01:00
this . addOrRemoveAsActive ( ) ;
2018-10-21 12:51:13 +02:00
}
2018-11-11 13:26:19 +01:00
@Override
2018-11-12 01:29:33 +01:00
public IAuraType getType ( ) {
2018-11-07 23:42:13 +01:00
return this . type ;
}
2018-11-11 13:26:19 +01:00
@Override
2018-10-21 12:51:13 +02:00
public void markDirty ( ) {
2019-02-09 18:47:20 +01:00
this . chunk . markDirty ( ) ;
2018-10-21 12:51:13 +02:00
this . needsSync = true ;
2020-12-07 01:06:22 +01:00
this . addOrRemoveAsActive ( ) ;
2018-10-21 12:51:13 +02:00
}
public void update ( ) {
World world = this . chunk . getWorld ( ) ;
2018-10-25 18:49:42 +02:00
for ( Map . Entry < BlockPos , MutableInt > entry : this . drainSpots . entrySet ( ) ) {
2018-11-18 19:49:30 +01:00
BlockPos pos = entry . getKey ( ) ;
MutableInt amount = entry . getValue ( ) ;
2020-01-21 21:04:44 +01:00
for ( IDrainSpotEffect effect : this . effects )
2018-12-02 01:36:41 +01:00
effect . update ( world , this . chunk , this , pos , amount . intValue ( ) ) ;
2018-11-18 19:49:30 +01:00
}
if ( this . needsSync ) {
2020-01-22 23:21:52 +01:00
ChunkPos pos = this . chunk . getPos ( ) ;
PacketHandler . sendToAllLoaded ( world ,
new BlockPos ( pos . x * 16 , 0 , pos . z * 16 ) ,
this . makePacket ( ) ) ;
2018-11-18 19:49:30 +01:00
this . needsSync = false ;
2018-10-21 12:51:13 +02:00
}
}
2020-01-22 23:21:52 +01:00
public PacketAuraChunk makePacket ( ) {
ChunkPos pos = this . chunk . getPos ( ) ;
return new PacketAuraChunk ( pos . x , pos . z , this . drainSpots ) ;
2018-10-21 13:12:03 +02:00
}
2019-02-09 21:55:40 +01:00
public void getSpotsInArea ( BlockPos pos , int radius , BiConsumer < BlockPos , Integer > consumer ) {
for ( Map . Entry < BlockPos , MutableInt > entry : this . drainSpots . entrySet ( ) ) {
BlockPos drainPos = entry . getKey ( ) ;
if ( drainPos . distanceSq ( pos ) < = radius * radius ) {
consumer . accept ( drainPos , entry . getValue ( ) . intValue ( ) ) ;
}
}
}
2019-10-20 22:30:49 +02:00
public void getActiveEffectIcons ( PlayerEntity player , Map < ResourceLocation , Tuple < ItemStack , Boolean > > icons ) {
2019-02-09 21:55:40 +01:00
for ( IDrainSpotEffect effect : this . effects ) {
Tuple < ItemStack , Boolean > alreadyThere = icons . get ( effect . getName ( ) ) ;
2020-01-21 21:04:44 +01:00
if ( alreadyThere ! = null & & alreadyThere . getB ( ) )
2019-02-09 21:55:40 +01:00
continue ;
for ( Map . Entry < BlockPos , MutableInt > entry : this . drainSpots . entrySet ( ) ) {
BlockPos pos = entry . getKey ( ) ;
MutableInt amount = entry . getValue ( ) ;
2020-01-23 16:05:52 +01:00
ActiveType state = effect . isActiveHere ( player , this . chunk , this , pos , amount . intValue ( ) ) ;
if ( state = = ActiveType . INACTIVE )
2019-02-09 21:55:40 +01:00
continue ;
ItemStack stack = effect . getDisplayIcon ( ) ;
if ( stack . isEmpty ( ) )
continue ;
2020-01-23 16:05:52 +01:00
icons . put ( effect . getName ( ) , new Tuple < > ( stack , state = = ActiveType . INHIBITED ) ) ;
2019-02-09 21:55:40 +01:00
}
}
}
2018-10-21 12:51:13 +02:00
@Override
2019-10-20 22:30:49 +02:00
public CompoundNBT serializeNBT ( ) {
ListNBT list = new ListNBT ( ) ;
2018-10-24 13:06:24 +02:00
for ( Map . Entry < BlockPos , MutableInt > entry : this . drainSpots . entrySet ( ) ) {
2019-10-20 22:30:49 +02:00
CompoundNBT tag = new CompoundNBT ( ) ;
2020-01-21 21:04:44 +01:00
tag . putLong ( " pos " , entry . getKey ( ) . toLong ( ) ) ;
tag . putInt ( " amount " , entry . getValue ( ) . intValue ( ) ) ;
list . add ( tag ) ;
2018-10-21 12:51:13 +02:00
}
2019-10-20 22:30:49 +02:00
CompoundNBT compound = new CompoundNBT ( ) ;
2020-01-21 21:04:44 +01:00
compound . put ( " drain_spots " , list ) ;
2018-10-21 12:51:13 +02:00
return compound ;
}
@Override
2019-10-20 22:30:49 +02:00
public void deserializeNBT ( CompoundNBT compound ) {
2018-10-21 12:51:13 +02:00
this . drainSpots . clear ( ) ;
2020-01-21 21:04:44 +01:00
ListNBT list = compound . getList ( " drain_spots " , 10 ) ;
for ( INBT base : list ) {
2019-10-20 22:30:49 +02:00
CompoundNBT tag = ( CompoundNBT ) base ;
2018-11-23 20:36:31 +01:00
this . addDrainSpot (
2018-10-21 12:51:13 +02:00
BlockPos . fromLong ( tag . getLong ( " pos " ) ) ,
2020-01-21 21:04:44 +01:00
new MutableInt ( tag . getInt ( " amount " ) ) ) ;
2018-10-21 12:51:13 +02:00
}
2020-12-07 01:06:22 +01:00
this . addOrRemoveAsActive ( ) ;
}
private void addOrRemoveAsActive ( ) {
long chunkPos = this . chunk . getPos ( ) . asLong ( ) ;
WorldData data = ( WorldData ) IWorldData . getWorldData ( this . chunk . getWorld ( ) ) ;
if ( this . drainSpots . size ( ) > 0 ) {
data . auraChunksWithSpots . put ( chunkPos , this ) ;
} else {
data . auraChunksWithSpots . remove ( chunkPos ) ;
}
2018-10-21 12:51:13 +02:00
}
}