minecraft-source/src/net/minecraft/world/level/ServerTickList.java

206 lines
8.5 KiB
Java

package net.minecraft.world.level;
import java.util.AbstractList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.core.Vec3i;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Collection;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import java.util.stream.Stream;
import net.minecraft.core.BlockPos;
import java.util.Iterator;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.ReportedException;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.CrashReportCategory;
import net.minecraft.CrashReport;
import com.google.common.collect.Lists;
import com.google.common.collect.Queues;
import java.util.Comparator;
import com.google.common.collect.Sets;
import java.util.function.Consumer;
import java.util.List;
import java.util.Queue;
import net.minecraft.server.level.ServerLevel;
import java.util.TreeSet;
import java.util.Set;
import net.minecraft.resources.ResourceLocation;
import java.util.function.Function;
import java.util.function.Predicate;
public class ServerTickList<T> implements TickList<T> {
protected final Predicate<T> ignore;
private final Function<T, ResourceLocation> toId;
private final Function<ResourceLocation, T> fromId;
private final Set<TickNextTickData<T>> tickNextTickSet;
private final TreeSet<TickNextTickData<T>> tickNextTickList;
private final ServerLevel level;
private final Queue<TickNextTickData<T>> currentlyTicking;
private final List<TickNextTickData<T>> alreadyTicked;
private final Consumer<TickNextTickData<T>> ticker;
public ServerTickList(final ServerLevel xd, final Predicate<T> predicate, final Function<T, ResourceLocation> function3, final Function<ResourceLocation, T> function4, final Consumer<TickNextTickData<T>> consumer) {
this.tickNextTickSet = Sets.newHashSet();
this.tickNextTickList = Sets.<TickNextTickData<T>>newTreeSet(TickNextTickData.createTimeComparator());
this.currentlyTicking = Queues.newArrayDeque();
this.alreadyTicked = Lists.newArrayList();
this.ignore = predicate;
this.toId = function3;
this.fromId = function4;
this.level = xd;
this.ticker = consumer;
}
public void tick() {
int integer2 = this.tickNextTickList.size();
if (integer2 != this.tickNextTickSet.size()) {
throw new IllegalStateException("TickNextTick list out of synch");
}
if (integer2 > 65536) {
integer2 = 65536;
}
final ServerChunkCache xb3 = this.level.getChunkSource();
final Iterator<TickNextTickData<T>> iterator4 = this.tickNextTickList.iterator();
this.level.getProfiler().push("cleaning");
while (integer2 > 0 && iterator4.hasNext()) {
final TickNextTickData<T> bkj5 = iterator4.next();
if (bkj5.delay > this.level.getGameTime()) {
break;
}
if (!xb3.isTickingChunk(bkj5.pos)) {
continue;
}
iterator4.remove();
this.tickNextTickSet.remove(bkj5);
this.currentlyTicking.add(bkj5);
--integer2;
}
this.level.getProfiler().popPush("ticking");
TickNextTickData<T> bkj5;
while ((bkj5 = this.currentlyTicking.poll()) != null) {
if (xb3.isTickingChunk(bkj5.pos)) {
try {
this.alreadyTicked.add(bkj5);
this.ticker.accept(bkj5);
continue;
}
catch (Throwable throwable6) {
final CrashReport h7 = CrashReport.forThrowable(throwable6, "Exception while ticking");
final CrashReportCategory i8 = h7.addCategory("Block being ticked");
CrashReportCategory.populateBlockDetails(i8, bkj5.pos, null);
throw new ReportedException(h7);
}
}
this.scheduleTick(bkj5.pos, bkj5.getType(), 0);
}
this.level.getProfiler().pop();
this.alreadyTicked.clear();
this.currentlyTicking.clear();
}
@Override
public boolean willTickThisTick(final BlockPos fk, final T object) {
return this.currentlyTicking.contains(new TickNextTickData(fk, object));
}
@Override
public void addAll(final Stream<TickNextTickData<T>> stream) {
stream.forEach(this::addTickData);
}
public List<TickNextTickData<T>> fetchTicksInChunk(final ChunkPos bje, final boolean boolean2, final boolean boolean3) {
final int integer5 = (bje.x << 4) - 2;
final int integer6 = integer5 + 16 + 2;
final int integer7 = (bje.z << 4) - 2;
final int integer8 = integer7 + 16 + 2;
return this.fetchTicksInArea(new BoundingBox(integer5, 0, integer7, integer6, 256, integer8), boolean2, boolean3);
}
public List<TickNextTickData<T>> fetchTicksInArea(final BoundingBox cky, final boolean boolean2, final boolean boolean3) {
List<TickNextTickData<T>> list5 = this.fetchTicksInArea(null, this.tickNextTickList, cky, boolean2);
if (boolean2 && list5 != null) {
this.tickNextTickSet.removeAll(list5);
}
list5 = this.fetchTicksInArea(list5, this.currentlyTicking, cky, boolean2);
if (!boolean3) {
list5 = this.fetchTicksInArea(list5, this.alreadyTicked, cky, boolean2);
}
return (list5 == null) ? Collections.<TickNextTickData<T>>emptyList() : list5;
}
@Nullable
private List<TickNextTickData<T>> fetchTicksInArea(@Nullable List<TickNextTickData<T>> list, final Collection<TickNextTickData<T>> collection, final BoundingBox cky, final boolean boolean4) {
final Iterator<TickNextTickData<T>> iterator6 = collection.iterator();
while (iterator6.hasNext()) {
final TickNextTickData<T> bkj7 = iterator6.next();
final BlockPos fk8 = bkj7.pos;
if (fk8.getX() >= cky.x0 && fk8.getX() < cky.x1 && fk8.getZ() >= cky.z0 && fk8.getZ() < cky.z1) {
if (boolean4) {
iterator6.remove();
}
if (list == null) {
list = Lists.newArrayList();
}
list.add(bkj7);
}
}
return list;
}
public void copy(final BoundingBox cky, final BlockPos fk) {
final List<TickNextTickData<T>> list4 = this.fetchTicksInArea(cky, false, false);
for (final TickNextTickData<T> bkj6 : list4) {
if (cky.isInside(bkj6.pos)) {
final BlockPos fk2 = bkj6.pos.offset(fk);
final T object8 = bkj6.getType();
this.addTickData(new TickNextTickData<T>(fk2, object8, bkj6.delay, bkj6.priority));
}
}
}
public ListTag save(final ChunkPos bje) {
final List<TickNextTickData<T>> list3 = this.fetchTicksInChunk(bje, false, true);
return ServerTickList.<T>saveTickList(this.toId, list3, this.level.getGameTime());
}
public static <T> ListTag saveTickList(final Function<T, ResourceLocation> function, final Iterable<TickNextTickData<T>> iterable, final long long3) {
final ListTag jz5 = new ListTag();
for (final TickNextTickData<T> bkj7 : iterable) {
final CompoundTag jt8 = new CompoundTag();
jt8.putString("i", function.apply(bkj7.getType()).toString());
jt8.putInt("x", bkj7.pos.getX());
jt8.putInt("y", bkj7.pos.getY());
jt8.putInt("z", bkj7.pos.getZ());
jt8.putInt("t", (int)(bkj7.delay - long3));
jt8.putInt("p", bkj7.priority.getValue());
((AbstractList<CompoundTag>)jz5).add(jt8);
}
return jz5;
}
@Override
public boolean hasScheduledTick(final BlockPos fk, final T object) {
return this.tickNextTickSet.contains(new TickNextTickData(fk, object));
}
@Override
public void scheduleTick(final BlockPos fk, final T object, final int integer, final TickPriority bkk) {
if (!this.ignore.test(object)) {
this.addTickData(new TickNextTickData<T>(fk, object, integer + this.level.getGameTime(), bkk));
}
}
private void addTickData(final TickNextTickData<T> bkj) {
if (!this.tickNextTickSet.contains(bkj)) {
this.tickNextTickSet.add(bkj);
this.tickNextTickList.add(bkj);
}
}
public int size() {
return this.tickNextTickSet.size();
}
}