added a new system that possibly massively increases aura spot performance

This commit is contained in:
Ell 2021-01-29 20:33:37 +01:00
parent 65879a448c
commit 06ec3cb4ff
5 changed files with 68 additions and 23 deletions

View file

@ -10,6 +10,7 @@ import de.ellpeck.naturesaura.blocks.tiles.TileEntityImpl;
import de.ellpeck.naturesaura.chunk.AuraChunk; import de.ellpeck.naturesaura.chunk.AuraChunk;
import de.ellpeck.naturesaura.compat.Compat; import de.ellpeck.naturesaura.compat.Compat;
import de.ellpeck.naturesaura.misc.WorldData; import de.ellpeck.naturesaura.misc.WorldData;
import de.ellpeck.naturesaura.misc.WorldData.WorldSection;
import net.minecraft.advancements.Advancement; import net.minecraft.advancements.Advancement;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -77,17 +78,27 @@ public final class Helper {
return false; return false;
} }
public static void getAuraChunksWithSpotsInArea(World world, BlockPos pos, int radius, Consumer<AuraChunk> consumer) { public static void getWorldSectionsWithSpotsInArea(World world, BlockPos pos, int radius, Consumer<WorldSection> consumer){
WorldData data = (WorldData) IWorldData.getWorldData(world); WorldData data = (WorldData) IWorldData.getWorldData(world);
for (int x = pos.getX() - radius >> 4; x <= pos.getX() + radius >> 4; x++) { for (int x = pos.getX() - radius >> WorldSection.B_SIZE; x <= pos.getX() + radius >> WorldSection.B_SIZE; x++) {
for (int z = pos.getZ() - radius >> 4; z <= pos.getZ() + radius >> 4; z++) { for (int z = pos.getZ() - radius >> WorldSection.B_SIZE; z <= pos.getZ() + radius >> WorldSection.B_SIZE; z++) {
AuraChunk chunk = data.auraChunksWithSpots.get(ChunkPos.asLong(x, z)); WorldSection section = data.worldSectionsWithSpots.get(ChunkPos.asLong(x, z));
if (chunk != null) if (section != null)
consumer.accept(chunk); consumer.accept(section);
} }
} }
} }
public static void getAuraChunksWithSpotsInArea(World world, BlockPos pos, int radius, Consumer<AuraChunk> consumer) {
getWorldSectionsWithSpotsInArea(world,pos,radius, s -> {
for (AuraChunk chunk : s.chunksWithSpots.values()) {
ChunkPos chunkPos = chunk.getPos();
if (chunkPos.x >= pos.getX() - radius >> 4 && chunkPos.x <= pos.getX() + radius >> 4 && chunkPos.z >= pos.getZ() - radius >> 4 && chunkPos.z <= pos.getZ() + radius >> 4)
consumer.accept(chunk);
}
});
}
public static List<ItemFrameEntity> getAttachedItemFrames(World world, BlockPos pos) { public static List<ItemFrameEntity> getAttachedItemFrames(World world, BlockPos pos) {
List<ItemFrameEntity> frames = world.getEntitiesWithinAABB(ItemFrameEntity.class, new AxisAlignedBB(pos).grow(0.25)); List<ItemFrameEntity> frames = world.getEntitiesWithinAABB(ItemFrameEntity.class, new AxisAlignedBB(pos).grow(0.25));
for (int i = frames.size() - 1; i >= 0; i--) { for (int i = frames.size() - 1; i >= 0; i--) {

View file

@ -7,6 +7,7 @@ import de.ellpeck.naturesaura.api.aura.chunk.IDrainSpotEffect.ActiveType;
import de.ellpeck.naturesaura.api.aura.type.IAuraType; import de.ellpeck.naturesaura.api.aura.type.IAuraType;
import de.ellpeck.naturesaura.api.misc.IWorldData; import de.ellpeck.naturesaura.api.misc.IWorldData;
import de.ellpeck.naturesaura.misc.WorldData; import de.ellpeck.naturesaura.misc.WorldData;
import de.ellpeck.naturesaura.misc.WorldData.WorldSection;
import de.ellpeck.naturesaura.packet.PacketAuraChunk; import de.ellpeck.naturesaura.packet.PacketAuraChunk;
import de.ellpeck.naturesaura.packet.PacketHandler; import de.ellpeck.naturesaura.packet.PacketHandler;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
@ -119,7 +120,7 @@ public class AuraChunk implements IAuraChunk {
private void addDrainSpot(BlockPos pos, MutableInt spot) { private void addDrainSpot(BlockPos pos, MutableInt spot) {
int expX = pos.getX() >> 4; int expX = pos.getX() >> 4;
int expZ = pos.getZ() >> 4; int expZ = pos.getZ() >> 4;
ChunkPos myPos = this.chunk.getPos(); ChunkPos myPos = this.getPos();
if (expX != myPos.x || expZ != myPos.z) 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); 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);
@ -130,7 +131,7 @@ public class AuraChunk implements IAuraChunk {
this.drainSpots.clear(); this.drainSpots.clear();
for (Map.Entry<BlockPos, MutableInt> entry : spots.entrySet()) for (Map.Entry<BlockPos, MutableInt> entry : spots.entrySet())
this.addDrainSpot(entry.getKey(), entry.getValue()); this.addDrainSpot(entry.getKey(), entry.getValue());
this.addOrRemoveAsActive(); this.addOrRemoveAsActive(this.drainSpots.size() > 0);
} }
@Override @Override
@ -142,7 +143,7 @@ public class AuraChunk implements IAuraChunk {
public void markDirty() { public void markDirty() {
this.chunk.markDirty(); this.chunk.markDirty();
this.needsSync = true; this.needsSync = true;
this.addOrRemoveAsActive(); this.addOrRemoveAsActive(this.drainSpots.size() > 0);
} }
public void update() { public void update() {
@ -156,7 +157,7 @@ public class AuraChunk implements IAuraChunk {
} }
if (this.needsSync) { if (this.needsSync) {
ChunkPos pos = this.chunk.getPos(); ChunkPos pos = this.getPos();
PacketHandler.sendToAllLoaded(world, PacketHandler.sendToAllLoaded(world,
new BlockPos(pos.x * 16, 0, pos.z * 16), new BlockPos(pos.x * 16, 0, pos.z * 16),
this.makePacket()); this.makePacket());
@ -165,7 +166,7 @@ public class AuraChunk implements IAuraChunk {
} }
public PacketAuraChunk makePacket() { public PacketAuraChunk makePacket() {
ChunkPos pos = this.chunk.getPos(); ChunkPos pos = this.getPos();
return new PacketAuraChunk(pos.x, pos.z, this.drainSpots); return new PacketAuraChunk(pos.x, pos.z, this.drainSpots);
} }
@ -197,6 +198,27 @@ public class AuraChunk implements IAuraChunk {
} }
} }
public ChunkPos getPos() {
return this.chunk.getPos();
}
public void addOrRemoveAsActive(boolean add) {
ChunkPos chunkPos = this.getPos();
long sectionPos = new ChunkPos(chunkPos.x >> WorldSection.B_SIZE - 4, chunkPos.z >> WorldSection.B_SIZE - 4).asLong();
WorldData data = (WorldData) IWorldData.getWorldData(this.chunk.getWorld());
if (add) {
WorldSection section = data.worldSectionsWithSpots.computeIfAbsent(sectionPos, l -> new WorldSection());
section.chunksWithSpots.put(chunkPos.asLong(), this);
} else {
WorldSection section = data.worldSectionsWithSpots.get(sectionPos);
if (section != null) {
section.chunksWithSpots.remove(chunkPos.asLong());
if (section.chunksWithSpots.size() <= 0)
data.worldSectionsWithSpots.remove(sectionPos);
}
}
}
@Override @Override
public CompoundNBT serializeNBT() { public CompoundNBT serializeNBT() {
ListNBT list = new ListNBT(); ListNBT list = new ListNBT();
@ -222,16 +244,7 @@ public class AuraChunk implements IAuraChunk {
BlockPos.fromLong(tag.getLong("pos")), BlockPos.fromLong(tag.getLong("pos")),
new MutableInt(tag.getInt("amount"))); new MutableInt(tag.getInt("amount")));
} }
this.addOrRemoveAsActive(); this.addOrRemoveAsActive(this.drainSpots.size() > 0);
} }
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);
}
}
} }

