package com.comphenix.xp.history; import java.util.Comparator; import java.util.SortedSet; import java.util.TreeSet; import org.bukkit.Location; import com.comphenix.xp.Debugger; import com.comphenix.xp.extra.ServiceProvider; /** * Registry of history (block change logging) providers. * <p> * The default service setting is ignored. * @author Kristian */ public class HistoryProviders extends ServiceProvider<HistoryService> { /** * Services sorted by lookup speed. */ protected transient SortedSet<HistoryService> speedOrder = new TreeSet<HistoryService>(new Comparator<HistoryService>() { public int compare(HistoryService o1, HistoryService o2) { return o1.getLookupSpeed().compareTo(o2.getLookupSpeed()); } }); public HistoryProviders() { super(LogBlockService.NAME); } public MemoryService getMemoryService() { return (MemoryService) getByName(MemoryService.NAME); } /** * Determines whether or not a block has been placed by a player, using the registered service providers * in order of lookup speed. * <p> * If no service provider could accurately answer the query, the function returns NULL. * * @param block - block to search for. * @param acceptGuesses - whether or not probabilistic answers are acceptable. * @param debugger - debugger that handles errors produced by any history service. * @return TRUE if the block was placed by a player, FALSE if it was generated naturally, or NULL if unknown. */ public Boolean hasPlayerHistory(Location block, boolean acceptGuesses, final Debugger debugger) { // Add a reasonable error handler return hasPlayerHistory(block, acceptGuesses, new ErrorHandler<Exception>() { @Override public void onError(Exception error) { error.printStackTrace(); } }); } /** * Determines whether or not a block has been placed by a player, using the registered service providers * in order of lookup speed. * <p> * If no service provider could accurately answer the query, the function returns NULL. * * @param block - block to search for. * @param acceptGuesses - whether or not probabilistic answers are acceptable. * @param errorHandler - reports errors from individual history services. * @return TRUE if the block was placed by a player, FALSE if it was generated naturally, or NULL if unknown. */ public Boolean hasPlayerHistory(Location block, boolean acceptGuesses, ErrorHandler<Exception> errorHandler) { Boolean current = null; for (HistoryService service : speedOrder) { Boolean answer = null; try { if (isEnabled(service)) answer = service.hasPlayerHistory(block); } catch (Exception e) { if (errorHandler != null) errorHandler.onError(e); } // Skip if no answer was provided if (answer != null) { // Record the last answer current = answer; // Early answers! if (current && !service.hasFalsePositives()) return true; else if (!current && !service.hasFalseNegatives()) return false; } } // If we're at this point, it must be because the last answer was probabilistic. if (acceptGuesses && current != null) { return current; } else { return null; } } @Override public HistoryService register(HistoryService service) { HistoryService removed = super.register(service); speedOrder.add(service); // Removed overridden service if (removed != null) { speedOrder.remove(removed); } return removed; } @Override public HistoryService unregister(HistoryService service) { HistoryService removed = super.unregister(service); // Clean up if (removed != null) speedOrder.remove(removed); return removed; } }