NaturesAura/src/main/java/de/ellpeck/naturesaura/chunk/AuraChunk.java

222 lines
7.8 KiB
Java
Raw Normal View History

package de.ellpeck.naturesaura.chunk;
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;
import de.ellpeck.naturesaura.api.aura.type.IAuraType;
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;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
2019-10-20 22:30:49 +02:00
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.Tuple;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
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;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
2018-11-11 13:26:19 +01:00
public class AuraChunk implements IAuraChunk {
private final Chunk chunk;
private final IAuraType type;
2018-12-03 00:45:34 +01:00
private final Map<BlockPos, MutableInt> drainSpots = new ConcurrentHashMap<>();
private final List<IDrainSpotEffect> effects = new ArrayList<>();
private boolean needsSync;
public AuraChunk(Chunk chunk, IAuraType type) {
this.chunk = chunk;
this.type = type;
for (Supplier<IDrainSpotEffect> supplier : NaturesAuraAPI.DRAIN_SPOT_EFFECTS.values()) {
IDrainSpotEffect effect = supplier.get();
if (effect.appliesHere(this.chunk, this, this.type))
this.effects.add(effect);
}
}
2018-11-11 13:26:19 +01:00
@Override
public int drainAura(BlockPos pos, int amount, boolean aimForZero, boolean simulate) {
if (amount <= 0)
return 0;
MutableInt spot = this.getActualDrainSpot(pos, true);
int curr = spot.intValue();
2019-01-27 19:12:48 +01:00
if (curr < 0 && curr - amount > 0) // Underflow protection
return this.drainAura(pos.up(), amount, aimForZero, simulate);
if (aimForZero) {
if (curr > 0 && curr - amount < 0)
amount = curr;
}
if (!simulate) {
spot.subtract(amount);
2018-12-03 00:45:34 +01:00
if (spot.intValue() == 0)
this.drainSpots.remove(pos);
this.markDirty();
}
return amount;
}
2018-11-11 13:26:19 +01:00
@Override
public int drainAura(BlockPos pos, int amount) {
return this.drainAura(pos, amount, false, false);
}
@Override
public int storeAura(BlockPos pos, int amount, boolean aimForZero, boolean simulate) {
if (amount <= 0)
return 0;
MutableInt spot = this.getActualDrainSpot(pos, true);
int curr = spot.intValue();
if (curr > 0 && curr + amount < 0) // Overflow protection
return this.storeAura(pos.up(), amount, aimForZero, simulate);
if (aimForZero) {
if (curr < 0 && curr + amount > 0) {
amount = -curr;
}
}
if (!simulate) {
spot.add(amount);
2018-12-03 00:45:34 +01:00
if (spot.intValue() == 0)
this.drainSpots.remove(pos);
this.markDirty();
}
return amount;
}
@Override
public int storeAura(BlockPos pos, int amount) {
return this.storeAura(pos, amount, true, false);
}
private MutableInt getActualDrainSpot(BlockPos pos, boolean make) {
2018-10-24 13:06:24 +02:00
MutableInt spot = this.drainSpots.get(pos);
if (spot == null && make) {
2018-10-24 13:06:24 +02:00
spot = new MutableInt();
this.addDrainSpot(pos, spot);
}
return spot;
}
@Override
public int getDrainSpot(BlockPos pos) {
MutableInt spot = this.getActualDrainSpot(pos, false);
return spot == null ? 0 : spot.intValue();
}
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) {
this.drainSpots.clear();
for (Map.Entry<BlockPos, MutableInt> entry : spots.entrySet())
this.addDrainSpot(entry.getKey(), entry.getValue());
}
2018-11-11 13:26:19 +01:00
@Override
public IAuraType getType() {
return this.type;
}
2018-11-11 13:26:19 +01:00
@Override
public void markDirty() {
this.chunk.markDirty();
this.needsSync = true;
}
public void update() {
World world = this.chunk.getWorld();
for (Map.Entry<BlockPos, MutableInt> entry : this.drainSpots.entrySet()) {
BlockPos pos = entry.getKey();
MutableInt amount = entry.getValue();
for (IDrainSpotEffect effect : this.effects) {
world.profiler.func_194340_a(() -> effect.getName().toString());
effect.update(world, this.chunk, this, pos, amount.intValue());
2018-10-31 12:16:42 +01:00
world.profiler.endSection();
}
}
if (this.needsSync) {
PacketHandler.sendToAllLoaded(world,
new BlockPos(this.chunk.x * 16, 0, this.chunk.z * 16),
this.makePacket());
this.needsSync = false;
}
}
public IMessage makePacket() {
return new PacketAuraChunk(this.chunk.x, this.chunk.z, this.drainSpots);
}
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) {
for (IDrainSpotEffect effect : this.effects) {
Tuple<ItemStack, Boolean> alreadyThere = icons.get(effect.getName());
if (alreadyThere != null && alreadyThere.getSecond())
continue;
for (Map.Entry<BlockPos, MutableInt> entry : this.drainSpots.entrySet()) {
BlockPos pos = entry.getKey();
MutableInt amount = entry.getValue();
int state = effect.isActiveHere(player, this.chunk, this, pos, amount.intValue());
if (state < 0)
continue;
ItemStack stack = effect.getDisplayIcon();
if (stack.isEmpty())
continue;
icons.put(effect.getName(), new Tuple<>(stack, state == 0));
}
}
}
@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();
tag.setLong("pos", entry.getKey().toLong());
2018-10-24 13:06:24 +02:00
tag.setInteger("amount", entry.getValue().intValue());
list.appendTag(tag);
}
2019-10-20 22:30:49 +02:00
CompoundNBT compound = new CompoundNBT();
compound.setTag("drain_spots", list);
return compound;
}
@Override
2019-10-20 22:30:49 +02:00
public void deserializeNBT(CompoundNBT compound) {
this.drainSpots.clear();
2019-10-20 22:30:49 +02:00
ListNBT list = compound.getTagList("drain_spots", 10);
for (NBTBase base : list) {
2019-10-20 22:30:49 +02:00
CompoundNBT tag = (CompoundNBT) base;
this.addDrainSpot(
BlockPos.fromLong(tag.getLong("pos")),
2018-10-24 13:06:24 +02:00
new MutableInt(tag.getInteger("amount")));
}
}
}