View file

@ -81,13 +81,15 @@ public class ClientEvents {
MutableInt amount = new MutableInt(IAuraChunk.DEFAULT_AURA); MutableInt amount = new MutableInt(IAuraChunk.DEFAULT_AURA);
MutableInt spots = new MutableInt(); MutableInt spots = new MutableInt();
MutableInt chunks = new MutableInt(); MutableInt chunks = new MutableInt();
MutableInt sections = new MutableInt();
IAuraChunk.getSpotsInArea(mc.world, mc.player.getPosition(), 35, (blockPos, drainSpot) -> { IAuraChunk.getSpotsInArea(mc.world, mc.player.getPosition(), 35, (blockPos, drainSpot) -> {
spots.increment(); spots.increment();
amount.add(drainSpot); amount.add(drainSpot);
}); });
Helper.getAuraChunksWithSpotsInArea(mc.world, mc.player.getPosition(), 35, c -> chunks.increment()); Helper.getAuraChunksWithSpotsInArea(mc.world, mc.player.getPosition(), 35, c -> chunks.increment());
Helper.getWorldSectionsWithSpotsInArea(mc.world, mc.player.getPosition(), 35, s -> sections.increment());
NumberFormat format = NumberFormat.getInstance(); NumberFormat format = NumberFormat.getInstance();
left.add(prefix + "A: " + format.format(amount.intValue()) + " (S: " + spots.intValue() + ", C: " + chunks.intValue() + ")"); left.add(prefix + "A: " + format.format(amount.intValue()) + " (S: " + spots.intValue() + ", C: " + chunks.intValue() + ", WS: " + sections.intValue() + ")");
left.add(prefix + "AT: " + IAuraType.forWorld(mc.world).getName()); left.add(prefix + "AT: " + IAuraType.forWorld(mc.world).getName());
} }
} }

