Skip to content

Commit

Permalink
Rework the provider system (#5087)
Browse files Browse the repository at this point in the history
  • Loading branch information
JRoy authored Jan 1, 2025
1 parent f2af952 commit 5515f9f
Show file tree
Hide file tree
Showing 92 changed files with 750 additions and 587 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.earth2me.essentials;

import java.util.stream.Collectors;
import net.ess3.provider.KnownCommandsProvider;
import org.bukkit.command.Command;
import org.bukkit.command.PluginIdentifiableCommand;
import org.bukkit.plugin.Plugin;
Expand Down Expand Up @@ -67,7 +68,7 @@ public final void addPlugin(final Plugin plugin) {

private List<Map.Entry<String, Command>> getPluginCommands(Plugin plugin) {
final Map<String, Command> commands = new HashMap<>();
for (final Map.Entry<String, Command> entry : ess.getKnownCommandsProvider().getKnownCommands().entrySet()) {
for (final Map.Entry<String, Command> entry : ess.provider(KnownCommandsProvider.class).getKnownCommands().entrySet()) {
if (entry.getValue() instanceof PluginIdentifiableCommand && ((PluginIdentifiableCommand) entry.getValue()).getPlugin().equals(plugin)) {
commands.put(entry.getKey(), entry.getValue());
}
Expand Down
331 changes: 76 additions & 255 deletions Essentials/src/main/java/com/earth2me/essentials/Essentials.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.earth2me.essentials.craftbukkit.Inventories;
import com.earth2me.essentials.utils.MaterialUtil;
import net.ess3.api.IEssentials;
import net.ess3.provider.PersistentDataProvider;
import net.ess3.provider.SpawnerItemProvider;
import org.bukkit.GameMode;
import org.bukkit.block.BlockState;
import org.bukkit.block.CreatureSpawner;
Expand All @@ -26,11 +28,11 @@ public EssentialsBlockListener(final IEssentials ess) {
public void onBlockPlace(final BlockPlaceEvent event) {
final ItemStack is = event.getItemInHand();

if (is.getType() == MaterialUtil.SPAWNER && ess.getPersistentDataProvider().getString(is, "convert") != null) {
if (is.getType() == MaterialUtil.SPAWNER && ess.provider(PersistentDataProvider.class).getString(is, "convert") != null) {
final BlockState blockState = event.getBlockPlaced().getState();
if (blockState instanceof CreatureSpawner) {
final CreatureSpawner spawner = (CreatureSpawner) blockState;
final EntityType type = ess.getSpawnerItemProvider().getEntityType(event.getItemInHand());
final EntityType type = ess.provider(SpawnerItemProvider.class).getEntityType(event.getItemInHand());
if (type != null && Mob.fromBukkitType(type) != null) {
if (ess.getUser(event.getPlayer()).isAuthorized("essentials.spawnerconvert." + Mob.fromBukkitType(type).name().toLowerCase(Locale.ENGLISH))) {
spawner.setSpawnedType(type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
import net.ess3.api.IEssentials;
import net.ess3.api.events.AfkStatusChangeEvent;
import net.ess3.provider.CommandSendListenerProvider;
import net.ess3.provider.FormattedCommandAliasProvider;
import net.ess3.provider.InventoryViewProvider;
import net.ess3.provider.KnownCommandsProvider;
import net.ess3.provider.providers.BukkitCommandSendListenerProvider;
import net.ess3.provider.providers.PaperCommandSendListenerProvider;
import net.essentialsx.api.v2.events.AsyncUserDataLoadEvent;
Expand Down Expand Up @@ -298,7 +301,7 @@ public void onPlayerQuit(final PlayerQuitEvent event) {
}
user.setLogoutLocation();
if (user.isRecipeSee()) {
ess.getInventoryViewProvider().getTopInventory(user.getBase().getOpenInventory()).clear();
ess.provider(InventoryViewProvider.class).getTopInventory(user.getBase().getOpenInventory()).clear();
}

final ArrayList<HumanEntity> viewers = new ArrayList<>(user.getBase().getInventory().getViewers());
Expand Down Expand Up @@ -615,10 +618,10 @@ public void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event)

// If the plugin command does not exist, check if it is an alias from commands.yml
if (ess.getServer().getPluginCommand(cmd) == null) {
final Command knownCommand = ess.getKnownCommandsProvider().getKnownCommands().get(cmd);
final Command knownCommand = ess.provider(KnownCommandsProvider.class).getKnownCommands().get(cmd);
if (knownCommand instanceof FormattedCommandAlias) {
final FormattedCommandAlias command = (FormattedCommandAlias) knownCommand;
for (String fullCommand : ess.getFormattedCommandAliasProvider().createCommands(command, event.getPlayer(), args.split(" "))) {
for (String fullCommand : ess.provider(FormattedCommandAliasProvider.class).createCommands(command, event.getPlayer(), args.split(" "))) {
handlePlayerCommandPreprocess(event, fullCommand);
}
return;
Expand Down Expand Up @@ -892,14 +895,15 @@ public void run() {
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onInventoryClickEvent(final InventoryClickEvent event) {
Player refreshPlayer = null;
final Inventory top = ess.getInventoryViewProvider().getTopInventory(event.getView());
final InventoryViewProvider provider = ess.provider(InventoryViewProvider.class);
final Inventory top = provider.getTopInventory(event.getView());
final InventoryType type = top.getType();

final Inventory clickedInventory;
if (event.getRawSlot() < 0) {
clickedInventory = null;
} else {
clickedInventory = event.getRawSlot() < top.getSize() ? top : ess.getInventoryViewProvider().getBottomInventory(event.getView());
clickedInventory = event.getRawSlot() < top.getSize() ? top : provider.getBottomInventory(event.getView());
}

final User user = ess.getUser((Player) event.getWhoClicked());
Expand Down Expand Up @@ -958,7 +962,8 @@ private boolean isPreventBindingHat(User user, PlayerInventory inventory) {
@EventHandler(priority = EventPriority.MONITOR)
public void onInventoryCloseEvent(final InventoryCloseEvent event) {
Player refreshPlayer = null;
final Inventory top = ess.getInventoryViewProvider().getTopInventory(event.getView());
final InventoryViewProvider provider = ess.provider(InventoryViewProvider.class);
final Inventory top = provider.getTopInventory(event.getView());
final InventoryType type = top.getType();
if (type == InventoryType.PLAYER) {
final User user = ess.getUser((Player) event.getPlayer());
Expand All @@ -972,7 +977,7 @@ public void onInventoryCloseEvent(final InventoryCloseEvent event) {
final User user = ess.getUser((Player) event.getPlayer());
if (user.isRecipeSee()) {
user.setRecipeSee(false);
ess.getInventoryViewProvider().getTopInventory(event.getView()).clear();
provider.getTopInventory(event.getView()).clear();
refreshPlayer = user.getBase();
}
} else if (type == InventoryType.CHEST && top.getSize() == 9) {
Expand Down
62 changes: 6 additions & 56 deletions Essentials/src/main/java/com/earth2me/essentials/IEssentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,7 @@
import com.earth2me.essentials.perm.PermissionsHandler;
import com.earth2me.essentials.updatecheck.UpdateChecker;
import com.earth2me.essentials.userstorage.IUserMap;
import net.ess3.nms.refl.providers.ReflOnlineModeProvider;
import net.ess3.provider.BannerDataProvider;
import net.ess3.provider.BiomeKeyProvider;
import net.ess3.provider.ContainerProvider;
import net.ess3.provider.DamageEventProvider;
import net.ess3.provider.FormattedCommandAliasProvider;
import net.ess3.provider.InventoryViewProvider;
import net.ess3.provider.ItemUnbreakableProvider;
import net.ess3.provider.KnownCommandsProvider;
import net.ess3.provider.MaterialTagProvider;
import net.ess3.provider.PersistentDataProvider;
import net.ess3.provider.PlayerLocaleProvider;
import net.ess3.provider.SerializationProvider;
import net.ess3.provider.ServerStateProvider;
import net.ess3.provider.SignDataProvider;
import net.ess3.provider.SpawnerBlockProvider;
import net.ess3.provider.SpawnerItemProvider;
import net.ess3.provider.SyncCommandsProvider;
import net.ess3.provider.WorldInfoProvider;
import net.ess3.provider.Provider;
import net.essentialsx.api.v2.services.BalanceTop;
import net.essentialsx.api.v2.services.mail.MailService;
import org.bukkit.Server;
Expand Down Expand Up @@ -157,43 +139,11 @@ public interface IEssentials extends Plugin {

Iterable<User> getOnlineUsers();

SpawnerItemProvider getSpawnerItemProvider();

SpawnerBlockProvider getSpawnerBlockProvider();

ServerStateProvider getServerStateProvider();

MaterialTagProvider getMaterialTagProvider();

ContainerProvider getContainerProvider();

KnownCommandsProvider getKnownCommandsProvider();

SerializationProvider getSerializationProvider();

FormattedCommandAliasProvider getFormattedCommandAliasProvider();

SyncCommandsProvider getSyncCommandsProvider();

PersistentDataProvider getPersistentDataProvider();

ReflOnlineModeProvider getOnlineModeProvider();

ItemUnbreakableProvider getItemUnbreakableProvider();

WorldInfoProvider getWorldInfoProvider();

SignDataProvider getSignDataProvider();

PlayerLocaleProvider getPlayerLocaleProvider();

DamageEventProvider getDamageEventProvider();

BiomeKeyProvider getBiomeKeyProvider();

BannerDataProvider getBannerDataProvider();
PluginCommand getPluginCommand(String cmd);

InventoryViewProvider getInventoryViewProvider();
ProviderFactory getProviders();

PluginCommand getPluginCommand(String cmd);
default <P extends Provider> P provider(final Class<P> providerClass) {
return getProviders().get(providerClass);
}
}
6 changes: 4 additions & 2 deletions Essentials/src/main/java/com/earth2me/essentials/Kit.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import net.ess3.api.IEssentials;
import net.ess3.api.TranslatableException;
import net.ess3.api.events.KitClaimEvent;
import net.ess3.provider.SerializationProvider;
import net.essentialsx.api.v2.events.KitPreExpandItemsEvent;
import org.bukkit.Bukkit;
import org.bukkit.Material;
Expand Down Expand Up @@ -191,13 +192,14 @@ public boolean expandItems(final User user, final List<String> items) throws Exc
}

final ItemStack stack;
final SerializationProvider serializationProvider = ess.provider(SerializationProvider.class);

if (kitItem.startsWith("@")) {
if (ess.getSerializationProvider() == null) {
if (serializationProvider == null) {
ess.getLogger().log(Level.WARNING, AdventureUtil.miniToLegacy(tlLiteral("kitError3", kitName, user.getName())));
continue;
}
stack = ess.getSerializationProvider().deserializeItem(Base64Coder.decodeLines(kitItem.substring(1)));
stack = serializationProvider.deserializeItem(Base64Coder.decodeLines(kitItem.substring(1)));
} else {
final String[] parts = kitItem.split(" +");
final ItemStack parseStack = ess.getItemDb().get(parts[0], parts.length > 1 ? Integer.parseInt(parts[1]) : 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
import com.google.common.base.Joiner;
import net.ess3.api.IEssentials;
import net.ess3.api.TranslatableException;
import net.ess3.provider.BannerDataProvider;
import net.ess3.provider.ItemUnbreakableProvider;
import net.ess3.provider.PotionMetaProvider;
import org.bukkit.Color;
import org.bukkit.DyeColor;
import org.bukkit.FireworkEffect;
Expand Down Expand Up @@ -565,7 +568,7 @@ public void addPotionMeta(final CommandSource sender, final boolean allowShortNa
}
pmeta.addCustomEffect(pEffect, true);
stack.setItemMeta(pmeta);
ess.getPotionMetaProvider().setSplashPotion(stack, isSplashPotion);
ess.provider(PotionMetaProvider.class).setSplashPotion(stack, isSplashPotion);
resetPotionMeta();
}
}
Expand Down Expand Up @@ -655,7 +658,7 @@ public void addBannerMeta(final CommandSource sender, final boolean allowShortNa
final BannerMeta meta = (BannerMeta) stack.getItemMeta();
if (split[0].equalsIgnoreCase("basecolor")) {
final Color color = Color.fromRGB(Integer.parseInt(split[1]));
ess.getBannerDataProvider().setBaseColor(stack, DyeColor.getByColor(color));
ess.provider(BannerDataProvider.class).setBaseColor(stack, DyeColor.getByColor(color));
} else if (patternType != null) {
//noinspection removal
final PatternType type = PatternType.getByIdentifier(split[0]);
Expand Down Expand Up @@ -718,7 +721,7 @@ private boolean hasMetaPermission(final User user, final String metaPerm, final

private void setUnbreakable(final IEssentials ess, final ItemStack is, final boolean unbreakable) {
final ItemMeta meta = is.getItemMeta();
ess.getItemUnbreakableProvider().setUnbreakable(meta, unbreakable);
ess.provider(ItemUnbreakableProvider.class).setUnbreakable(meta, unbreakable);
is.setItemMeta(meta);
}
}
137 changes: 137 additions & 0 deletions Essentials/src/main/java/com/earth2me/essentials/ProviderFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package com.earth2me.essentials;

import io.papermc.lib.PaperLib;
import net.ess3.provider.Provider;
import net.essentialsx.providers.NullableProvider;
import net.essentialsx.providers.ProviderData;
import net.essentialsx.providers.ProviderTest;
import org.bukkit.plugin.Plugin;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;

public class ProviderFactory {
private final Map<Class<? extends Provider>, Provider> providers = new HashMap<>();
private final Map<Class<? extends Provider>, List<Class<? extends Provider>>> registeredProviders = new HashMap<>();
private final Essentials essentials;

public ProviderFactory(final Essentials essentials) {
this.essentials = essentials;
}

/**
* Gets the provider which has been selected for the given type.
* @param providerClass The provider type.
* @return the provider or null if no provider could be selected for that type.
*/
public <P extends Provider> P get(final Class<P> providerClass) {
final Provider provider = providers.get(providerClass);
if (provider == null) {
return null;
}
//noinspection unchecked
return (P) provider;
}

@SafeVarargs
public final void registerProvider(final Class<? extends Provider>... toRegister) {
for (final Class<? extends Provider> provider : toRegister) {
final Class<?> superclass = provider.getInterfaces().length > 0 ? provider.getInterfaces()[0] : provider.getSuperclass();
if (Provider.class.isAssignableFrom(superclass)) {
//noinspection unchecked
registeredProviders.computeIfAbsent((Class<? extends Provider>) superclass, k -> new ArrayList<>()).add(provider);
if (essentials.getSettings().isDebug()) {
essentials.getLogger().info("Registered provider " + provider.getSimpleName() + " for " + superclass.getSimpleName());
}
}
}
}

public void finalizeRegistration() {
for (final Map.Entry<Class<? extends Provider>, List<Class<? extends Provider>>> entry : registeredProviders.entrySet()) {
final Class<? extends Provider> providerClass = entry.getKey();
final boolean nullable = providerClass.isAnnotationPresent(NullableProvider.class);
Class<? extends Provider> highestProvider = null;
ProviderData highestProviderData = null;
int highestWeight = -1;
for (final Class<? extends Provider> provider : entry.getValue()) {
try {
final ProviderData providerData = provider.getAnnotation(ProviderData.class);
if (providerData.weight() > highestWeight && testProvider(provider)) {
highestWeight = providerData.weight();
highestProvider = provider;
highestProviderData = providerData;
}
} catch (final Exception e) {
essentials.getLogger().log(Level.SEVERE, "Failed to initialize provider " + provider.getName(), e);
}
}

if (highestProvider != null) {
essentials.getLogger().info("Selected " + highestProviderData.description() + " as the provider for " + providerClass.getSimpleName());
providers.put(providerClass, getProviderInstance(highestProvider));
} else if (!nullable) {
throw new IllegalStateException("No provider found for " + providerClass.getName());
} else {
essentials.getLogger().info("No provider found for " + providerClass.getSimpleName() + ", but it is nullable");
}
}
registeredProviders.clear();
}

private boolean testProvider(final Class<?> providerClass) throws InvocationTargetException, IllegalAccessException {
try {
for (final Method method : providerClass.getMethods()) {
if (method.isAnnotationPresent(ProviderTest.class)) {
return (Boolean) method.invoke(null);
}
}
return true;
} catch (final NoClassDefFoundError ignored) {
return false;
}
}

private <P extends Provider> P getProviderInstance(final Class<P> provider) {
try {
final Constructor<?> constructor = provider.getConstructors()[0];
if (constructor.getParameterTypes().length == 0) {
//noinspection unchecked
return (P) constructor.newInstance();
}
final Object[] args = new Object[constructor.getParameterTypes().length];

/*
Providers can have constructors with any of the following types, and this code will automatically supply them;
- Plugin - The Essentials instance will be passed
- boolean - True will be passed if this server is running Paper, otherwise false.
*/
for (int i = 0; i < args.length; i++) {
final Class<?> paramType = constructor.getParameterTypes()[i];
if (paramType.isAssignableFrom(Plugin.class)) {
args[i] = essentials;
} else if (paramType.isAssignableFrom(boolean.class)) {
args[i] = PaperLib.isPaper();
} else {
throw new IllegalArgumentException("Unsupported parameter type " + paramType.getName());
}
}

//noinspection unchecked
return (P) constructor.newInstance(args);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
try {
return provider.getConstructor().newInstance();
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException ex) {
e.printStackTrace();
throw new RuntimeException(ex);
}
}
}
}
Loading

0 comments on commit 5515f9f

Please sign in to comment.