Package ch.njol.skript.events

Source Code of ch.njol.skript.events.EvtAtTime$EvtAtInfo

/*
*   This file is part of Skript.
*
*  Skript is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  Skript is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with Skript.  If not, see <http://www.gnu.org/licenses/>.
*
*
* Copyright 2011-2014 Peter Güttinger
*
*/

package ch.njol.skript.events;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.event.Event;
import org.eclipse.jdt.annotation.Nullable;

import ch.njol.skript.Skript;
import ch.njol.skript.SkriptEventHandler;
import ch.njol.skript.events.bukkit.ScheduledEvent;
import ch.njol.skript.lang.Literal;
import ch.njol.skript.lang.SelfRegisteringSkriptEvent;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.lang.Trigger;
import ch.njol.skript.registrations.Classes;
import ch.njol.skript.util.Time;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

/**
* @author Peter Güttinger
*/
@SuppressFBWarnings("EQ_COMPARETO_USE_OBJECT_EQUALS")
public class EvtAtTime extends SelfRegisteringSkriptEvent implements Comparable<EvtAtTime> {
  static {
    Skript.registerEvent("*At Time", EvtAtTime.class, ScheduledEvent.class, "at %time% [in %worlds%]")
        .description("An event that occurs at a given <a href='../classes/#time'>minecraft time</a> in every world or only in specific worlds.")
        .examples("at 18:00", "at 7am in \"world\"")
        .since("1.3.4");
  }
 
  private final static int CHECKPERIOD = 10;
 
  private final static class EvtAtInfo {
    public EvtAtInfo() {}
   
    int lastTick; // as Bukkit's scheduler is inconsistent this saves the exact tick when the events were last checked
    int currentIndex;
    ArrayList<EvtAtTime> list = new ArrayList<EvtAtTime>();
  }
 
  final static HashMap<World, EvtAtInfo> triggers = new HashMap<World, EvtAtInfo>();
 
  @Nullable
  private Trigger t;
  int tick;
 
  @SuppressWarnings("null")
  private transient World[] worlds;
  /**
   * null if all worlds
   */
  @Nullable
  private String[] worldNames = null;
 
  @SuppressWarnings({"unchecked", "null"})
  @Override
  public boolean init(final Literal<?>[] args, final int matchedPattern, final ParseResult parser) {
    tick = ((Literal<Time>) args[0]).getSingle().getTicks();
    worlds = args[1] == null ? Bukkit.getWorlds().toArray(new World[0]) : ((Literal<World>) args[1]).getAll();
    if (args[1] != null) {
      worldNames = new String[worlds.length];
      for (int i = 0; i < worlds.length; i++)
        worldNames[i] = worlds[i].getName();
    }
    return true;
  }
 
  private static int taskID = -1;
 
  private static void registerListener() {
    if (taskID != -1)
      return;
    taskID = Bukkit.getScheduler().scheduleSyncRepeatingTask(Skript.getInstance(), new Runnable() {
      @SuppressWarnings("null")
      @Override
      public void run() {
        for (final Entry<World, EvtAtInfo> e : triggers.entrySet()) {
          final EvtAtInfo i = e.getValue();
          final int tick = (int) e.getKey().getTime();
          if (i.lastTick == tick) // stupid Bukkit scheduler
            continue;
          if (i.lastTick + CHECKPERIOD * 2 < tick || i.lastTick > tick && i.lastTick - 24000 + CHECKPERIOD * 2 < tick) { // time changed
            i.lastTick = tick - CHECKPERIOD;
            if (i.lastTick < 0)
              i.lastTick += 24000;
          }
          final boolean midnight = i.lastTick > tick;
          if (midnight)
            i.lastTick -= 24000;
          final int lastIndex = i.currentIndex;
          while (true) {
            final EvtAtTime next = i.list.get(i.currentIndex);
            final int nextTick = midnight && next.tick > 12000 ? next.tick - 24000 : next.tick;
            if (i.lastTick < nextTick && nextTick <= tick) {
              next.execute(e.getKey());
              i.currentIndex++;
              if (i.currentIndex == i.list.size())
                i.currentIndex = 0;
              if (i.currentIndex == lastIndex)
                break;
            } else {
              break;
            }
          }
          i.lastTick = tick;
        }
      }
    }, 0, CHECKPERIOD);
  }
 
  void execute(final World w) {
    final Trigger t = this.t;
    if (t == null) {
      assert false;
      return;
    }
    final ScheduledEvent e = new ScheduledEvent(w);
    SkriptEventHandler.logEventStart(e);
    SkriptEventHandler.logTriggerEnd(t);
    t.execute(e);
    SkriptEventHandler.logTriggerEnd(t);
    SkriptEventHandler.logEventEnd();
  }
 
  @SuppressWarnings("null")
  private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
    in.defaultReadObject();
    if (worldNames != null) {
      worlds = new World[worldNames.length];
      for (int i = 0; i < worlds.length; i++) {
        if ((worlds[i] = Bukkit.getWorld(worldNames[i])) == null)
          throw new IOException();
      }
    } else {
      worlds = Bukkit.getWorlds().toArray(new World[0]);
    }
  }
 
  @Override
  public void register(final Trigger t) {
    this.t = t;
    for (final World w : worlds) {
      EvtAtInfo i = triggers.get(w);
      if (i == null) {
        triggers.put(w, i = new EvtAtInfo());
        i.lastTick = (int) w.getTime() - 1;
      }
      i.list.add(this);
      Collections.sort(i.list);
    }
    registerListener();
  }
 
  @Override
  public void unregister(final Trigger t) {
    assert t == this.t;
    this.t = null;
    final Iterator<EvtAtInfo> iter = triggers.values().iterator();
    while (iter.hasNext()) {
      final EvtAtInfo i = iter.next();
      i.list.remove(this);
      if (i.list.isEmpty())
        iter.remove();
    }
    if (triggers.isEmpty())
      unregisterAll();
  }
 
  @Override
  public void unregisterAll() {
    if (taskID != -1)
      Bukkit.getScheduler().cancelTask(taskID);
    t = null;
    taskID = -1;
    triggers.clear();
  }
 
  @Override
  public String toString(final @Nullable Event e, final boolean debug) {
    return "at " + Time.toString(tick) + " in worlds " + Classes.toString(worlds, true);
  }
 
  @Override
  public int compareTo(final EvtAtTime e) {
    return tick - e.tick;
  }
 
}
TOP

Related Classes of ch.njol.skript.events.EvtAtTime$EvtAtInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.