minecraft-src/net/minecraft/world/level/timers/TimerQueue.java
2025-07-04 03:45:38 +03:00

124 lines
4.1 KiB
Java

package net.minecraft.world.level.timers;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.google.common.primitives.UnsignedLong;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.Dynamic;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Set;
import java.util.stream.Stream;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag;
import org.slf4j.Logger;
public class TimerQueue<T> {
private static final Logger LOGGER = LogUtils.getLogger();
private static final String CALLBACK_DATA_TAG = "Callback";
private static final String TIMER_NAME_TAG = "Name";
private static final String TIMER_TRIGGER_TIME_TAG = "TriggerTime";
private final TimerCallbacks<T> callbacksRegistry;
private final Queue<TimerQueue.Event<T>> queue = new PriorityQueue(createComparator());
private UnsignedLong sequentialId = UnsignedLong.ZERO;
private final Table<String, Long, TimerQueue.Event<T>> events = HashBasedTable.create();
private static <T> Comparator<TimerQueue.Event<T>> createComparator() {
return Comparator.comparingLong(event -> event.triggerTime).thenComparing(event -> event.sequentialId);
}
public TimerQueue(TimerCallbacks<T> callbacksRegistry, Stream<? extends Dynamic<?>> scheduledEventsDynamic) {
this(callbacksRegistry);
this.queue.clear();
this.events.clear();
this.sequentialId = UnsignedLong.ZERO;
scheduledEventsDynamic.forEach(dynamic -> {
Tag tag = dynamic.convert(NbtOps.INSTANCE).getValue();
if (tag instanceof CompoundTag compoundTag) {
this.loadEvent(compoundTag);
} else {
LOGGER.warn("Invalid format of events: {}", tag);
}
});
}
public TimerQueue(TimerCallbacks<T> callbacksRegistry) {
this.callbacksRegistry = callbacksRegistry;
}
public void tick(T obj, long gameTime) {
while (true) {
TimerQueue.Event<T> event = (TimerQueue.Event<T>)this.queue.peek();
if (event == null || event.triggerTime > gameTime) {
return;
}
this.queue.remove();
this.events.remove(event.id, gameTime);
event.callback.handle(obj, this, gameTime);
}
}
public void schedule(String id, long triggerTime, TimerCallback<T> callback) {
if (!this.events.contains(id, triggerTime)) {
this.sequentialId = this.sequentialId.plus(UnsignedLong.ONE);
TimerQueue.Event<T> event = new TimerQueue.Event<>(triggerTime, this.sequentialId, id, callback);
this.events.put(id, triggerTime, event);
this.queue.add(event);
}
}
public int remove(String eventId) {
Collection<TimerQueue.Event<T>> collection = this.events.row(eventId).values();
collection.forEach(this.queue::remove);
int i = collection.size();
collection.clear();
return i;
}
public Set<String> getEventsIds() {
return Collections.unmodifiableSet(this.events.rowKeySet());
}
private void loadEvent(CompoundTag tag) {
TimerCallback<T> timerCallback = (TimerCallback<T>)tag.read("Callback", this.callbacksRegistry.codec()).orElse(null);
if (timerCallback != null) {
String string = tag.getStringOr("Name", "");
long l = tag.getLongOr("TriggerTime", 0L);
this.schedule(string, l, timerCallback);
}
}
private CompoundTag storeEvent(TimerQueue.Event<T> event) {
CompoundTag compoundTag = new CompoundTag();
compoundTag.putString("Name", event.id);
compoundTag.putLong("TriggerTime", event.triggerTime);
compoundTag.store("Callback", this.callbacksRegistry.codec(), event.callback);
return compoundTag;
}
public ListTag store() {
ListTag listTag = new ListTag();
this.queue.stream().sorted(createComparator()).map(this::storeEvent).forEach(listTag::add);
return listTag;
}
public static class Event<T> {
public final long triggerTime;
public final UnsignedLong sequentialId;
public final String id;
public final TimerCallback<T> callback;
Event(long triggerTime, UnsignedLong sequentialId, String id, TimerCallback<T> callback) {
this.triggerTime = triggerTime;
this.sequentialId = sequentialId;
this.id = id;
this.callback = callback;
}
}
}