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.gson.JsonObject; 022import com.google.gson.JsonParser; 023import com.google.inject.Inject; 024import com.intellectualsites.paster.IncendoPaster; 025import com.plotsquared.core.PlotSquared; 026import com.plotsquared.core.configuration.Settings; 027import com.plotsquared.core.configuration.Storage; 028import com.plotsquared.core.configuration.caption.TranslatableCaption; 029import com.plotsquared.core.inject.annotations.ConfigFile; 030import com.plotsquared.core.inject.annotations.WorldFile; 031import com.plotsquared.core.player.PlotPlayer; 032import com.plotsquared.core.util.PremiumVerification; 033import com.plotsquared.core.util.task.TaskManager; 034import net.kyori.adventure.text.Component; 035import net.kyori.adventure.text.minimessage.tag.Tag; 036import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; 037import org.checkerframework.checker.nullness.qual.NonNull; 038 039import java.io.File; 040import java.io.IOException; 041import java.lang.management.ManagementFactory; 042import java.lang.management.RuntimeMXBean; 043import java.nio.file.Files; 044import java.util.concurrent.TimeUnit; 045 046@CommandDeclaration(command = "debugpaste", 047 aliases = "dp", 048 usage = "/plot debugpaste", 049 permission = "plots.debugpaste", 050 category = CommandCategory.DEBUG, 051 confirmation = true, 052 requiredType = RequiredType.NONE) 053public class DebugPaste extends SubCommand { 054 055 private final File configFile; 056 private final File worldfile; 057 058 @Inject 059 public DebugPaste( 060 @ConfigFile final @NonNull File configFile, 061 @WorldFile final @NonNull File worldFile 062 ) { 063 this.configFile = configFile; 064 this.worldfile = worldFile; 065 } 066 067 @Override 068 public boolean onCommand(final PlotPlayer<?> player, String[] args) { 069 TaskManager.runTaskAsync(() -> { 070 try { 071 StringBuilder b = new StringBuilder(); 072 b.append( 073 """ 074 # Welcome to this paste 075 # It is meant to provide us at IntellectualSites with better information about your problem 076 """ 077 ); 078 b.append("# PlotSquared Information\n"); 079 b.append("PlotSquared Version: ").append(PlotSquared.get().getVersion()) 080 .append("\n"); 081 b.append("Database Type: ").append(Storage.MySQL.USE ? "MySQL" : "SQLite").append("\n"); 082 b.append("Resource ID: ").append(PremiumVerification.getResourceID()).append("\n"); 083 b.append("Download ID: ").append(PremiumVerification.getDownloadID()).append("\n"); 084 b.append("This PlotSquared version is licensed to the spigot user ") 085 .append(PremiumVerification.getUserID()).append("\n\n"); 086 b.append("# WorldEdit implementation:\n"); 087 b.append(PlotSquared.platform().worldEditImplementations()).append("\n\n"); 088 b.append("# Server Information\n"); 089 b.append("Server Version: ").append(PlotSquared.platform().serverBrand()).append(": ") 090 .append(PlotSquared.platform().serverImplementation()).append("\n") 091 .append("\n"); 092 b.append("online_mode: ").append(!Settings.UUID.OFFLINE).append(';') 093 .append(!Settings.UUID.OFFLINE).append('\n'); 094 b.append(PlotSquared.platform().pluginsFormatted()); 095 b.append("\n\n# YAY! Now, let's see what we can find in your JVM\n"); 096 Runtime runtime = Runtime.getRuntime(); 097 RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean(); 098 b.append("Uptime: ") 099 .append(TimeUnit.MINUTES.convert(rb.getUptime(), TimeUnit.MILLISECONDS)) 100 .append(" minutes") 101 .append('\n'); 102 b.append("JVM Flags: ").append(rb.getInputArguments()).append('\n'); 103 b.append("Free Memory: ").append(runtime.freeMemory() / 1024 / 1024).append(" MB") 104 .append('\n'); 105 b.append("Max Memory: ").append(runtime.maxMemory() / 1024 / 1024).append(" MB") 106 .append('\n'); 107 b.append("Total Memory: ").append(runtime.totalMemory() / 1024 / 1024).append(" MB") 108 .append('\n'); 109 b.append("Available Processors: ").append(runtime.availableProcessors()).append('\n'); 110 b.append("Java Name: ").append(rb.getVmName()).append('\n'); 111 b.append("Java Version: '").append(System.getProperty("java.version")) 112 .append("'\n"); 113 b.append("Java Vendor: '").append(System.getProperty("java.vendor")).append("'\n"); 114 b.append("Operating System: '").append(System.getProperty("os.name")).append("'\n"); 115 b.append("OS Version: ").append(System.getProperty("os.version")).append('\n'); 116 b.append("OS Arch: ").append(System.getProperty("os.arch")).append('\n'); 117 b.append("# Okay :D Great. You are now ready to create your bug report!"); 118 b.append( 119 "\n# You can do so at https://github.com/IntellectualSites/PlotSquared/issues"); 120 b.append("\n# or via our Discord at https://discord.gg/intellectualsites"); 121 122 final IncendoPaster incendoPaster = new IncendoPaster("plotsquared"); 123 incendoPaster.addFile(new IncendoPaster.PasteFile("information", b.toString())); 124 125 try { 126 final File logFile = 127 new File("logs/latest.log"); 128 if (Files.size(logFile.toPath()) > 14_000_000) { 129 throw new IOException( 130 "The latest.log is larger than 14MB. Please reboot your server and submit a new paste."); 131 } 132 incendoPaster 133 .addFile(logFile); 134 } catch (IOException ignored) { 135 player.sendMessage( 136 TranslatableCaption.of("debugpaste.latest_log"), 137 TagResolver.builder() 138 .tag("file", Tag.inserting(Component.text("latest.log"))) 139 .tag("size", Tag.inserting(Component.text("14MB"))) 140 .build() 141 ); 142 } 143 144 try { 145 incendoPaster.addFile(this.configFile); 146 } catch (final IllegalArgumentException ignored) { 147 player.sendMessage( 148 TranslatableCaption.of("debugpaste.empty_file"), 149 TagResolver.resolver("file", Tag.inserting(Component.text("settings.yml"))) 150 ); 151 } 152 try { 153 incendoPaster.addFile(this.worldfile); 154 } catch (final IllegalArgumentException ignored) { 155 player.sendMessage( 156 TranslatableCaption.of("debugpaste.empty_file"), 157 TagResolver.resolver("file", Tag.inserting(Component.text("worlds.yml"))) 158 ); 159 } 160 161 try { 162 final File MultiverseWorlds = new File( 163 PlotSquared.platform().getDirectory(), 164 "../Multiverse-Core/worlds.yml" 165 ); 166 incendoPaster.addFile(MultiverseWorlds, "Multiverse-Core/worlds.yml"); 167 } catch (final IOException ignored) { 168 player.sendMessage( 169 TranslatableCaption.of("debugpaste.skip_multiverse"), 170 TagResolver.resolver("file", Tag.inserting(Component.text("worlds.yml"))) 171 ); 172 } 173 174 try { 175 final String rawResponse = incendoPaster.upload(); 176 final JsonObject jsonObject = 177 new JsonParser().parse(rawResponse).getAsJsonObject(); 178 179 if (jsonObject.has("created")) { 180 final String pasteId = jsonObject.get("paste_id").getAsString(); 181 final String link = 182 String.format("https://athion.net/ISPaster/paste/view/%s", pasteId); 183 player.sendMessage( 184 TranslatableCaption.of("debugpaste.debug_report_created"), 185 TagResolver.resolver("url", Tag.preProcessParsed(link)) 186 ); 187 } else { 188 final String responseMessage = jsonObject.get("response").getAsString(); 189 player.sendMessage( 190 TranslatableCaption.of("debugpaste.creation_failed"), 191 TagResolver.resolver("value", Tag.inserting(Component.text(responseMessage))) 192 ); 193 } 194 } catch (final Throwable throwable) { 195 throwable.printStackTrace(); 196 player.sendMessage( 197 TranslatableCaption.of("debugpaste.creation_failed"), 198 TagResolver.resolver("value", Tag.inserting(Component.text(throwable.getMessage()))) 199 ); 200 } 201 } catch (IOException e) { 202 e.printStackTrace(); 203 } 204 }); 205 return true; 206 } 207 208}