Allow custom update URLs for modules

This commit is contained in:
2026-05-19 21:29:55 -04:00
parent 2543c7f19e
commit 42f7a02a7a
9 changed files with 224 additions and 42 deletions
@@ -3,6 +3,7 @@ package dev.plex.command;
import com.mojang.brigadier.tree.LiteralCommandNode;
import dev.plex.api.PlexApi;
import dev.plex.command.source.RequiredCommandSource;
import dev.plex.module.PlexModule;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import java.util.List;
@@ -37,6 +38,15 @@ public interface PlexCommand
{
}
/**
* Supplies the owning module to commands that need module-owned resources.
*
* @param module owning module
*/
default void bindModule(PlexModule module)
{
}
/**
* Returns the primary command name.
*
@@ -13,6 +13,7 @@ import dev.plex.command.exception.ConsoleOnlyException;
import dev.plex.command.exception.PlayerNotBannedException;
import dev.plex.command.exception.PlayerNotFoundException;
import dev.plex.command.source.RequiredCommandSource;
import dev.plex.module.PlexModule;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import java.util.Collection;
@@ -42,6 +43,7 @@ public abstract class SimplePlexCommand implements PlexCommand
{
private final CommandSpec commandSpec;
private PlexApi api;
private PlexModule module;
protected SimplePlexCommand(CommandSpec commandSpec)
{
@@ -65,6 +67,12 @@ public abstract class SimplePlexCommand implements PlexCommand
this.api = api;
}
@Override
public final void bindModule(PlexModule module)
{
this.module = module;
}
@Override
public final LiteralCommandNode<CommandSourceStack> buildCommand()
{
@@ -124,7 +132,7 @@ public abstract class SimplePlexCommand implements PlexCommand
{
return true;
}
throw new CommandFailException(api().messages().messageString("noPermissionNode", permission));
throw new CommandFailException(messageString("noPermissionNode", permission));
}
protected boolean silentCheckPermission(CommandSender sender, String permission)
@@ -154,16 +162,28 @@ public abstract class SimplePlexCommand implements PlexCommand
protected Component messageComponent(String key, Object... objects)
{
if (module != null)
{
return module.messageComponent(key, objects);
}
return api().messages().messageComponent(key, objects);
}
protected Component messageComponent(String key, Component... objects)
{
if (module != null)
{
return module.messageComponent(key, objects);
}
return api().messages().messageComponent(key, objects);
}
protected String messageString(String key, Object... objects)
{
if (module != null)
{
return module.messageString(key, objects);
}
return api().messages().messageString(key, objects);
}
@@ -1,7 +1,9 @@
package dev.plex.module;
import dev.plex.api.PlexApi;
import dev.plex.api.config.ModuleConfiguration;
import dev.plex.command.PlexCommand;
import dev.plex.config.ModuleConfig;
import java.io.File;
import java.io.IOException;
@@ -9,10 +11,10 @@ import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import net.kyori.adventure.text.Component;
import org.apache.logging.log4j.Logger;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
@@ -31,6 +33,7 @@ public abstract class PlexModule
private final List<Listener> listeners = new ArrayList<>();
private PlexApi api;
private ModuleConfiguration messages;
private PlexModuleFile plexModuleFile;
private File dataFolder;
private Logger logger;
@@ -158,41 +161,6 @@ public abstract class PlexModule
.orElse(null);
}
/**
* Adds a default message if the message key is not already configured.
*
* @param message message key
* @param initValue default value to write
*/
public void addDefaultMessage(String message, Object initValue)
{
if (api.configuration().messages().getString(message) == null)
{
api.configuration().messages().set(message, initValue);
api.configuration().messages().save();
logger.debug("'{}' message added from {}", message, plexModuleFile.getName());
}
}
/**
* Adds a default message and comments if the message key is not already configured.
*
* @param message message key
* @param initValue default value to write
* @param comments comments to write above the message key
*/
public void addDefaultMessage(String message, Object initValue, String... comments)
{
if (api.configuration().messages().getString(message) == null)
{
api.configuration().messages().set(message, initValue);
api.configuration().messages().save();
api.configuration().messages().setComments(message, Arrays.asList(comments));
api.configuration().messages().save();
logger.debug("'{}' message added from {}", message, plexModuleFile.getName());
}
}
/**
* Opens a resource from this module's class loader.
*
@@ -270,6 +238,90 @@ public abstract class PlexModule
return logger;
}
/**
* Loads this module's message file.
*
* @param from resource path to copy defaults from
*/
public void loadMessages(String from)
{
loadMessages(from, "messages.yml");
}
/**
* Loads this module's message file.
*
* @param from resource path to copy defaults from
* @param to destination file path relative to the module data folder
*/
public void loadMessages(String from, String to)
{
messages = new ModuleConfig(this, from, to);
messages.load();
}
/**
* Returns this module's loaded messages, if any.
*
* @return module messages, or {@code null} when this module has no messages
*/
@Nullable
public ModuleConfiguration messages()
{
return messages;
}
/**
* Resolves a module message into a component, falling back to Plex messages.
*
* @param entry message key
* @param objects replacement values
* @return resolved component
*/
public Component messageComponent(String entry, Object... objects)
{
return api.messages().miniMessage(messageString(entry, objects));
}
/**
* Resolves a module message into a component using component replacements.
*
* @param entry message key
* @param objects component replacement values
* @return resolved component
*/
public Component messageComponent(String entry, Component... objects)
{
Component component = api.messages().miniMessage(messageString(entry));
for (int i = 0; i < objects.length; i++)
{
int finalI = i;
component = component.replaceText(builder -> builder.matchLiteral("{" + finalI + "}").replacement(objects[finalI]).build());
}
return component;
}
/**
* Resolves a module message into a string, falling back to Plex messages.
*
* @param entry message key
* @param objects replacement values
* @return resolved message string
*/
public String messageString(String entry, Object... objects)
{
String message = messages == null ? null : messages.getString(entry);
if (message == null)
{
return api.messages().messageString(entry, objects);
}
for (int i = 0; i < objects.length; i++)
{
message = message.replace("{" + i + "}", String.valueOf(objects[i]));
}
return message;
}
/**
* Sets the Plex API facade for this module.
*
@@ -287,6 +339,7 @@ public abstract class PlexModule
{
command.bindApi(api);
}
command.bindModule(this);
}
/**
@@ -14,6 +14,8 @@ public final class PlexModuleFile
private final int apiCompatibility;
private List<String> libraries = List.of();
private List<String> repositories = List.of();
private boolean updaterEnabled = true;
private List<String> updateUrls = List.of();
/**
* Creates module metadata.
@@ -122,4 +124,47 @@ public final class PlexModuleFile
{
this.repositories = List.copyOf(repositories);
}
/**
* Returns whether Plex should include this module in module update commands.
*
* @return {@code true} when module updates are enabled
*/
public boolean isUpdaterEnabled()
{
return updaterEnabled;
}
/**
* Sets whether Plex should include this module in module update commands.
*
* @param updaterEnabled whether module updates are enabled
*/
public void setUpdaterEnabled(boolean updaterEnabled)
{
this.updaterEnabled = updaterEnabled;
}
/**
* Returns custom updater base URLs declared by the module.
*
* <p>An empty list means Plex should use the built-in first-party updater
* endpoints.</p>
*
* @return custom updater base URLs
*/
public List<String> getUpdateUrls()
{
return updateUrls;
}
/**
* Sets custom updater base URLs declared by the module.
*
* @param updateUrls custom updater base URLs
*/
public void setUpdateUrls(List<String> updateUrls)
{
this.updateUrls = updateUrls == null ? List.of() : List.copyOf(updateUrls);
}
}