[1.7+] - Scheduler

tox1cozZ

aka Agravaine
8,454
598
2,890
Нашел неплохой Scheduler, похожий на баккитовский.
https://github.com/diesieben07/Seve...take_weiland/mods/commons/util/Scheduler.java
Переписал под 1.7+ и убрал лишние Deprecated методы.
Код:
import static com.google.common.base.Preconditions.checkArgument;

import java.util.ArrayList;
import java.util.List;

import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
import net.minecraftforge.fml.common.gameevent.TickEvent.Type;
import net.minecraftforge.fml.relauncher.Side;

/**
 * @author diesieben07
 */
public final class Scheduler{

    private static Scheduler server;
    private static Scheduler client;

    /**
     * <p>Return a Scheduler that executes tasks on the main server thread.</p>
     * @return a Scheduler
     */
    public static Scheduler server(){
        return server;
    }

    /**
     * <p>The Scheduler that executes tasks on the main client thread. On a dedicated server this method will return null.</p>
     * @return a Scheduler or null
     */
    public static Scheduler client(){
        return client;
    }

    /**
     * <p>Return {@link #client()} if {@code side} is {@code Side.CLIENT}, {@link #server()} otherwise.</p>
     * @param side the side
     * @return a Scheduler for the side
     */
    public static Scheduler forSide(Side side){
        return side.isClient() ? client : server;
    }

    public void execute(Runnable task){
        schedule(task, 0);
    }

    /**
     * <p>Execute the given task after {@code tickDelay} ticks have passed.</p>
     * @param task the task
     * @param tickDelay the delay, in ticks
     */
    public void schedule(Runnable task, long tickDelay){
        checkArgument(tickDelay >= 0);
        synchronized(ticker.queue){
            ticker.queue.add(new Task(task, tickDelay + 1));
        }
    }

    static{
        if(FMLCommonHandler.instance().getSide().isClient()){
            client = new Scheduler(Side.CLIENT);
            FMLCommonHandler.instance().bus().register(client.ticker);
        }else{
            client = null;
        }

        server = new Scheduler(Side.SERVER);
        FMLCommonHandler.instance().bus().register(server.ticker);
    } 

    private final Ticker ticker;

    private Scheduler(Side side){
        ticker = new Ticker(side);
    }

    private static class Task{

        public final Runnable runnable;
        public long ticks;

        public Task(Runnable taskRunnable, long taskTicks){
            runnable = taskRunnable;
            ticks = taskTicks;
        }
    }

    private static class Ticker{

        private List<Task> queue = new ArrayList<Task>();
        private List<Task> scheduledNow = new ArrayList<Task>();

        private Side side;

        private Ticker(Side tickerSide){
            side = tickerSide;
        }

        @SubscribeEvent
        public void tick(TickEvent e){
            if(e.side == side && e.type == (side == Side.SERVER ? Type.SERVER : Type.CLIENT) && e.phase == Phase.START){
                synchronized(queue){
                    int idx = queue.size();
                    while(--idx >= 0){
                        Task task = queue.get(idx);
                        if(--task.ticks == 0){
                            queue.remove(idx);
                            scheduledNow.add(task);
                        }
                    }
                }

                int idx = scheduledNow.size();
                while(--idx >= 0){
                    scheduledNow.remove(idx).runnable.run();
                }
            }
        }
    }
}
Возможно кому-то понадобится.
 
1,990
18
105
Не очень хороший скедулер, если честно. Каждый тик проверка на запуск равная O(N). Можно ведь сделать O(1), если добавить переменную времени (в какой тик запускать), там переписать всего ничего.
Ах да, и хранить таски в ArrayList, тогда на один тик можно будет повесить кучу тасков, при этом не меняя количество проверок на запуск этого списка тасков.
 
Сверху