Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework the provider system #5087

Merged
merged 35 commits into from
Jan 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
9771d16
Rework the provider system
JRoy Aug 23, 2022
a6441d7
pop review
JRoy Aug 24, 2022
0f045fb
Merge remote-tracking branch 'upstream/2.x' into rework/providers
JRoy Oct 13, 2022
5edbc5e
Merge branch '2.x' into rework/providers
JRoy Oct 13, 2022
faab19b
kennytv.dmg
JRoy Nov 8, 2022
02b6b1b
Merge branch '2.x' into rework/providers
JRoy Nov 8, 2022
b5b3de9
Merge branch '2.x' into rework/providers
JRoy Dec 26, 2022
ebca72c
Merge remote-tracking branch 'upstream/2.x' into rework/providers
JRoy May 23, 2023
8eac04a
Update provider calls in /bottom
JRoy May 23, 2023
d45af88
Merge branch '2.x' into rework/providers
JRoy May 23, 2023
ea622f8
Merge remote-tracking branch 'upstream/2.x' into rework/providers
JRoy Jul 29, 2023
0008e1c
Merge branch '2.x' into rework/providers
JRoy Aug 22, 2023
4d6558a
Merge branch '2.x' into rework/providers
mdcfe Dec 18, 2023
7f417ef
Add some javadocs
JRoy Dec 21, 2023
0360db3
inline some usages
JRoy Dec 26, 2023
99357fc
Merge branch '2.x' into rework/providers
JRoy Feb 12, 2024
f36c2dc
Merge remote-tracking branch 'upstream/2.x' into rework/providers
JRoy Feb 19, 2024
0dcdb8b
Merge remote-tracking branch 'upstream/2.x' into rework/providers
JRoy Jul 23, 2024
4e5c194
Fix missing test from 1.9-1.12 Spawn Egg Provider
JRoy Jul 23, 2024
f05a9dd
Fix compile/merge errors
JRoy Jul 24, 2024
dda1325
Merge remote-tracking branch 'upstream/2.x' into rework/providers
JRoy Aug 11, 2024
a32ad6f
Merge remote-tracking branch 'upstream/2.x' into rework/providers
JRoy Sep 14, 2024
06c5a86
Merge remote-tracking branch 'upstream/2.x' into rework/providers
JRoy Oct 13, 2024
1018210
Merge remote-tracking branch 'upstream/2.x' into rework/providers
JRoy Nov 9, 2024
8f41b5a
Merge branch '2.x' into rework/providers
JRoy Nov 17, 2024
92c71f2
Merge remote-tracking branch 'upstream/2.x' into rework/providers
JRoy Nov 24, 2024
149110e
Merge remote-tracking branch 'upstream/2.x' into rework/providers
JRoy Nov 24, 2024
2c4576e
fix compile
JRoy Nov 25, 2024
b1c51db
Merge remote-tracking branch 'upstream/2.x' into rework/providers
JRoy Nov 30, 2024
cd007e8
fix compile
JRoy Nov 30, 2024
c8d6f64
Merge branch '2.x' into rework/providers
JRoy Dec 14, 2024
5b146f8
fix issue w/FormattedCommandAliasProvider on 1.8 forks
JRoy Dec 19, 2024
73426f4
fix old provider method call
JRoy Dec 30, 2024
aad0ee5
review concerns
JRoy Dec 30, 2024
a869f09
fix 1.8 spigot compat
JRoy Dec 30, 2024
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
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;
JRoy marked this conversation as resolved.
Show resolved Hide resolved
}
//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());
JRoy marked this conversation as resolved.
Show resolved Hide resolved
} 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
Loading