View file

@ -19,8 +19,10 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IChunk;
import net.minecraft.world.gen.GenerationStage.Decoration; import net.minecraft.world.gen.GenerationStage.Decoration;
import net.minecraft.world.server.ChunkHolder; import net.minecraft.world.server.ChunkHolder;
import net.minecraft.world.server.ChunkManager; import net.minecraft.world.server.ChunkManager;
@ -29,6 +31,7 @@ import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.world.BiomeLoadingEvent; import net.minecraftforge.event.world.BiomeLoadingEvent;
import net.minecraftforge.event.world.ChunkEvent;
import net.minecraftforge.event.world.ChunkWatchEvent; import net.minecraftforge.event.world.ChunkWatchEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
@ -69,6 +72,16 @@ public class CommonEvents {
event.addCapability(new ResourceLocation(NaturesAura.MOD_ID, "aura"), new AuraChunkProvider(chunk)); event.addCapability(new ResourceLocation(NaturesAura.MOD_ID, "aura"), new AuraChunkProvider(chunk));
} }
@SubscribeEvent
public void onChunkUnload(ChunkEvent.Unload event) {
IChunk chunk = event.getChunk();
if (chunk instanceof Chunk) {
IAuraChunk auraChunk = ((Chunk) chunk).getCapability(NaturesAuraAPI.capAuraChunk).orElse(null);
if (auraChunk instanceof AuraChunk)
((AuraChunk) auraChunk).addOrRemoveAsActive(false);
}
}
@SubscribeEvent @SubscribeEvent
public void onWorldCapsAttach(AttachCapabilitiesEvent<World> event) { public void onWorldCapsAttach(AttachCapabilitiesEvent<World> event) {
event.addCapability(new ResourceLocation(NaturesAura.MOD_ID, "data"), new WorldData()); event.addCapability(new ResourceLocation(NaturesAura.MOD_ID, "data"), new WorldData());

View file

@ -30,7 +30,7 @@ import java.util.*;
public class WorldData implements IWorldData { public class WorldData implements IWorldData {
public final ListMultimap<ResourceLocation, Tuple<Vector3d, Integer>> effectPowders = ArrayListMultimap.create(); public final ListMultimap<ResourceLocation, Tuple<Vector3d, Integer>> effectPowders = ArrayListMultimap.create();
public final Long2ObjectOpenHashMap<AuraChunk> auraChunksWithSpots = new Long2ObjectOpenHashMap<>(); public final Long2ObjectOpenHashMap<WorldSection> worldSectionsWithSpots = new Long2ObjectOpenHashMap<>();
public final List<BlockPos> recentlyConvertedMossStones = new ArrayList<>(); public final List<BlockPos> recentlyConvertedMossStones = new ArrayList<>();
public final Set<TileEntitySpawnLamp> spawnLamps = new HashSet<>(); public final Set<TileEntitySpawnLamp> spawnLamps = new HashSet<>();
private final Map<String, ItemStackHandlerNA> enderStorages = new HashMap<>(); private final Map<String, ItemStackHandlerNA> enderStorages = new HashMap<>();
@ -100,4 +100,10 @@ public class WorldData implements IWorldData {
if (this.recentlyConvertedMossStones.size() > 512) if (this.recentlyConvertedMossStones.size() > 512)
this.recentlyConvertedMossStones.remove(0); this.recentlyConvertedMossStones.remove(0);
} }
public static class WorldSection {
// each world section is 128 blocks big
public static final int B_SIZE = 7;
public final Long2ObjectOpenHashMap<AuraChunk> chunksWithSpots = new Long2ObjectOpenHashMap<>();
}
} }