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 ;
2018-11-12 01:29:33 +01:00
import de.ellpeck.naturesaura.api.aura.type.IAuraType ;
2018-10-21 12:51:13 +02:00
import de.ellpeck.naturesaura.packet.PacketAuraChunk ;
import de.ellpeck.naturesaura.packet.PacketHandler ;
import net.minecraft.nbt.NBTBase ;
import net.minecraft.nbt.NBTTagCompound ;
import net.minecraft.nbt.NBTTagList ;
import net.minecraft.util.EnumFacing ;
import net.minecraft.util.math.BlockPos ;
import net.minecraft.world.World ;
import net.minecraft.world.chunk.Chunk ;
import net.minecraftforge.common.capabilities.Capability ;
2018-10-21 13:12:03 +02:00
import net.minecraftforge.fml.common.network.simpleimpl.IMessage ;
2018-10-21 12:51:13 +02:00
import org.apache.commons.lang3.mutable.MutableInt ;
import javax.annotation.Nonnull ;
import javax.annotation.Nullable ;
2018-11-18 19:49:30 +01:00
import java.util.* ;
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-10-24 13:06:24 +02:00
private final Map < BlockPos , MutableInt > drainSpots = new HashMap < > ( ) ;
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-12-02 01:36:41 +01:00
public void getSpotsInArea ( BlockPos pos , int radius , BiConsumer < BlockPos , Integer > consumer ) {
2018-10-24 13:06:24 +02:00
for ( Map . Entry < BlockPos , MutableInt > entry : this . drainSpots . entrySet ( ) ) {
2018-10-21 12:51:13 +02:00
BlockPos drainPos = entry . getKey ( ) ;
if ( drainPos . distanceSq ( pos ) < = radius * radius ) {
2018-12-02 01:36:41 +01:00
consumer . accept ( drainPos , entry . getValue ( ) . intValue ( ) ) ;
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 ;
2018-12-02 01:36:41 +01:00
MutableInt spot = this . getActualDrainSpot ( pos , true ) ;
int curr = spot . intValue ( ) ;
if ( curr < 0 & & curr - amount > 0 ) // Underflow protection
return 0 ;
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 ) ;
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 ;
2018-12-02 01:36:41 +01:00
MutableInt spot = this . getActualDrainSpot ( pos , true ) ;
int curr = spot . intValue ( ) ;
if ( curr > 0 & & curr + amount < 0 ) // Overflow protection
return 0 ;
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 ) ;
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 ;
if ( expX ! = this . chunk . x | | expZ ! = this . chunk . z )
throw new IllegalArgumentException ( " Tried to add drain spot " + pos + " to chunk at " + this . chunk . x + " , " + this . chunk . z + " when it should've been added to chunk at " + expX + " , " + expZ ) ;
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 ( ) ) ;
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 ( ) {
this . needsSync = true ;
}
public void update ( ) {
World world = this . chunk . getWorld ( ) ;
2018-11-18 19:49:30 +01:00
Set < BlockPos > toClear = null ;
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 ( ) ;
2018-10-25 18:49:42 +02:00
for ( IDrainSpotEffect effect : this . effects ) {
2018-11-13 11:39:28 +01:00
world . profiler . func_194340_a ( ( ) - > effect . getName ( ) . toString ( ) ) ;
2018-12-02 01:36:41 +01:00
effect . update ( world , this . chunk , this , pos , amount . intValue ( ) ) ;
2018-10-31 12:16:42 +01:00
world . profiler . endSection ( ) ;
2018-10-21 12:51:13 +02:00
}
2018-11-18 19:49:30 +01:00
if ( amount . intValue ( ) = = 0 ) {
if ( toClear = = null )
toClear = new HashSet < > ( ) ;
toClear . add ( pos ) ;
}
}
if ( toClear ! = null ) {
for ( BlockPos spot : toClear )
this . drainSpots . remove ( spot ) ;
this . markDirty ( ) ;
}
if ( this . needsSync ) {
PacketHandler . sendToAllLoaded ( world ,
new BlockPos ( this . chunk . x * 16 , 0 , this . chunk . z * 16 ) ,
this . makePacket ( ) ) ;
this . needsSync = false ;
2018-10-21 12:51:13 +02:00
}
}
2018-10-21 13:12:03 +02:00
public IMessage makePacket ( ) {
return new PacketAuraChunk ( this . chunk . x , this . chunk . z , this . drainSpots ) ;
}
2018-10-21 12:51:13 +02:00
@Override
public boolean hasCapability ( @Nonnull Capability < ? > capability , @Nullable EnumFacing facing ) {
2018-11-12 22:04:40 +01:00
return capability = = NaturesAuraAPI . capAuraChunk ;
2018-10-21 12:51:13 +02:00
}
@Nullable
@Override
public < T > T getCapability ( @Nonnull Capability < T > capability , @Nullable EnumFacing facing ) {
2018-11-12 22:04:40 +01:00
return capability = = NaturesAuraAPI . capAuraChunk ? ( T ) this : null ;
2018-10-21 12:51:13 +02:00
}
@Override
public NBTTagCompound serializeNBT ( ) {
NBTTagList list = new NBTTagList ( ) ;
2018-10-24 13:06:24 +02:00
for ( Map . Entry < BlockPos , MutableInt > entry : this . drainSpots . entrySet ( ) ) {
2018-10-21 12:51:13 +02:00
NBTTagCompound tag = new NBTTagCompound ( ) ;
tag . setLong ( " pos " , entry . getKey ( ) . toLong ( ) ) ;
2018-10-24 13:06:24 +02:00
tag . setInteger ( " amount " , entry . getValue ( ) . intValue ( ) ) ;
2018-10-21 12:51:13 +02:00
list . appendTag ( tag ) ;
}
NBTTagCompound compound = new NBTTagCompound ( ) ;
compound . setTag ( " drain_spots " , list ) ;
return compound ;
}
@Override
public void deserializeNBT ( NBTTagCompound compound ) {
this . drainSpots . clear ( ) ;
NBTTagList list = compound . getTagList ( " drain_spots " , 10 ) ;
for ( NBTBase base : list ) {
NBTTagCompound tag = ( NBTTagCompound ) base ;
2018-11-23 20:36:31 +01:00
this . addDrainSpot (
2018-10-21 12:51:13 +02:00
BlockPos . fromLong ( tag . getLong ( " pos " ) ) ,
2018-10-24 13:06:24 +02:00
new MutableInt ( tag . getInteger ( " amount " ) ) ) ;
2018-10-21 12:51:13 +02:00
}
}
}