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.services.plots; 020 021import cloud.commandframework.services.types.Service; 022import com.google.common.cache.Cache; 023import com.google.common.cache.CacheBuilder; 024import com.plotsquared.core.plot.Plot; 025import com.plotsquared.core.plot.PlotAreaType; 026import com.plotsquared.core.plot.PlotId; 027import org.checkerframework.checker.nullness.qual.NonNull; 028import org.checkerframework.checker.nullness.qual.Nullable; 029 030import java.util.Collections; 031import java.util.List; 032import java.util.concurrent.TimeUnit; 033import java.util.function.Predicate; 034 035public interface AutoService extends Service<AutoQuery, List<Plot>> { 036 037 Cache<PlotId, Plot> plotCandidateCache = CacheBuilder.newBuilder() 038 .expireAfterWrite(20, TimeUnit.SECONDS).build(); 039 Object plotLock = new Object(); 040 041 final class DefaultAutoService implements AutoService { 042 043 @Override 044 public List<Plot> handle(final @NonNull AutoQuery autoQuery) { 045 return Collections.emptyList(); 046 } 047 048 } 049 050 final class SinglePlotService implements AutoService, Predicate<AutoQuery> { 051 052 @Nullable 053 @Override 054 public List<Plot> handle(@NonNull AutoQuery autoQuery) { 055 Plot plot; 056 PlotId nextId = autoQuery.startId(); 057 do { 058 synchronized (plotLock) { 059 plot = autoQuery.plotArea().getNextFreePlot(autoQuery.player(), nextId); 060 if (plot != null && plotCandidateCache.getIfPresent(plot.getId()) == null) { 061 plotCandidateCache.put(plot.getId(), plot); 062 return Collections.singletonList(plot); 063 } 064 // if the plot is already in the cache, we want to make sure we skip it the next time 065 if (plot != null) { 066 nextId = plot.getId(); 067 } 068 } 069 } while (plot != null); 070 return null; 071 } 072 073 @Override 074 public boolean test(final @NonNull AutoQuery autoQuery) { 075 return autoQuery.sizeX() == 1 && autoQuery.sizeZ() == 1; 076 } 077 078 } 079 080 final class MultiPlotService implements AutoService, Predicate<AutoQuery> { 081 082 @Override 083 public List<Plot> handle(final @NonNull AutoQuery autoQuery) { 084 /* TODO: Add timeout? */ 085 outer: 086 while (true) { 087 synchronized (plotLock) { 088 final PlotId start = 089 autoQuery.plotArea().getMeta("lastPlot", PlotId.of(0, 0)).getNextId(); 090 final PlotId end = PlotId.of( 091 start.getX() + autoQuery.sizeX() - 1, 092 start.getY() + autoQuery.sizeZ() - 1 093 ); 094 final List<Plot> plots = 095 autoQuery.plotArea().canClaim(autoQuery.player(), start, end); 096 autoQuery.plotArea().setMeta("lastPlot", start); // set entry point for next try 097 if (plots != null && !plots.isEmpty()) { 098 for (final Plot plot : plots) { 099 if (plotCandidateCache.getIfPresent(plot.getId()) != null) { 100 continue outer; 101 } 102 plotCandidateCache.put(plot.getId(), plot); 103 } 104 return plots; 105 } 106 } 107 } 108 } 109 110 @Override 111 public boolean test(final @NonNull AutoQuery autoQuery) { 112 return autoQuery.plotArea().getType() != PlotAreaType.PARTIAL; 113 } 114 115 } 116 117}