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.TypeLiteral; 022import com.plotsquared.core.configuration.caption.StaticCaption; 023import com.plotsquared.core.configuration.caption.Templates; 024import com.plotsquared.core.configuration.caption.TranslatableCaption; 025import com.plotsquared.core.permissions.Permission; 026import com.plotsquared.core.player.MetaDataAccess; 027import com.plotsquared.core.player.MetaDataKey; 028import com.plotsquared.core.player.PlotPlayer; 029import com.plotsquared.core.plot.Plot; 030import com.plotsquared.core.plot.comment.CommentInbox; 031import com.plotsquared.core.plot.comment.CommentManager; 032import com.plotsquared.core.plot.comment.PlotComment; 033import com.plotsquared.core.util.StringMan; 034import com.plotsquared.core.util.TabCompletions; 035import com.plotsquared.core.util.task.RunnableVal; 036import net.kyori.adventure.text.Component; 037import net.kyori.adventure.text.TextComponent; 038import net.kyori.adventure.text.minimessage.Template; 039 040import java.util.Collection; 041import java.util.Collections; 042import java.util.LinkedList; 043import java.util.List; 044import java.util.stream.Collectors; 045 046@CommandDeclaration(command = "inbox", 047 usage = "/plot inbox [inbox] [delete <index> | clear | page]", 048 permission = "plots.inbox", 049 category = CommandCategory.CHAT, 050 requiredType = RequiredType.PLAYER) 051public class Inbox extends SubCommand { 052 053 public void displayComments(PlotPlayer<?> player, List<PlotComment> oldComments, int page) { 054 if (oldComments == null || oldComments.isEmpty()) { 055 player.sendMessage(TranslatableCaption.of("comment.inbox_empty")); 056 return; 057 } 058 PlotComment[] comments = oldComments.toArray(new PlotComment[0]); 059 if (page < 0) { 060 page = 0; 061 } 062 // Get the total pages 063 // int totalPages = ((int) Math.ceil(12 * 064 int totalPages = (int) Math.ceil(comments.length / 12); 065 if (page > totalPages) { 066 page = totalPages; 067 } 068 // Only display 12 per page 069 int max = page * 12 + 12; 070 if (max > comments.length) { 071 max = comments.length; 072 } 073 TextComponent.Builder builder = Component.text(); 074 builder.append(MINI_MESSAGE.parse(TranslatableCaption.of("list.comment_list_header_paged").getComponent(player) + '\n', 075 Template.of("amount", String.valueOf(comments.length)), Template.of("cur", String.valueOf(page + 1)), 076 Template.of("max", String.valueOf(totalPages + 1)), Template.of("word", "all") 077 )); 078 079 // This might work xD 080 for (int x = page * 12; x < max; x++) { 081 PlotComment comment = comments[x]; 082 Component commentColored; 083 if (player.getName().equals(comment.senderName)) { 084 commentColored = MINI_MESSAGE 085 .parse( 086 TranslatableCaption.of("list.comment_list_by_lister").getComponent(player), 087 Template.of("comment", comment.comment) 088 ); 089 } else { 090 commentColored = MINI_MESSAGE 091 .parse( 092 TranslatableCaption.of("list.comment_list_by_other").getComponent(player), 093 Template.of("comment", comment.comment) 094 ); 095 } 096 Template number = Template.of("number", String.valueOf(x)); 097 Template world = Template.of("world", comment.world); 098 Template plot_id = Template.of("plot_id", comment.id.getX() + ";" + comment.id.getY()); 099 Template commenter = Template.of("commenter", comment.senderName); 100 Template commentTemplate = Template.of("comment", commentColored); 101 builder.append(MINI_MESSAGE 102 .parse( 103 TranslatableCaption.of("list.comment_list_comment").getComponent(player), 104 number, 105 world, 106 plot_id, 107 commenter, 108 commentTemplate 109 )); 110 } 111 player.sendMessage(StaticCaption.of(MINI_MESSAGE.serialize(builder.build()))); 112 } 113 114 @Override 115 public boolean onCommand(final PlotPlayer<?> player, String[] args) { 116 final Plot plot = player.getCurrentPlot(); 117 if (plot == null) { 118 player.sendMessage(TranslatableCaption.of("errors.not_in_plot")); 119 return false; 120 } 121 if (!plot.hasOwner()) { 122 player.sendMessage(TranslatableCaption.of("info.plot_unowned")); 123 return false; 124 } 125 if (args.length == 0) { 126 sendUsage(player); 127 for (final CommentInbox inbox : CommentManager.inboxes.values()) { 128 if (inbox.canRead(plot, player)) { 129 if (!inbox.getComments(plot, new RunnableVal<>() { 130 @Override 131 public void run(List<PlotComment> value) { 132 if (value != null) { 133 int total = 0; 134 int unread = 0; 135 for (PlotComment comment : value) { 136 total++; 137 if (comment.timestamp > CommentManager 138 .getTimestamp(player, inbox.toString())) { 139 unread++; 140 } 141 } 142 if (total != 0) { 143 player.sendMessage( 144 TranslatableCaption.of("comment.inbox_item"), 145 Template.of("value", inbox + " (" + total + '/' + unread + ')') 146 ); 147 return; 148 } 149 } 150 player.sendMessage( 151 TranslatableCaption.of("comment.inbox_item"), 152 Template.of("value", inbox.toString()) 153 ); 154 } 155 })) { 156 player.sendMessage( 157 TranslatableCaption.of("comment.inbox_item"), 158 Template.of("value", inbox.toString()) 159 ); 160 } 161 } 162 } 163 return false; 164 } 165 final CommentInbox inbox = CommentManager.inboxes.get(args[0].toLowerCase()); 166 if (inbox == null) { 167 player.sendMessage( 168 TranslatableCaption.of("comment.invalid_inbox"), 169 Template.of("list", StringMan.join(CommentManager.inboxes.keySet(), ", ")) 170 ); 171 return false; 172 } 173 final MetaDataKey<Long> metaDataKey = MetaDataKey.of( 174 String.format("inbox:%s", inbox), 175 new TypeLiteral<>() { 176 } 177 ); 178 try (final MetaDataAccess<Long> metaDataAccess = player.accessTemporaryMetaData(metaDataKey)) { 179 metaDataAccess.set(System.currentTimeMillis()); 180 } 181 final int page; 182 if (args.length > 1) { 183 switch (args[1].toLowerCase()) { 184 case "delete": 185 if (!inbox.canModify(plot, player)) { 186 player.sendMessage(TranslatableCaption.of("comment.no_perm_inbox_modify")); 187 return false; 188 } 189 if (args.length != 3) { 190 player.sendMessage( 191 TranslatableCaption.of("commandconfig.command_syntax"), 192 Template.of("value", "/plot inbox " + inbox + " delete <index>") 193 ); 194 return true; 195 } 196 final int index; 197 try { 198 index = Integer.parseInt(args[2]); 199 if (index < 1) { 200 player.sendMessage( 201 TranslatableCaption.of("comment.not_valid_inbox_index"), 202 Templates.of("number", index) 203 ); 204 return false; 205 } 206 } catch (NumberFormatException ignored) { 207 player.sendMessage( 208 TranslatableCaption.of("commandconfig.command_syntax"), 209 Template.of("value", "/plot inbox " + inbox + " delete <index>") 210 ); 211 return false; 212 } 213 214 if (!inbox.getComments(plot, new RunnableVal<>() { 215 @Override 216 public void run(List<PlotComment> value) { 217 if (index > value.size()) { 218 player.sendMessage( 219 TranslatableCaption.of("comment.not_valid_inbox_index"), 220 Templates.of("number", index) 221 ); 222 return; 223 } 224 PlotComment comment = value.get(index - 1); 225 inbox.removeComment(plot, comment); 226 boolean success = plot.getPlotCommentContainer().removeComment(comment); 227 if (success) { 228 player.sendMessage( 229 TranslatableCaption.of("comment.comment_removed_success"), 230 Template.of("value", comment.comment) 231 ); 232 } else { 233 player.sendMessage( 234 TranslatableCaption.of("comment.comment_removed_failure")); 235 } 236 } 237 })) { 238 player.sendMessage(TranslatableCaption.of("errors.not_in_plot")); 239 return false; 240 } 241 return true; 242 case "clear": 243 if (!inbox.canModify(plot, player)) { 244 player.sendMessage(TranslatableCaption.of("comment.no_perm_inbox_modify")); 245 } 246 inbox.clearInbox(plot); 247 List<PlotComment> comments = plot.getPlotCommentContainer().getComments(inbox.toString()); 248 if (!comments.isEmpty()) { 249 player.sendMessage( 250 TranslatableCaption.of("comment.comment_removed_success"), 251 Template.of("value", String.valueOf(comments)) 252 ); 253 plot.getPlotCommentContainer().removeComments(comments); 254 } 255 return true; 256 default: 257 try { 258 page = Integer.parseInt(args[1]); 259 } catch (NumberFormatException ignored) { 260 sendUsage(player); 261 return false; 262 } 263 } 264 } else { 265 page = 1; 266 } 267 if (!inbox.canRead(plot, player)) { 268 player.sendMessage(TranslatableCaption.of("comment.no_perm_inbox")); 269 return false; 270 } 271 if (!inbox.getComments(plot, new RunnableVal<>() { 272 @Override 273 public void run(List<PlotComment> value) { 274 displayComments(player, value, page); 275 } 276 })) { 277 player.sendMessage(TranslatableCaption.of("info.plot_unowned")); 278 return false; 279 } 280 return true; 281 } 282 283 @Override 284 public Collection<Command> tab(final PlotPlayer<?> player, final String[] args, final boolean space) { 285 if (args.length == 1) { 286 final List<String> completions = new LinkedList<>(); 287 if (player.hasPermission(Permission.PERMISSION_INBOX_READ_OWNER)) { 288 completions.add("owner"); 289 } 290 if (player.hasPermission(Permission.PERMISSION_INBOX_READ_PUBLIC)) { 291 completions.add("public"); 292 } 293 if (player.hasPermission(Permission.PERMISSION_INBOX_READ_REPORT)) { 294 completions.add("report"); 295 } 296 final List<Command> commands = completions.stream().filter(completion -> completion 297 .toLowerCase() 298 .startsWith(args[0].toLowerCase())) 299 .map(completion -> new Command(null, true, completion, "", RequiredType.PLAYER, CommandCategory.CHAT) { 300 }).collect(Collectors.toCollection(LinkedList::new)); 301 if (player.hasPermission(Permission.PERMISSION_INBOX) && args[0].length() > 0) { 302 commands.addAll(TabCompletions.completePlayers(player, args[0], Collections.emptyList())); 303 } 304 return commands; 305 } 306 return TabCompletions.completePlayers(player, String.join(",", args).trim(), Collections.emptyList()); 307 } 308 309}