Handle Hikari (GPLv3) databases, replace Vault permissions with LuckPerms permissions

This commit is contained in:
NotAlexNoyle committed 2026-07-26 10:43:06 -04:00
1 parent 4a671fbe05
commit 756819303e
8 files changed
+194 -103

No files matched your search

+1
View File
@@ -215,6 +215,7 @@ project(":quickshop-bukkit") {
compileOnly(files(protocolLibJar)) // Import Legacy ProtocolLib API.
compileOnly("me.xanium:GemsEconomy:4.9.3-GCRemake-1.6")
compileOnly("com.github.MilkBowl:VaultAPI:1.7.1")
compileOnly("net.luckperms:api:5.5")
compileOnly("me.clip:placeholderapi:2.11.5")
compileOnly("net.tnemc:EconomyCore:0.1.2.6-Pre1")
compileOnly("net.tnemc:Reserve:0.1.5.3-SNAPSHOT-4")
@@ -10,6 +10,9 @@ public class InventoryWrapperRegistry {
private final Map<String, InventoryWrapperManager> registry = new MapMaker().makeMap();
// Extra provider names resolving onto a canonical registry key.
private final Map<String, String> aliases = new MapMaker().makeMap();
@Nullable
public String find(InventoryWrapperManager manager) {
@@ -28,9 +31,31 @@ public class InventoryWrapperRegistry {
}
@Nullable
public InventoryWrapperManager get(String pluginName) {
public InventoryWrapperManager get(String providerName) {
return registry.get(pluginName);
InventoryWrapperManager manager = registry.get(providerName);
if (manager != null) {
return manager;
}
String canonical = aliases.get(providerName);
return canonical == null ? null : registry.get(canonical);
}
/**
* Makes an extra provider name resolve to an already registered one. Aliases
* are only read by {@link #get(String)} and are never returned by
* {@link #find(InventoryWrapperManager)}, so they never get persisted.
*
* @param alias The extra name to accept.
* @param canonicalName The registered name it resolves to.
*/
public void registerAlias(@NotNull String alias, @NotNull String canonicalName) {
aliases.put(alias, canonicalName);
}
@@ -51,10 +76,36 @@ public class InventoryWrapperRegistry {
}
/**
* Registers a manager under an explicit provider name instead of a plugin name.
* The name given here is what {@link #find(InventoryWrapperManager)} returns
* and therefore what gets persisted on shops.
*
* @param providerName The name to register under.
* @param manager The manager.
*/
public void register(@NotNull String providerName, @NotNull InventoryWrapperManager manager) {
registry.put(providerName, manager);
}
public void unregister(@NotNull Plugin plugin) {
registry.remove(plugin.getName());
}
/**
* Removes a manager registered through
* {@link #register(String, InventoryWrapperManager)}.
*
* @param providerName The name it was registered under.
*/
public void unregister(@NotNull String providerName) {
registry.remove(providerName);
}
}
@@ -83,6 +83,13 @@ import org.slf4j.Logger;
public class QuickShop implements QuickShopAPI, Reloadable {
/**
* Provider name persisted in data.inv_wrapper for the built-in wrapper. Kept as
* the upstream Hikari name rather than this fork's plugin name so the database
* stays interchangeable with upstream QuickShop-Hikari.
*/
public static final String BUILTIN_INVENTORY_WRAPPER_PROVIDER = "QuickShop-Hikari";
/**
* If running environment test
*/
@@ -326,7 +333,9 @@ public class QuickShop implements QuickShopAPI, Reloadable {
loadChatProcessor();
loadTextManager();
logger.info("Register InventoryWrapper...");
this.inventoryWrapperRegistry.register(javaPlugin, this.inventoryWrapperManager);
this.inventoryWrapperRegistry.register(BUILTIN_INVENTORY_WRAPPER_PROVIDER, this.inventoryWrapperManager);
// Accept shops written while this fork's own plugin name was being persisted.
this.inventoryWrapperRegistry.registerAlias(javaPlugin.getName(), BUILTIN_INVENTORY_WRAPPER_PROVIDER);
logger.info("Initializing NexusManager...");
this.nexusManager = new NexusManager(this);
logger.info("QuickShop " + javaPlugin.getFork() + " - Early boot step - Complete");
@@ -0,0 +1,109 @@
package com.ghostchu.quickshop.permission;
import com.ghostchu.quickshop.api.obj.QUser;
import com.ghostchu.quickshop.api.permission.PermissionProvider;
import com.ghostchu.quickshop.api.permission.ProviderIsEmptyException;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.LuckPermsProvider;
import net.luckperms.api.model.user.User;
import net.luckperms.api.platform.PlayerAdapter;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* Queries LuckPerms directly, replacing the Vault permission bridge.
* <p>
* Checks go through PlayerAdapter, which resolves against the player's current
* contexts. This matches Player#hasPermission as long as LuckPerms keeps
* apply-bukkit-default-permissions, apply-bukkit-child-permissions and
* apply-bukkit-attachment-permissions enabled (all default to true) -
* QuickShop's plugin.yml relies on both defaults and children trees.
*/
public class LuckPermsPermissionProvider implements PermissionProvider {
private final LuckPerms api;
private final PlayerAdapter<Player> playerAdapter;
public LuckPermsPermissionProvider() {
try {
this.api = LuckPermsProvider.get();
} catch (IllegalStateException | NoClassDefFoundError e) {
throw new ProviderIsEmptyException(getName());
}
this.playerAdapter = this.api.getPlayerAdapter(Player.class);
}
/**
* Get the debug infos in provider
*
* @param sender CommandSender
* @param permission The permission want to check
* @return Debug Infos
*/
public @NotNull PermissionInformationContainer getDebugInfo(@NotNull CommandSender sender,
@NotNull String permission)
{
if (sender instanceof Server) {
return new PermissionInformationContainer(sender, permission, null, "User is Console");
}
if (!(sender instanceof Player player)) {
return new PermissionInformationContainer(sender, permission, null, "Sender is not a LuckPerms user");
}
User user = playerAdapter.getUser(player);
return new PermissionInformationContainer(sender, permission, user.getPrimaryGroup(), null);
}
@Override
public @NotNull String getName() {
return "LuckPerms";
}
@Override
public boolean hasPermission(@NotNull CommandSender sender, @NotNull String permission) {
if (sender instanceof Player player) {
return playerAdapter.getPermissionData(player).checkPermission(permission).asBoolean();
}
// Console and command blocks have no LuckPerms user to resolve against.
return sender.hasPermission(permission);
}
@Override
public boolean hasPermission(@NotNull QUser sender, @NotNull String permission) {
Player player = sender.getBukkitPlayer().orElse(null);
if (player == null) {
return false;
}
return playerAdapter.getPermissionData(player).checkPermission(permission).asBoolean();
}
}
@@ -3,6 +3,7 @@ package com.ghostchu.quickshop.permission;
import com.ghostchu.quickshop.QuickShop;
import com.ghostchu.quickshop.api.obj.QUser;
import com.ghostchu.quickshop.api.permission.PermissionProvider;
import com.ghostchu.quickshop.api.permission.ProviderIsEmptyException;
import com.ghostchu.quickshop.util.Util;
import com.ghostchu.quickshop.util.logger.Log;
import lombok.Getter;
@@ -24,11 +25,27 @@ public class PermissionManager {
public PermissionManager(QuickShop plugin) {
this.plugin = plugin;
provider = new BukkitPermsProvider();
provider = selectProvider(plugin);
plugin.logger().info("Selected permission provider: {}", provider.getName());
}
@NotNull
private static PermissionProvider selectProvider(QuickShop plugin) {
try {
return new LuckPermsPermissionProvider();
} catch (ProviderIsEmptyException | NoClassDefFoundError e) {
Log.debug("LuckPerms is not available, falling back to Bukkit superperms.");
return new BukkitPermsProvider();
}
}
/**
* Check the permission for sender
*
@@ -2,8 +2,8 @@ package com.ghostchu.quickshop.permission;
public enum PermissionProviderType {
// BUKKIT(0), VAULT(1), LUCKPERMS(2), PERMISSIONEX(3), GROUPMANAGER(4);
BUKKIT(0);
// PERMISSIONEX(3), GROUPMANAGER(4);
BUKKIT(0), LUCKPERMS(2);
final int id;
@@ -1,96 +0,0 @@
package com.ghostchu.quickshop.permission;
import com.ghostchu.quickshop.api.obj.QUser;
import com.ghostchu.quickshop.api.permission.PermissionProvider;
import com.ghostchu.quickshop.api.permission.ProviderIsEmptyException;
import net.milkbowl.vault.permission.Permission;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.jetbrains.annotations.NotNull;
@Deprecated
public class VaultPermissionProvider implements PermissionProvider {
private final Permission api;
@Deprecated
public VaultPermissionProvider() {
RegisteredServiceProvider<Permission> rsp = Bukkit.getServicesManager().getRegistration(Permission.class);
if (rsp == null) {
throw new ProviderIsEmptyException(getName());
}
api = rsp.getProvider();
}
/**
* Get permission provider name
*
* @return The name of permission provider
*/
@Override
public @NotNull String getName() {
return "Vault";
}
/**
* Test the sender has special permission
*
* @param sender CommandSender
* @param permission The permission want to check
* @return hasPermission
*/
@Override
public boolean hasPermission(@NotNull CommandSender sender, @NotNull String permission) {
return api.has(sender, permission);
}
@Override
public boolean hasPermission(@NotNull QUser sender, @NotNull String permission) {
Player player = sender.getBukkitPlayer().orElse(null);
if (player == null) {
return false;
}
return api.has(player, permission);
}
/**
* Get the debug infos in provider
*
* @param sender CommandSender
* @param permission The permission want to check
* @return Debug Infos
*/
public @NotNull PermissionInformationContainer getDebugInfo(@NotNull CommandSender sender,
@NotNull String permission)
{
if (sender instanceof Server) {
return new PermissionInformationContainer(sender, permission, null, "User is Console");
}
OfflinePlayer offlinePlayer = (OfflinePlayer) sender;
return new PermissionInformationContainer(sender, permission, api.getPrimaryGroup(null, offlinePlayer), null);
}
}
@@ -469,7 +469,7 @@ public class SimpleShopManager implements ShopManager, Reloadable {
// Create the basic shop
ContainerShop shop = new ContainerShop(plugin, -1, info.getLocation(), price, info.getItem(), createQUser,
false, ShopType.SELLING, new YamlConfiguration(), null, false, null,
plugin.getJavaPlugin().getName(),
QuickShop.BUILTIN_INVENTORY_WRAPPER_PROVIDER,
plugin.getInventoryWrapperManager().mklink(new BukkitInventoryWrapper((holder).getInventory())),
null, Collections.emptyMap(), new SimpleBenefit());
createShop(shop, info.getSignBlock(), info.isBypassed());