package net.minecraft.world.ticks; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet; import java.util.Iterator; import java.util.List; import java.util.Optional; import java.util.PriorityQueue; import java.util.Queue; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Stream; import net.minecraft.core.BlockPos; import net.minecraft.nbt.ListTag; import net.minecraft.world.level.ChunkPos; import org.jetbrains.annotations.Nullable; public class LevelChunkTicks implements SerializableTickContainer, TickContainerAccess { private final Queue> tickQueue = new PriorityQueue(ScheduledTick.DRAIN_ORDER); @Nullable private List> pendingTicks; private final Set> ticksPerPosition = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH); @Nullable private BiConsumer, ScheduledTick> onTickAdded; public LevelChunkTicks() { } public LevelChunkTicks(List> pendingTicks) { this.pendingTicks = pendingTicks; for (SavedTick savedTick : pendingTicks) { this.ticksPerPosition.add(ScheduledTick.probe(savedTick.type(), savedTick.pos())); } } public void setOnTickAdded(@Nullable BiConsumer, ScheduledTick> onTickAdded) { this.onTickAdded = onTickAdded; } @Nullable public ScheduledTick peek() { return (ScheduledTick)this.tickQueue.peek(); } @Nullable public ScheduledTick poll() { ScheduledTick scheduledTick = (ScheduledTick)this.tickQueue.poll(); if (scheduledTick != null) { this.ticksPerPosition.remove(scheduledTick); } return scheduledTick; } @Override public void schedule(ScheduledTick tick) { if (this.ticksPerPosition.add(tick)) { this.scheduleUnchecked(tick); } } private void scheduleUnchecked(ScheduledTick tick) { this.tickQueue.add(tick); if (this.onTickAdded != null) { this.onTickAdded.accept(this, tick); } } @Override public boolean hasScheduledTick(BlockPos pos, T type) { return this.ticksPerPosition.contains(ScheduledTick.probe(type, pos)); } public void removeIf(Predicate> predicate) { Iterator> iterator = this.tickQueue.iterator(); while (iterator.hasNext()) { ScheduledTick scheduledTick = (ScheduledTick)iterator.next(); if (predicate.test(scheduledTick)) { iterator.remove(); this.ticksPerPosition.remove(scheduledTick); } } } public Stream> getAll() { return this.tickQueue.stream(); } @Override public int count() { return this.tickQueue.size() + (this.pendingTicks != null ? this.pendingTicks.size() : 0); } public ListTag save(long gameTime, Function idGetter) { ListTag listTag = new ListTag(); if (this.pendingTicks != null) { for (SavedTick savedTick : this.pendingTicks) { listTag.add(savedTick.save(idGetter)); } } for (ScheduledTick scheduledTick : this.tickQueue) { listTag.add(SavedTick.saveTick(scheduledTick, idGetter, gameTime)); } return listTag; } public void unpack(long gameTime) { if (this.pendingTicks != null) { int i = -this.pendingTicks.size(); for (SavedTick savedTick : this.pendingTicks) { this.scheduleUnchecked(savedTick.unpack(gameTime, i++)); } } this.pendingTicks = null; } public static LevelChunkTicks load(ListTag tag, Function> isParser, ChunkPos pos) { Builder> builder = ImmutableList.builder(); SavedTick.loadTickList(tag, isParser, pos, builder::add); return new LevelChunkTicks<>(builder.build()); } }