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.command; 020 021import com.google.inject.Inject; 022import com.plotsquared.core.configuration.Settings; 023import com.plotsquared.core.configuration.caption.TranslatableCaption; 024import com.plotsquared.core.database.DBFunc; 025import com.plotsquared.core.events.PlotRateEvent; 026import com.plotsquared.core.events.TeleportCause; 027import com.plotsquared.core.permissions.Permission; 028import com.plotsquared.core.player.PlotPlayer; 029import com.plotsquared.core.plot.Plot; 030import com.plotsquared.core.plot.PlotInventory; 031import com.plotsquared.core.plot.PlotItemStack; 032import com.plotsquared.core.plot.Rating; 033import com.plotsquared.core.plot.flag.implementations.DoneFlag; 034import com.plotsquared.core.util.EventDispatcher; 035import com.plotsquared.core.util.InventoryUtil; 036import com.plotsquared.core.util.MathMan; 037import com.plotsquared.core.util.TabCompletions; 038import com.plotsquared.core.util.query.PlotQuery; 039import com.plotsquared.core.util.task.TaskManager; 040import net.kyori.adventure.text.minimessage.Template; 041import org.checkerframework.checker.nullness.qual.NonNull; 042 043import java.util.Collection; 044import java.util.Collections; 045import java.util.HashMap; 046import java.util.LinkedList; 047import java.util.List; 048import java.util.Map.Entry; 049import java.util.UUID; 050import java.util.stream.Collectors; 051 052@CommandDeclaration(command = "rate", 053 permission = "plots.rate", 054 usage = "/plot rate [# | next | purge]", 055 aliases = "rt", 056 category = CommandCategory.INFO, 057 requiredType = RequiredType.PLAYER) 058public class Rate extends SubCommand { 059 060 private final EventDispatcher eventDispatcher; 061 private final InventoryUtil inventoryUtil; 062 063 @Inject 064 public Rate( 065 final @NonNull EventDispatcher eventDispatcher, 066 final @NonNull InventoryUtil inventoryUtil 067 ) { 068 this.eventDispatcher = eventDispatcher; 069 this.inventoryUtil = inventoryUtil; 070 } 071 072 @Override 073 public boolean onCommand(final PlotPlayer<?> player, String[] args) { 074 if (args.length == 1) { 075 switch (args[0].toLowerCase()) { 076 case "next" -> { 077 final List<Plot> plots = PlotQuery.newQuery().whereBasePlot().asList(); 078 plots.sort((p1, p2) -> { 079 double v1 = 0; 080 if (!p1.getRatings().isEmpty()) { 081 for (Entry<UUID, Rating> entry : p1.getRatings().entrySet()) { 082 v1 -= 11 - entry.getValue().getAverageRating(); 083 } 084 } 085 double v2 = 0; 086 if (!p2.getRatings().isEmpty()) { 087 for (Entry<UUID, Rating> entry : p2.getRatings().entrySet()) { 088 v2 -= 11 - entry.getValue().getAverageRating(); 089 } 090 } 091 if (v1 == v2) { 092 return -0; 093 } 094 return v2 > v1 ? 1 : -1; 095 }); 096 UUID uuid = player.getUUID(); 097 for (Plot p : plots) { 098 if ((!Settings.Done.REQUIRED_FOR_RATINGS || DoneFlag.isDone(p)) && p 099 .isBasePlot() && !p.getRatings().containsKey(uuid) && !p 100 .isAdded(uuid)) { 101 p.teleportPlayer(player, TeleportCause.COMMAND_RATE, result -> { 102 }); 103 player.sendMessage(TranslatableCaption.of("tutorial.rate_this")); 104 return true; 105 } 106 } 107 player.sendMessage(TranslatableCaption.of("invalid.found_no_plots")); 108 return false; 109 } 110 case "purge" -> { 111 final Plot plot = player.getCurrentPlot(); 112 if (plot == null) { 113 player.sendMessage(TranslatableCaption.of("errors.not_in_plot")); 114 return false; 115 } 116 if (!player.hasPermission(Permission.PERMISSION_ADMIN_COMMAND_PURGE_RATINGS, true)) { 117 return false; 118 } 119 plot.clearRatings(); 120 player.sendMessage(TranslatableCaption.of("ratings.ratings_purged")); 121 return true; 122 } 123 } 124 } 125 final Plot plot = player.getCurrentPlot(); 126 if (plot == null) { 127 player.sendMessage(TranslatableCaption.of("errors.not_in_plot")); 128 return false; 129 } 130 if (!plot.hasOwner()) { 131 player.sendMessage(TranslatableCaption.of("ratings.rating_not_owned")); 132 return false; 133 } 134 if (plot.isOwner(player.getUUID())) { 135 player.sendMessage(TranslatableCaption.of("ratings.rating_not_your_own")); 136 return false; 137 } 138 if (Settings.Done.REQUIRED_FOR_RATINGS && !DoneFlag.isDone(plot)) { 139 player.sendMessage(TranslatableCaption.of("ratings.rating_not_done")); 140 return false; 141 } 142 if (Settings.Ratings.CATEGORIES != null && !Settings.Ratings.CATEGORIES.isEmpty()) { 143 final Runnable run = new Runnable() { 144 @Override 145 public void run() { 146 if (plot.getRatings().containsKey(player.getUUID())) { 147 player.sendMessage( 148 TranslatableCaption.of("ratings.rating_already_exists"), 149 Template.of("plot", plot.getId().toString()) 150 ); 151 return; 152 } 153 final MutableInt index = new MutableInt(0); 154 final MutableInt rating = new MutableInt(0); 155 String title = Settings.Ratings.CATEGORIES.get(0); 156 PlotInventory inventory = new PlotInventory(inventoryUtil, player, 1, title) { 157 @Override 158 public boolean onClick(int i) { 159 rating.add((i + 1) * Math.pow(10, index.getValue())); 160 index.increment(); 161 if (index.getValue() >= Settings.Ratings.CATEGORIES.size()) { 162 int rV = rating.getValue(); 163 PlotRateEvent event = Rate.this.eventDispatcher 164 .callRating(this.getPlayer(), plot, new Rating(rV)); 165 if (event.getRating() != null) { 166 plot.addRating(this.getPlayer().getUUID(), event.getRating()); 167 getPlayer().sendMessage( 168 TranslatableCaption.of("ratings.rating_applied"), 169 Template.of("plot", plot.getId().toString()) 170 ); 171 } 172 return false; 173 } 174 setTitle(Settings.Ratings.CATEGORIES.get(index.getValue())); 175 return true; 176 } 177 }; 178 inventory.setItem(0, new PlotItemStack(Settings.Ratings.BLOCK_0, 1, 179 TranslatableCaption.of("ratings.0-8").getComponent(player) 180 )); 181 inventory.setItem(1, new PlotItemStack(Settings.Ratings.BLOCK_1, 1, 182 TranslatableCaption.of("ratings.1-8").getComponent(player) 183 )); 184 inventory.setItem(2, new PlotItemStack(Settings.Ratings.BLOCK_2, 2, 185 TranslatableCaption.of("ratings.2-8").getComponent(player) 186 )); 187 inventory.setItem(3, new PlotItemStack(Settings.Ratings.BLOCK_3, 3, 188 TranslatableCaption.of("ratings.3-8").getComponent(player) 189 )); 190 inventory.setItem(4, new PlotItemStack(Settings.Ratings.BLOCK_4, 4, 191 TranslatableCaption.of("ratings.4-8").getComponent(player) 192 )); 193 inventory.setItem(5, new PlotItemStack(Settings.Ratings.BLOCK_5, 5, 194 TranslatableCaption.of("ratings.5-8").getComponent(player) 195 )); 196 inventory.setItem(6, new PlotItemStack(Settings.Ratings.BLOCK_6, 6, 197 TranslatableCaption.of("ratings.6-8").getComponent(player) 198 )); 199 inventory.setItem(7, new PlotItemStack(Settings.Ratings.BLOCK_7, 7, 200 TranslatableCaption.of("ratings.7-8").getComponent(player) 201 )); 202 inventory.setItem(8, new PlotItemStack(Settings.Ratings.BLOCK_8, 8, 203 TranslatableCaption.of("ratings.8-8").getComponent(player) 204 )); 205 inventory.openInventory(); 206 } 207 }; 208 if (plot.getSettings().getRatings() == null) { 209 if (!Settings.Enabled_Components.RATING_CACHE) { 210 TaskManager.runTaskAsync(() -> { 211 plot.getSettings().setRatings(DBFunc.getRatings(plot)); 212 run.run(); 213 }); 214 return true; 215 } 216 plot.getSettings().setRatings(new HashMap<>()); 217 } 218 run.run(); 219 return true; 220 } 221 if (args.length < 1) { 222 player.sendMessage(TranslatableCaption.of("ratings.rating_not_valid")); 223 return true; 224 } 225 String arg = args[0]; 226 final int rating; 227 if (MathMan.isInteger(arg) && arg.length() < 3 && !arg.isEmpty()) { 228 rating = Integer.parseInt(arg); 229 if (rating > 10 || rating < 1) { 230 player.sendMessage(TranslatableCaption.of("ratings.rating_not_valid")); 231 return false; 232 } 233 } else { 234 player.sendMessage(TranslatableCaption.of("ratings.rating_not_valid")); 235 return false; 236 } 237 final UUID uuid = player.getUUID(); 238 final Runnable run = () -> { 239 if (plot.getRatings().containsKey(uuid)) { 240 player.sendMessage( 241 TranslatableCaption.of("ratings.rating_already_exists"), 242 Template.of("plot", plot.getId().toString()) 243 ); 244 return; 245 } 246 PlotRateEvent event = 247 this.eventDispatcher.callRating(player, plot, new Rating(rating)); 248 if (event.getRating() != null) { 249 plot.addRating(uuid, event.getRating()); 250 player.sendMessage( 251 TranslatableCaption.of("ratings.rating_applied"), 252 Template.of("plot", plot.getId().toString()) 253 ); 254 } 255 }; 256 if (plot.getSettings().getRatings() == null) { 257 if (!Settings.Enabled_Components.RATING_CACHE) { 258 TaskManager.runTaskAsync(() -> { 259 plot.getSettings().setRatings(DBFunc.getRatings(plot)); 260 run.run(); 261 }); 262 return true; 263 } 264 plot.getSettings().setRatings(new HashMap<>()); 265 } 266 run.run(); 267 return true; 268 } 269 270 @Override 271 public Collection<Command> tab(final PlotPlayer<?> player, final String[] args, final boolean space) { 272 if (args.length == 1) { 273 final List<String> completions = new LinkedList<>(); 274 if (player.hasPermission(Permission.PERMISSION_RATE)) { 275 completions.add("1 - 10"); 276 } 277 if (player.hasPermission(Permission.PERMISSION_ADMIN_COMMAND_PURGE_RATINGS)) { 278 completions.add("purge"); 279 } 280 final List<Command> commands = completions.stream().filter(completion -> completion 281 .toLowerCase() 282 .startsWith(args[0].toLowerCase())) 283 .map(completion -> new Command(null, true, completion, "", RequiredType.PLAYER, CommandCategory.INFO) { 284 }).collect(Collectors.toCollection(LinkedList::new)); 285 if (player.hasPermission(Permission.PERMISSION_RATE) && args[0].length() > 0) { 286 commands.addAll(TabCompletions.completePlayers(player, args[0], Collections.emptyList())); 287 } 288 return commands; 289 } 290 return TabCompletions.completePlayers(player, String.join(",", args).trim(), Collections.emptyList()); 291 } 292 293 private static class MutableInt { 294 295 private int value; 296 297 MutableInt(int i) { 298 this.value = i; 299 } 300 301 void increment() { 302 this.value++; 303 } 304 305 void decrement() { 306 this.value--; 307 } 308 309 int getValue() { 310 return this.value; 311 } 312 313 void add(Number v) { 314 this.value += v.intValue(); 315 } 316 317 } 318 319}