Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -423,18 +423,23 @@ private void loadPlugins() {

try {
Path pluginPath = Path.of("plugins");
Path updatePath = configuration.isUpdateFolderEnabled() ? pluginPath.resolve(configuration.getUpdateFolderName()) : null;

if (!pluginPath.toFile().exists()) {
Files.createDirectory(pluginPath);
} else {
if (!pluginPath.toFile().isDirectory()) {
logger.warn("Plugin location {} is not a directory, continuing without loading plugins",
pluginPath);
return;
}
}

pluginManager.loadPlugins(pluginPath);
if (updatePath != null && !updatePath.toFile().exists()) {
Files.createDirectory(updatePath);
}

if (!pluginPath.toFile().isDirectory()) {
logger.warn("Plugin location {} is not a directory, continuing without loading plugins",
pluginPath);
return;
}

pluginManager.loadPlugins(pluginPath, updatePath);
} catch (Exception e) {
logger.error("Couldn't load plugins", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,14 @@ public boolean isLogPlayerConnections() {
return advanced.isLogPlayerConnections();
}

public boolean isUpdateFolderEnabled() {
return !advanced.getUpdateFolderName().isEmpty();
}

public String getUpdateFolderName() {
return advanced.getUpdateFolderName();
}

public boolean isAcceptTransfers() {
return this.advanced.isAcceptTransfers();
}
Expand Down Expand Up @@ -763,6 +771,8 @@ private static class Advanced {
@Expose
private boolean logPlayerConnections = true;
@Expose
private String updateFolderName = ".update";
@Expose
private boolean acceptTransfers = false;
@Expose
private boolean enableReusePort = false;
Expand Down Expand Up @@ -800,6 +810,7 @@ private Advanced(CommentedConfig config) {
this.announceProxyCommands = config.getOrElse("announce-proxy-commands", true);
this.logCommandExecutions = config.getOrElse("log-command-executions", false);
this.logPlayerConnections = config.getOrElse("log-player-connections", true);
this.updateFolderName = config.getOrElse("update-folder", ".update");
this.acceptTransfers = config.getOrElse("accepts-transfers", false);
this.enableReusePort = config.getOrElse("enable-reuse-port", false);
this.commandRateLimit = config.getIntOrElse("command-rate-limit", 25);
Expand Down Expand Up @@ -866,6 +877,10 @@ public boolean isLogPlayerConnections() {
return logPlayerConnections;
}

public String getUpdateFolderName() {
return updateFolderName;
}

public boolean isAcceptTransfers() {
return this.acceptTransfers;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import com.velocitypowered.proxy.plugin.loader.VelocityPluginContainer;
import com.velocitypowered.proxy.plugin.loader.java.JavaPluginLoader;
import com.velocitypowered.proxy.plugin.util.PluginDependencyUtils;
import edu.umd.cs.findbugs.annotations.Nullable;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.nio.file.DirectoryStream;
Expand Down Expand Up @@ -82,19 +83,19 @@ public void registerPlugin(PluginContainer plugin) {
/**
* Loads all plugins from the specified {@code directory}.
*
* @param directory the directory to load from
* @param pluginDirectory the directory to load from
* @throws IOException if we could not open the directory
*/
@SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE",
justification = "I looked carefully and there's no way SpotBugs is right.")
public void loadPlugins(Path directory) throws IOException {
checkNotNull(directory, "directory");
checkArgument(directory.toFile().isDirectory(), "provided path isn't a directory");
public void loadPlugins(Path pluginDirectory, @Nullable Path updateDirectory) throws IOException {
checkNotNull(pluginDirectory, "directory");
checkArgument(pluginDirectory.toFile().isDirectory(), "provided path isn't a directory");

Map<String, PluginDescription> foundCandidates = new LinkedHashMap<>();
JavaPluginLoader loader = new JavaPluginLoader(server, directory);
JavaPluginLoader loader = new JavaPluginLoader(server, pluginDirectory);

try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory,
try (DirectoryStream<Path> stream = Files.newDirectoryStream(pluginDirectory,
p -> p.toFile().isFile() && p.toString().endsWith(".jar"))) {
for (Path path : stream) {
try {
Expand Down Expand Up @@ -122,6 +123,11 @@ public void loadPlugins(Path directory) throws IOException {
return;
}

// Update plugins if an update folder is defined
if (updateDirectory != null) {
updatePlugins(pluginDirectory, updateDirectory, foundCandidates, loader);
}

List<PluginDescription> sortedPlugins = PluginDependencyUtils.sortCandidates(
new ArrayList<>(foundCandidates.values()));

Expand Down Expand Up @@ -182,6 +188,67 @@ protected void configure() {
}
}

private void updatePlugins(
Path pluginDirectory,
Path updateDirectory,
Map<String, PluginDescription> found,
JavaPluginLoader loader
) throws IOException {
checkNotNull(updateDirectory, "updateDirectory");

List<PluginDescription> availableUpdates = new ArrayList<>();
JavaPluginLoader updateLoader = new JavaPluginLoader(server, updateDirectory);
try (
DirectoryStream<Path> stream = Files.newDirectoryStream(updateDirectory, path -> path.toFile().isFile() && path.toString().endsWith(".jar"))
) {
for (Path path : stream) {
try {
availableUpdates.add(updateLoader.loadCandidate(path));
} catch (Exception e) {
logger.error("Unable to load plugin candidate {}", path, e);
}
}
}

for (PluginDescription availableUpdate : availableUpdates) {
PluginDescription potentialMatch = found.get(availableUpdate.getId());

// This should not happen but acts as a failsafe
if (availableUpdate.getSource().isEmpty()) {
logger.warn("No source found for plugin {} found", availableUpdate.getId());
continue;
}

if (potentialMatch != null) {
if (potentialMatch.getSource().isEmpty()) {
logger.warn("No source for plugin {} found, continuing without update.",
potentialMatch.getId());
continue;
}

// Remove outdated plugin file
try {
Files.deleteIfExists(potentialMatch.getSource().get());
} catch (IOException e) {
logger.error("Unable to delete plugin {} from plugins folder at {}",
potentialMatch.getId(), pluginDirectory.toString(), e);
continue;
}
}

Path newPath = pluginDirectory.resolve(availableUpdate.getSource().get().getFileName());
try {
Files.move(availableUpdate.getSource().get(), newPath);
logger.info("Successfully updated plugin {} to version {}",
availableUpdate.getId(), availableUpdate.getVersion());
PluginDescription movedDescription = loader.loadCandidate(newPath);
found.put(movedDescription.getId(), movedDescription);
} catch (Exception e) {
logger.error("Unable to update plugin {}", availableUpdate.getId(), e);
}
}
}

@Override
public Optional<PluginContainer> fromInstance(Object instance) {
checkNotNull(instance, "instance");
Expand Down
3 changes: 3 additions & 0 deletions proxy/src/main/resources/default-velocity.toml
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ log-command-executions = false
# and disconnecting from the proxy.
log-player-connections = true

# The name of the update folder, set to "" to disable the update folder
update-folder = ".update"

# Allows players transferred from other hosts via the
# Transfer packet (Minecraft 1.20.5) to be received.
accepts-transfers = false
Expand Down