Rewrite the tick queue to be slightly more robust and not trigger actions for worlds they weren't intended to run in

This commit is contained in:
Sollace 2020-05-29 20:20:50 +02:00
parent 848f6ef66d
commit b4443e0549
4 changed files with 37 additions and 48 deletions

View file

@ -1,44 +1,55 @@
package com.minelittlepony.unicopia;
import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import com.google.common.collect.Lists;
import com.google.common.collect.Queues;
import net.minecraft.world.World;
public class AwaitTickQueue {
private static final Queue<Consumer<World>> SCHEDULED_TASKS = Queues.newArrayDeque();
private static List<DelayedTask> DELAYED_TASKS = Lists.newArrayList();
private static final Object LOCKER = new Object();
private static List<Entry> PENDING_TASKS = new ArrayList<>();
public static void enqueueTask(Consumer<World> task) {
public static void scheduleTask(World reference, Consumer<World> task, int ticksLater) {
if (!reference.isClient) {
synchronized (LOCKER) {
SCHEDULED_TASKS.add(task);
PENDING_TASKS.add(new Entry(reference, task, ticksLater));
}
}
public static void scheduleTask(Consumer<World> task, int ticksLater) {
synchronized (LOCKER) {
DELAYED_TASKS.add(new DelayedTask(task, ticksLater));
}
}
static void tick(World world) {
if (world.isClient) {
return;
if (!world.isClient) {
synchronized (LOCKER) {
final Queue<Entry> tasks = new ArrayDeque<>();
PENDING_TASKS = PENDING_TASKS.stream().filter(e -> e.tick(world, tasks)).collect(Collectors.toList());
tasks.forEach(e -> e.run(world));
}
}
}
synchronized (LOCKER) {
DELAYED_TASKS = DELAYED_TASKS.stream().filter(DelayedTask::tick).collect(Collectors.toList());
private static final class Entry {
private final Consumer<World> task;
private final WeakReference<World> world;
private int ticks;
Consumer<World> task;
while ((task = SCHEDULED_TASKS.poll()) != null) {
Entry(World world, Consumer<World> task, int ticks) {
this.world = new WeakReference<>(world);
this.task = task;
this.ticks = ticks;
}
boolean tick(World world, Queue<Entry> tasks) {
World w = this.world.get();
return w != null && (w != world || ticks-- > 0 || !tasks.add(this));
}
void run(World world) {
if (this.world.get() == world) {
try {
task.accept(world);
} catch (Exception e) {
@ -47,26 +58,4 @@ public class AwaitTickQueue {
}
}
}
private static class DelayedTask {
final Consumer<World> task;
int ticksDelay;
DelayedTask(Consumer<World> task, int ticks) {
this.task = task;
this.ticksDelay = ticks;
}
boolean tick() {
if (ticksDelay-- <= 0) {
SCHEDULED_TASKS.add(task);
return false;
}
return true;
}
}
}

View file

@ -93,7 +93,7 @@ public class SpellBookContainer extends Container {
worldObj.createExplosion(null, player.getX(), player.getY(), player.getZ(), 0, DestructionType.NONE);
worldObj.addParticle(ParticleTypes.EXPLOSION, player.getX(), player.getY(), player.getZ(), 1, 0, 0);
AwaitTickQueue.enqueueTask(w -> player.container.close(player));
AwaitTickQueue.scheduleTask(player.world, w -> player.container.close(player), 0);
return;
}

View file

@ -234,7 +234,7 @@ public class AlicornAmuletItem extends ArmorItem implements AddictiveMagicitem,
player.world.createExplosion(player, pos.x, pos.y, pos.z, 10, DestructionType.NONE);
AwaitTickQueue.scheduleTask(w -> {
AwaitTickQueue.scheduleTask(player.world, w -> {
w.createExplosion(player, pos.x, pos.y, pos.z, 6, DestructionType.BREAK);
}, 50);
}

View file

@ -146,11 +146,11 @@ public interface Caster<E extends LivingEntity> extends Owned<E>, Levelled, Affi
}
default void notifyNearbySpells(Spell sender, BlockPos origin, double radius, int newState) {
AwaitTickQueue.enqueueTask(w -> {
AwaitTickQueue.scheduleTask(getWorld(), w -> {
VecHelper.findAllEntitiesInRange(getEntity(), getWorld(), origin, radius)
.filter(i -> i instanceof EtherialListener)
.forEach(i -> ((EtherialListener)i).onNearbySpellChange(this, sender, newState));
});
}, 0);
}
default void notifyNearbySpells(Spell sender, double radius, int newState) {