206 lines
8.5 KiB
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();
|
|
}
|
|
}
|