<commit_before>package de.craften.plugins.rpgplus.components.timer;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import de.craften.plugins.rpgplus.util.components.PluginComponentBase;
import org.bukkit.Bukkit;
import org.bukkit.World;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * A component that provides a timing API.
 */
public class TimerComponent extends PluginComponentBase {
    private Multimap<String, Timer> callbacks = ArrayListMultimap.create();
    private Map<String, Long> lastTimes = new HashMap<>();
    private int id = 0;

    @Override
    protected void onActivated() {
        runTaskTimer(new Runnable() {
            @Override
            public void run() {
                tick();
            }
        }, 0, 1);
    }

    /**
     * Invokes all registered callbacks, if needed. If the world's time is earlier than the world time of the last
     * call of tick, all handlers between these two times are invoked.
     */
    protected void tick() {
        for (Map.Entry<String, Collection<Timer>> worldEntry : callbacks.asMap().entrySet()) {
            World world = getServer().getWorld(worldEntry.getKey());
            long lastTime = getLastTime(world);
            long now = world.getTime();

            if (now < lastTime) {
                for (long time = lastTime; time < 24_000; time++) {
                    for (Timer timer : worldEntry.getValue()) {
                        if (timer.time == time) {
                            timer.callback.run();
                        }
                    }
                }
                for (long time = 0; time <= now; time++) {
                    for (Timer timer : worldEntry.getValue()) {
                        if (timer.time == time) {
                            timer.callback.run();
                        }
                    }
                }
            } else {
                for (long time = lastTime; time <= now; time++) {
                    for (Timer timer : worldEntry.getValue()) {
                        if (timer.time == time) {
                            timer.callback.run();
                        }
                    }
                }
            }
            this.lastTimes.put(world.getName(), world.getTime());
        }
    }

    private long getLastTime(World world) {
        Long lastTick = this.lastTimes.get(world.getName());
        if (lastTick != null) {
            return lastTick;
        }
        return world.getTime();
    }

    /**
     * Adds the given time-based callback.
     *
     * @param world    world
     * @param time     time to call this handler (0..23999)<commit_msg>Fix handling of skipped ticks, resolves #15.<commit_after>package de.craften.plugins.rpgplus.components.timer;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import de.craften.plugins.rpgplus.util.components.PluginComponentBase;
import org.bukkit.World;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * A component that provides a timing API.
 */
public class TimerComponent extends PluginComponentBase {
    private Multimap<String, Timer> callbacks = ArrayListMultimap.create();
    private Map<String, Long> skippedTimeStarts = new HashMap<>(); //contains the first tick that was not yet processes for a world
    private int id = 0;

    @Override
    protected void onActivated() {
        runTaskTimer(new Runnable() {
            @Override
            public void run() {
                tick();
            }
        }, 0, 1);
    }

    /**
     * Invokes all registered callbacks, if needed. If the world's time is earlier than the world time of the last
     * call of tick, all handlers between these two times are invoked.
     */
    protected void tick() {
        for (Map.Entry<String, Collection<Timer>> worldEntry : callbacks.asMap().entrySet()) {
            World world = getServer().getWorld(worldEntry.getKey());
            long firstSkippedTime = firstSkippedTime(world);
            long now = world.getTime();

            if (now < firstSkippedTime) {
                for (long time = firstSkippedTime; time < 24_000; time++) {
                    for (Timer timer : worldEntry.getValue()) {
                        if (timer.time == time) {
                            timer.callback.run();
                        }
                    }
                }
                for (long time = 0; time <= now; time++) {
                    for (Timer timer : worldEntry.getValue()) {
                        if (timer.time == time) {
                            timer.callback.run();
                        }
                    }
                }
            } else {
                for (long time = firstSkippedTime; time <= now; time++) {
                    for (Timer timer : worldEntry.getValue()) {
                        if (timer.time == time) {
                            timer.callback.run();
                        }
                    }
                }
            }
            this.skippedTimeStarts.put(world.getName(), world.getTime() + 1);
        }
    }

    private long firstSkippedTime(World world) {
        Long lastTick = this.skippedTimeStarts.get(world.getName());
        if (lastTick != null) {
            return lastTick;
        }
        return world.getTime();
    }

    /**
     * Adds the given time-based callback.
     *
     * @param world    world
     * @param time     time to call this handler (0..23999)
{'fraction_non_alphanumeric': 0.10491861288039632, 'fraction_numerical': 0.00583864118895966, 'mean_word_length': 1.58363802559415, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6723242', 'n_tokens_mistral': 1509, 'n_tokens_neox': 1427, 'n_words': 392}