From 06ec3cb4ffd83cf46d75b8a49790a50df2340a5f Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Fri, 29 Jan 2021 20:33:37 +0100 Subject: [PATCH] added a new system that possibly massively increases aura spot performance --- .../java/de/ellpeck/naturesaura/Helper.java | 23 +++++++--- .../ellpeck/naturesaura/chunk/AuraChunk.java | 43 ++++++++++++------- .../naturesaura/events/ClientEvents.java | 4 +- .../naturesaura/events/CommonEvents.java | 13 ++++++ .../ellpeck/naturesaura/misc/WorldData.java | 8 +++- 5 files changed, 68 insertions(+), 23 deletions(-) diff --git a/src/main/java/de/ellpeck/naturesaura/Helper.java b/src/main/java/de/ellpeck/naturesaura/Helper.java index 302cc913..4458fb48 100644 --- a/src/main/java/de/ellpeck/naturesaura/Helper.java +++ b/src/main/java/de/ellpeck/naturesaura/Helper.java @@ -10,6 +10,7 @@ import de.ellpeck.naturesaura.blocks.tiles.TileEntityImpl; import de.ellpeck.naturesaura.chunk.AuraChunk; import de.ellpeck.naturesaura.compat.Compat; import de.ellpeck.naturesaura.misc.WorldData; +import de.ellpeck.naturesaura.misc.WorldData.WorldSection; import net.minecraft.advancements.Advancement; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -77,17 +78,27 @@ public final class Helper { return false; } - public static void getAuraChunksWithSpotsInArea(World world, BlockPos pos, int radius, Consumer consumer) { + public static void getWorldSectionsWithSpotsInArea(World world, BlockPos pos, int radius, Consumer consumer){ WorldData data = (WorldData) IWorldData.getWorldData(world); - for (int x = pos.getX() - radius >> 4; x <= pos.getX() + radius >> 4; x++) { - for (int z = pos.getZ() - radius >> 4; z <= pos.getZ() + radius >> 4; z++) { - AuraChunk chunk = data.auraChunksWithSpots.get(ChunkPos.asLong(x, z)); - if (chunk != null) - consumer.accept(chunk); + for (int x = pos.getX() - radius >> WorldSection.B_SIZE; x <= pos.getX() + radius >> WorldSection.B_SIZE; x++) { + for (int z = pos.getZ() - radius >> WorldSection.B_SIZE; z <= pos.getZ() + radius >> WorldSection.B_SIZE; z++) { + WorldSection section = data.worldSectionsWithSpots.get(ChunkPos.asLong(x, z)); + if (section != null) + consumer.accept(section); } } } + public static void getAuraChunksWithSpotsInArea(World world, BlockPos pos, int radius, Consumer 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 getAttachedItemFrames(World world, BlockPos pos) { List frames = world.getEntitiesWithinAABB(ItemFrameEntity.class, new AxisAlignedBB(pos).grow(0.25)); for (int i = frames.size() - 1; i >= 0; i--) { diff --git a/src/main/java/de/ellpeck/naturesaura/chunk/AuraChunk.java b/src/main/java/de/ellpeck/naturesaura/chunk/AuraChunk.java index 426cd7f4..08ff3cc9 100644 --- a/src/main/java/de/ellpeck/naturesaura/chunk/AuraChunk.java +++ b/src/main/java/de/ellpeck/naturesaura/chunk/AuraChunk.java @@ -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.misc.IWorldData; import de.ellpeck.naturesaura.misc.WorldData; +import de.ellpeck.naturesaura.misc.WorldData.WorldSection; import de.ellpeck.naturesaura.packet.PacketAuraChunk; import de.ellpeck.naturesaura.packet.PacketHandler; import net.minecraft.entity.player.PlayerEntity; @@ -119,7 +120,7 @@ public class AuraChunk implements IAuraChunk { private void addDrainSpot(BlockPos pos, MutableInt spot) { int expX = pos.getX() >> 4; int expZ = pos.getZ() >> 4; - ChunkPos myPos = this.chunk.getPos(); + ChunkPos myPos = this.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); @@ -130,7 +131,7 @@ public class AuraChunk implements IAuraChunk { this.drainSpots.clear(); for (Map.Entry entry : spots.entrySet()) this.addDrainSpot(entry.getKey(), entry.getValue()); - this.addOrRemoveAsActive(); + this.addOrRemoveAsActive(this.drainSpots.size() > 0); } @Override @@ -142,7 +143,7 @@ public class AuraChunk implements IAuraChunk { public void markDirty() { this.chunk.markDirty(); this.needsSync = true; - this.addOrRemoveAsActive(); + this.addOrRemoveAsActive(this.drainSpots.size() > 0); } public void update() { @@ -156,7 +157,7 @@ public class AuraChunk implements IAuraChunk { } if (this.needsSync) { - ChunkPos pos = this.chunk.getPos(); + ChunkPos pos = this.getPos(); PacketHandler.sendToAllLoaded(world, new BlockPos(pos.x * 16, 0, pos.z * 16), this.makePacket()); @@ -165,7 +166,7 @@ public class AuraChunk implements IAuraChunk { } public PacketAuraChunk makePacket() { - ChunkPos pos = this.chunk.getPos(); + ChunkPos pos = this.getPos(); 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 public CompoundNBT serializeNBT() { ListNBT list = new ListNBT(); @@ -222,16 +244,7 @@ public class AuraChunk implements IAuraChunk { BlockPos.fromLong(tag.getLong("pos")), 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); - } - } } diff --git a/src/main/java/de/ellpeck/naturesaura/events/ClientEvents.java b/src/main/java/de/ellpeck/naturesaura/events/ClientEvents.java index ea09b6fd..42acbb5e 100644 --- a/src/main/java/de/ellpeck/naturesaura/events/ClientEvents.java +++ b/src/main/java/de/ellpeck/naturesaura/events/ClientEvents.java @@ -81,13 +81,15 @@ public class ClientEvents { MutableInt amount = new MutableInt(IAuraChunk.DEFAULT_AURA); MutableInt spots = new MutableInt(); MutableInt chunks = new MutableInt(); + MutableInt sections = new MutableInt(); IAuraChunk.getSpotsInArea(mc.world, mc.player.getPosition(), 35, (blockPos, drainSpot) -> { spots.increment(); amount.add(drainSpot); }); 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(); - 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()); } } diff --git a/src/main/java/de/ellpeck/naturesaura/events/CommonEvents.java b/src/main/java/de/ellpeck/naturesaura/events/CommonEvents.java index 884388ee..be893696 100644 --- a/src/main/java/de/ellpeck/naturesaura/events/CommonEvents.java +++ b/src/main/java/de/ellpeck/naturesaura/events/CommonEvents.java @@ -19,8 +19,10 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.IWorld; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.IChunk; import net.minecraft.world.gen.GenerationStage.Decoration; import net.minecraft.world.server.ChunkHolder; import net.minecraft.world.server.ChunkManager; @@ -29,6 +31,7 @@ import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.world.BiomeLoadingEvent; +import net.minecraftforge.event.world.ChunkEvent; import net.minecraftforge.event.world.ChunkWatchEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.ObfuscationReflectionHelper; @@ -69,6 +72,16 @@ public class CommonEvents { 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 public void onWorldCapsAttach(AttachCapabilitiesEvent event) { event.addCapability(new ResourceLocation(NaturesAura.MOD_ID, "data"), new WorldData()); diff --git a/src/main/java/de/ellpeck/naturesaura/misc/WorldData.java b/src/main/java/de/ellpeck/naturesaura/misc/WorldData.java index 3589afa7..1c0802c5 100644 --- a/src/main/java/de/ellpeck/naturesaura/misc/WorldData.java +++ b/src/main/java/de/ellpeck/naturesaura/misc/WorldData.java @@ -30,7 +30,7 @@ import java.util.*; public class WorldData implements IWorldData { public final ListMultimap> effectPowders = ArrayListMultimap.create(); - public final Long2ObjectOpenHashMap auraChunksWithSpots = new Long2ObjectOpenHashMap<>(); + public final Long2ObjectOpenHashMap worldSectionsWithSpots = new Long2ObjectOpenHashMap<>(); public final List recentlyConvertedMossStones = new ArrayList<>(); public final Set spawnLamps = new HashSet<>(); private final Map enderStorages = new HashMap<>(); @@ -100,4 +100,10 @@ public class WorldData implements IWorldData { if (this.recentlyConvertedMossStones.size() > 512) 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 chunksWithSpots = new Long2ObjectOpenHashMap<>(); + } }