/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.mojang.logging.LogUtils * it.unimi.dsi.fastutil.longs.Long2ObjectFunction * it.unimi.dsi.fastutil.longs.LongOpenHashSet * it.unimi.dsi.fastutil.longs.LongSet * org.slf4j.Logger */ package net.minecraft.world.level.entity; import com.mojang.logging.LogUtils; import it.unimi.dsi.fastutil.longs.Long2ObjectFunction; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.util.VisibleForDebug; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.entity.EntityAccess; import net.minecraft.world.level.entity.EntityInLevelCallback; import net.minecraft.world.level.entity.EntityLookup; import net.minecraft.world.level.entity.EntitySection; import net.minecraft.world.level.entity.EntitySectionStorage; import net.minecraft.world.level.entity.LevelCallback; import net.minecraft.world.level.entity.LevelEntityGetter; import net.minecraft.world.level.entity.LevelEntityGetterAdapter; import net.minecraft.world.level.entity.Visibility; import org.slf4j.Logger; public class TransientEntitySectionManager { private static final Logger LOGGER = LogUtils.getLogger(); private final LevelCallback callbacks; private final EntityLookup entityStorage; private final EntitySectionStorage sectionStorage; private final LongSet tickingChunks = new LongOpenHashSet(); private final LevelEntityGetter entityGetter; public TransientEntitySectionManager(Class entityClass, LevelCallback callbacks) { this.entityStorage = new EntityLookup(); this.sectionStorage = new EntitySectionStorage(entityClass, (Long2ObjectFunction)((Long2ObjectFunction)key -> this.tickingChunks.contains(key) ? Visibility.TICKING : Visibility.TRACKED)); this.callbacks = callbacks; this.entityGetter = new LevelEntityGetterAdapter(this.entityStorage, this.sectionStorage); } public void startTicking(ChunkPos pos) { long chunkKey = pos.toLong(); this.tickingChunks.add(chunkKey); this.sectionStorage.getExistingSectionsInChunk(chunkKey).forEach(section -> { Visibility previousStatus = section.updateChunkStatus(Visibility.TICKING); if (!previousStatus.isTicking()) { section.getEntities().filter(e -> !e.isAlwaysTicking()).forEach(this.callbacks::onTickingStart); } }); } public void stopTicking(ChunkPos pos) { long chunkKey = pos.toLong(); this.tickingChunks.remove(chunkKey); this.sectionStorage.getExistingSectionsInChunk(chunkKey).forEach(section -> { Visibility previousStatus = section.updateChunkStatus(Visibility.TRACKED); if (previousStatus.isTicking()) { section.getEntities().filter(e -> !e.isAlwaysTicking()).forEach(this.callbacks::onTickingEnd); } }); } public LevelEntityGetter getEntityGetter() { return this.entityGetter; } public void addEntity(T entity) { this.entityStorage.add(entity); long sectionKey = SectionPos.asLong(entity.blockPosition()); EntitySection entitySection = this.sectionStorage.getOrCreateSection(sectionKey); entitySection.add(entity); entity.setLevelCallback(new Callback(this, entity, sectionKey, entitySection)); this.callbacks.onCreated(entity); this.callbacks.onTrackingStart(entity); if (entity.isAlwaysTicking() || entitySection.getStatus().isTicking()) { this.callbacks.onTickingStart(entity); } } @VisibleForDebug public int count() { return this.entityStorage.count(); } private void removeSectionIfEmpty(long sectionPos, EntitySection section) { if (section.isEmpty()) { this.sectionStorage.remove(sectionPos); } } @VisibleForDebug public String gatherStats() { return this.entityStorage.count() + "," + this.sectionStorage.count() + "," + this.tickingChunks.size(); } private class Callback implements EntityInLevelCallback { private final T entity; private long currentSectionKey; private EntitySection currentSection; final /* synthetic */ TransientEntitySectionManager this$0; /* * WARNING - Possible parameter corruption * WARNING - void declaration */ private Callback(T t, long currentSection, EntitySection entitySection) { void var3_3; void entity; this.this$0 = (TransientEntitySectionManager)l; this.entity = entity; this.currentSectionKey = var3_3; this.currentSection = (EntitySection)currentSection; } @Override public void onMove() { BlockPos pos = this.entity.blockPosition(); long newSectionPos = SectionPos.asLong(pos); if (newSectionPos != this.currentSectionKey) { Visibility previousStatus = this.currentSection.getStatus(); if (!this.currentSection.remove(this.entity)) { LOGGER.warn("Entity {} wasn't found in section {} (moving to {})", new Object[]{this.entity, SectionPos.of(this.currentSectionKey), newSectionPos}); } this.this$0.removeSectionIfEmpty(this.currentSectionKey, this.currentSection); EntitySection newSection = this.this$0.sectionStorage.getOrCreateSection(newSectionPos); newSection.add(this.entity); this.currentSection = newSection; this.currentSectionKey = newSectionPos; this.this$0.callbacks.onSectionChange(this.entity); if (!this.entity.isAlwaysTicking()) { boolean wasTicking = previousStatus.isTicking(); boolean isTicking = newSection.getStatus().isTicking(); if (wasTicking && !isTicking) { this.this$0.callbacks.onTickingEnd(this.entity); } else if (!wasTicking && isTicking) { this.this$0.callbacks.onTickingStart(this.entity); } } } } @Override public void onRemove(Entity.RemovalReason reason) { Visibility status; if (!this.currentSection.remove(this.entity)) { LOGGER.warn("Entity {} wasn't found in section {} (destroying due to {})", new Object[]{this.entity, SectionPos.of(this.currentSectionKey), reason}); } if ((status = this.currentSection.getStatus()).isTicking() || this.entity.isAlwaysTicking()) { this.this$0.callbacks.onTickingEnd(this.entity); } this.this$0.callbacks.onTrackingEnd(this.entity); this.this$0.callbacks.onDestroyed(this.entity); this.this$0.entityStorage.remove(this.entity); this.entity.setLevelCallback(NULL); this.this$0.removeSectionIfEmpty(this.currentSectionKey, this.currentSection); } } }