001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.core.plot.expiration; 020 021import com.plotsquared.core.PlotSquared; 022import com.plotsquared.core.configuration.Settings; 023import com.plotsquared.core.plot.Plot; 024import com.plotsquared.core.plot.PlotArea; 025import com.plotsquared.core.plot.world.PlotAreaManager; 026import com.plotsquared.core.util.query.PlotQuery; 027import org.checkerframework.checker.nullness.qual.NonNull; 028 029import java.util.ArrayList; 030import java.util.Collection; 031import java.util.Collections; 032import java.util.LinkedList; 033import java.util.List; 034import java.util.Set; 035import java.util.concurrent.TimeUnit; 036import java.util.stream.Collectors; 037 038public class ExpiryTask { 039 040 private final Settings.Auto_Clear settings; 041 private final PlotAreaManager plotAreaManager; 042 private long cutoffThreshold = Long.MIN_VALUE; 043 044 public ExpiryTask(final Settings.Auto_Clear settings, final @NonNull PlotAreaManager plotAreaManager) { 045 this.settings = settings; 046 this.plotAreaManager = plotAreaManager; 047 } 048 049 public Settings.Auto_Clear getSettings() { 050 return settings; 051 } 052 053 public boolean allowsArea(PlotArea area) { 054 return settings.WORLDS.contains(area.toString()) || settings.WORLDS 055 .contains(area.getWorldName()) || settings.WORLDS.contains("*"); 056 } 057 058 public boolean applies(PlotArea area) { 059 if (allowsArea(area)) { 060 if (settings.REQUIRED_PLOTS <= 0) { 061 return true; 062 } 063 Set<Plot> plots = null; 064 if (cutoffThreshold != Long.MAX_VALUE 065 && area.getPlots().size() > settings.REQUIRED_PLOTS 066 || (plots = getPlotsToCheck()).size() > settings.REQUIRED_PLOTS) { 067 // calculate cutoff 068 if (cutoffThreshold == Long.MIN_VALUE) { 069 plots = plots != null ? plots : getPlotsToCheck(); 070 int diff = settings.REQUIRED_PLOTS; 071 boolean min = true; 072 if (plots.size() > settings.REQUIRED_PLOTS) { 073 min = false; 074 diff = plots.size() - settings.REQUIRED_PLOTS; 075 } 076 ExpireManager expireManager = PlotSquared.platform().expireManager(); 077 List<Long> entireList = 078 plots.stream().map(plot -> expireManager.getAge(plot, settings.DELETE_IF_OWNER_IS_UNKNOWN)) 079 .collect(Collectors.toList()); 080 List<Long> top = new ArrayList<>(diff + 1); 081 if (diff > 1000) { 082 Collections.sort(entireList); 083 cutoffThreshold = entireList.get(settings.REQUIRED_PLOTS); 084 } else { 085 loop: 086 for (long num : entireList) { 087 int size = top.size(); 088 if (size == 0) { 089 top.add(num); 090 continue; 091 } 092 long end = top.get(size - 1); 093 if (min ? num < end : num > end) { 094 for (int i = 0; i < size; i++) { 095 long existing = top.get(i); 096 if (min ? num < existing : num > existing) { 097 top.add(i, num); 098 if (size == diff) { 099 top.remove(size); 100 } 101 continue loop; 102 } 103 } 104 } 105 if (size < diff) { 106 top.add(num); 107 } 108 } 109 cutoffThreshold = top.get(top.size() - 1); 110 } 111 // Add half a day, as expiry is performed each day 112 cutoffThreshold += (TimeUnit.DAYS.toMillis(1) / 2); 113 } 114 return true; 115 } else { 116 cutoffThreshold = Long.MAX_VALUE; 117 } 118 } 119 return false; 120 } 121 122 public Set<Plot> getPlotsToCheck() { 123 final Collection<PlotArea> areas = new LinkedList<>(); 124 for (final PlotArea plotArea : this.plotAreaManager.getAllPlotAreas()) { 125 if (this.allowsArea(plotArea)) { 126 areas.add(plotArea); 127 } 128 } 129 return PlotQuery.newQuery().inAreas(areas).asSet(); 130 } 131 132 public boolean applies(long diff) { 133 return diff > TimeUnit.DAYS.toMillis(settings.DAYS) && diff > cutoffThreshold; 134 } 135 136 public boolean appliesAccountAge(long accountAge) { 137 if (settings.SKIP_ACCOUNT_AGE_DAYS != -1) { 138 return accountAge <= TimeUnit.DAYS.toMillis(settings.SKIP_ACCOUNT_AGE_DAYS); 139 } 140 return false; 141 } 142 143 public boolean needsAnalysis() { 144 return settings.THRESHOLD > 0; 145 } 146 147 public boolean applies(PlotAnalysis analysis) { 148 return analysis.getComplexity(settings) <= settings.THRESHOLD; 149 } 150 151 public boolean requiresConfirmation() { 152 return settings.CONFIRMATION; 153 } 154 155 /** 156 * Returns {@code true} if this task respects unknown owners 157 * 158 * @return {@code true} if unknown owners should be counted as never online 159 * @since 6.4.0 160 */ 161 public boolean shouldDeleteForUnknownOwner() { 162 return settings.DELETE_IF_OWNER_IS_UNKNOWN; 163 } 164 165}