Paper Plugins

Co-authored-by: Micah Rao <micah.s.rao@gmail.com>
This commit is contained in:
Owen1212055
2022-07-06 23:00:31 -04:00
parent 329dfdabdc
commit 216388dfdf
103 changed files with 7450 additions and 42 deletions

View File

@@ -0,0 +1,203 @@
package io.papermc.paper.command.subcommands;
import com.google.common.graph.GraphBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.internal.Streams;
import com.google.gson.stream.JsonWriter;
import io.papermc.paper.command.PaperSubcommand;
import io.papermc.paper.plugin.entrypoint.Entrypoint;
import io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler;
import io.papermc.paper.plugin.entrypoint.classloader.group.LockingClassLoaderGroup;
import io.papermc.paper.plugin.entrypoint.classloader.group.PaperPluginClassLoaderStorage;
import io.papermc.paper.plugin.entrypoint.classloader.group.SimpleListPluginClassLoaderGroup;
import io.papermc.paper.plugin.entrypoint.classloader.group.SpigotPluginClassLoaderGroup;
import io.papermc.paper.plugin.entrypoint.classloader.group.StaticPluginClassLoaderGroup;
import io.papermc.paper.plugin.entrypoint.dependency.GraphDependencyContext;
import io.papermc.paper.plugin.entrypoint.dependency.SimpleMetaDependencyTree;
import io.papermc.paper.plugin.provider.entrypoint.DependencyContext;
import io.papermc.paper.plugin.entrypoint.strategy.modern.ModernPluginLoadingStrategy;
import io.papermc.paper.plugin.entrypoint.strategy.ProviderConfiguration;
import io.papermc.paper.plugin.manager.PaperPluginManagerImpl;
import io.papermc.paper.plugin.provider.PluginProvider;
import io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader;
import io.papermc.paper.plugin.provider.classloader.PaperClassLoaderStorage;
import io.papermc.paper.plugin.provider.classloader.PluginClassLoaderGroup;
import io.papermc.paper.plugin.storage.ConfiguredProviderStorage;
import io.papermc.paper.plugin.storage.ProviderStorage;
import net.minecraft.server.MinecraftServer;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;
import java.io.PrintStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
import static net.kyori.adventure.text.format.NamedTextColor.RED;
@DefaultQualifier(NonNull.class)
public final class DumpPluginsCommand implements PaperSubcommand {
@Override
public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
this.dumpPlugins(sender, args);
return true;
}
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss");
private void dumpPlugins(final CommandSender sender, final String[] args) {
Path parent = Path.of("debug");
Path path = parent.resolve("plugin-info-" + FORMATTER.format(LocalDateTime.now()) + ".txt");
try {
Files.createDirectories(parent);
Files.createFile(path);
sender.sendMessage(text("Writing plugin information to " + path, GREEN));
final JsonObject data = this.writeDebug();
StringWriter stringWriter = new StringWriter();
JsonWriter jsonWriter = new JsonWriter(stringWriter);
jsonWriter.setIndent(" ");
jsonWriter.setLenient(false);
Streams.write(data, jsonWriter);
try (PrintStream out = new PrintStream(Files.newOutputStream(path), false, StandardCharsets.UTF_8)) {
out.print(stringWriter);
}
sender.sendMessage(text("Successfully written plugin debug information!", GREEN));
} catch (Throwable e) {
sender.sendMessage(text("Failed to write plugin information! See the console for more info.", RED));
MinecraftServer.LOGGER.warn("Error occurred while dumping plugin info", e);
}
}
private JsonObject writeDebug() {
JsonObject root = new JsonObject();
if (ConfiguredProviderStorage.LEGACY_PLUGIN_LOADING) {
root.addProperty("legacy-loading-strategy", true);
}
this.writeProviders(root);
this.writePlugins(root);
this.writeClassloaders(root);
return root;
}
private void writeProviders(JsonObject root) {
JsonObject rootProviders = new JsonObject();
root.add("providers", rootProviders);
for (Map.Entry<Entrypoint<?>, ProviderStorage<?>> entry : LaunchEntryPointHandler.INSTANCE.getStorage().entrySet()) {
JsonObject entrypoint = new JsonObject();
JsonArray providers = new JsonArray();
entrypoint.add("providers", providers);
List<PluginProvider<Object>> pluginProviders = new ArrayList<>();
for (PluginProvider<?> provider : entry.getValue().getRegisteredProviders()) {
JsonObject providerObj = new JsonObject();
providerObj.addProperty("name", provider.getMeta().getName());
providerObj.addProperty("version", provider.getMeta().getVersion());
providerObj.addProperty("dependencies", provider.getMeta().getPluginDependencies().toString());
providerObj.addProperty("soft-dependencies", provider.getMeta().getPluginSoftDependencies().toString());
providerObj.addProperty("load-before", provider.getMeta().getLoadBeforePlugins().toString());
providers.add(providerObj);
pluginProviders.add((PluginProvider<Object>) provider);
}
JsonArray loadOrder = new JsonArray();
entrypoint.add("load-order", loadOrder);
ModernPluginLoadingStrategy<Object> modernPluginLoadingStrategy = new ModernPluginLoadingStrategy<>(new ProviderConfiguration<>() {
@Override
public void applyContext(PluginProvider<Object> provider, DependencyContext dependencyContext) {
}
@Override
public boolean load(PluginProvider<Object> provider, Object provided) {
return true;
}
@Override
public boolean preloadProvider(PluginProvider<Object> provider) {
// Don't load provider
loadOrder.add(provider.getMeta().getName());
return false;
}
});
modernPluginLoadingStrategy.loadProviders(pluginProviders, new SimpleMetaDependencyTree(GraphBuilder.directed().build()));
rootProviders.add(entry.getKey().getDebugName(), entrypoint);
}
}
private void writePlugins(JsonObject root) {
JsonArray rootPlugins = new JsonArray();
root.add("plugins", rootPlugins);
for (Plugin plugin : PaperPluginManagerImpl.getInstance().getPlugins()) {
rootPlugins.add(plugin.toString());
}
}
private void writeClassloaders(JsonObject root) {
JsonObject classLoadersRoot = new JsonObject();
root.add("classloaders", classLoadersRoot);
PaperPluginClassLoaderStorage storage = (PaperPluginClassLoaderStorage) PaperClassLoaderStorage.instance();
classLoadersRoot.addProperty("global", storage.getGlobalGroup().toString());
classLoadersRoot.addProperty("dependency_graph", PaperPluginManagerImpl.getInstance().getInstanceManagerGraph().toString());
JsonArray array = new JsonArray();
classLoadersRoot.add("children", array);
for (PluginClassLoaderGroup group : storage.getGroups()) {
array.add(this.writeClassloader(group));
}
}
private JsonObject writeClassloader(PluginClassLoaderGroup group) {
JsonObject classLoadersRoot = new JsonObject();
if (group instanceof SimpleListPluginClassLoaderGroup listGroup) {
JsonArray array = new JsonArray();
classLoadersRoot.addProperty("main", listGroup.toString());
if (group instanceof StaticPluginClassLoaderGroup staticPluginClassLoaderGroup) {
classLoadersRoot.addProperty("plugin-holder", staticPluginClassLoaderGroup.getPluginClassloader().toString());
} else if (group instanceof SpigotPluginClassLoaderGroup spigotPluginClassLoaderGroup) {
classLoadersRoot.addProperty("plugin-holder", spigotPluginClassLoaderGroup.getPluginClassLoader().toString());
}
classLoadersRoot.add("children", array);
for (ConfiguredPluginClassLoader innerGroup : listGroup.getClassLoaders()) {
array.add(this.writeClassloader(innerGroup));
}
} else if (group instanceof LockingClassLoaderGroup locking) {
// Unwrap
return this.writeClassloader(locking.getParent());
} else {
classLoadersRoot.addProperty("raw", group.toString());
}
return classLoadersRoot;
}
private JsonElement writeClassloader(ConfiguredPluginClassLoader innerGroup) {
return new JsonPrimitive(innerGroup.toString());
}
}