Skip to content

Commit 5515f9f

Browse files
authored
Rework the provider system (#5087)
1 parent f2af952 commit 5515f9f

File tree

92 files changed

+750
-587
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+750
-587
lines changed

Essentials/src/main/java/com/earth2me/essentials/AlternativeCommandsHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.earth2me.essentials;
22

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

6869
private List<Map.Entry<String, Command>> getPluginCommands(Plugin plugin) {
6970
final Map<String, Command> commands = new HashMap<>();
70-
for (final Map.Entry<String, Command> entry : ess.getKnownCommandsProvider().getKnownCommands().entrySet()) {
71+
for (final Map.Entry<String, Command> entry : ess.provider(KnownCommandsProvider.class).getKnownCommands().entrySet()) {
7172
if (entry.getValue() instanceof PluginIdentifiableCommand && ((PluginIdentifiableCommand) entry.getValue()).getPlugin().equals(plugin)) {
7273
commands.put(entry.getKey(), entry.getValue());
7374
}

Essentials/src/main/java/com/earth2me/essentials/Essentials.java

Lines changed: 76 additions & 255 deletions
Large diffs are not rendered by default.

Essentials/src/main/java/com/earth2me/essentials/EssentialsBlockListener.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import com.earth2me.essentials.craftbukkit.Inventories;
44
import com.earth2me.essentials.utils.MaterialUtil;
55
import net.ess3.api.IEssentials;
6+
import net.ess3.provider.PersistentDataProvider;
7+
import net.ess3.provider.SpawnerItemProvider;
68
import org.bukkit.GameMode;
79
import org.bukkit.block.BlockState;
810
import org.bukkit.block.CreatureSpawner;
@@ -26,11 +28,11 @@ public EssentialsBlockListener(final IEssentials ess) {
2628
public void onBlockPlace(final BlockPlaceEvent event) {
2729
final ItemStack is = event.getItemInHand();
2830

29-
if (is.getType() == MaterialUtil.SPAWNER && ess.getPersistentDataProvider().getString(is, "convert") != null) {
31+
if (is.getType() == MaterialUtil.SPAWNER && ess.provider(PersistentDataProvider.class).getString(is, "convert") != null) {
3032
final BlockState blockState = event.getBlockPlaced().getState();
3133
if (blockState instanceof CreatureSpawner) {
3234
final CreatureSpawner spawner = (CreatureSpawner) blockState;
33-
final EntityType type = ess.getSpawnerItemProvider().getEntityType(event.getItemInHand());
35+
final EntityType type = ess.provider(SpawnerItemProvider.class).getEntityType(event.getItemInHand());
3436
if (type != null && Mob.fromBukkitType(type) != null) {
3537
if (ess.getUser(event.getPlayer()).isAuthorized("essentials.spawnerconvert." + Mob.fromBukkitType(type).name().toLowerCase(Locale.ENGLISH))) {
3638
spawner.setSpawnedType(type);

Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
import net.ess3.api.IEssentials;
1818
import net.ess3.api.events.AfkStatusChangeEvent;
1919
import net.ess3.provider.CommandSendListenerProvider;
20+
import net.ess3.provider.FormattedCommandAliasProvider;
21+
import net.ess3.provider.InventoryViewProvider;
22+
import net.ess3.provider.KnownCommandsProvider;
2023
import net.ess3.provider.providers.BukkitCommandSendListenerProvider;
2124
import net.ess3.provider.providers.PaperCommandSendListenerProvider;
2225
import net.essentialsx.api.v2.events.AsyncUserDataLoadEvent;
@@ -298,7 +301,7 @@ public void onPlayerQuit(final PlayerQuitEvent event) {
298301
}
299302
user.setLogoutLocation();
300303
if (user.isRecipeSee()) {
301-
ess.getInventoryViewProvider().getTopInventory(user.getBase().getOpenInventory()).clear();
304+
ess.provider(InventoryViewProvider.class).getTopInventory(user.getBase().getOpenInventory()).clear();
302305
}
303306

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

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

898902
final Inventory clickedInventory;
899903
if (event.getRawSlot() < 0) {
900904
clickedInventory = null;
901905
} else {
902-
clickedInventory = event.getRawSlot() < top.getSize() ? top : ess.getInventoryViewProvider().getBottomInventory(event.getView());
906+
clickedInventory = event.getRawSlot() < top.getSize() ? top : provider.getBottomInventory(event.getView());
903907
}
904908

905909
final User user = ess.getUser((Player) event.getWhoClicked());
@@ -958,7 +962,8 @@ private boolean isPreventBindingHat(User user, PlayerInventory inventory) {
958962
@EventHandler(priority = EventPriority.MONITOR)
959963
public void onInventoryCloseEvent(final InventoryCloseEvent event) {
960964
Player refreshPlayer = null;
961-
final Inventory top = ess.getInventoryViewProvider().getTopInventory(event.getView());
965+
final InventoryViewProvider provider = ess.provider(InventoryViewProvider.class);
966+
final Inventory top = provider.getTopInventory(event.getView());
962967
final InventoryType type = top.getType();
963968
if (type == InventoryType.PLAYER) {
964969
final User user = ess.getUser((Player) event.getPlayer());
@@ -972,7 +977,7 @@ public void onInventoryCloseEvent(final InventoryCloseEvent event) {
972977
final User user = ess.getUser((Player) event.getPlayer());
973978
if (user.isRecipeSee()) {
974979
user.setRecipeSee(false);
975-
ess.getInventoryViewProvider().getTopInventory(event.getView()).clear();
980+
provider.getTopInventory(event.getView()).clear();
976981
refreshPlayer = user.getBase();
977982
}
978983
} else if (type == InventoryType.CHEST && top.getSize() == 9) {

Essentials/src/main/java/com/earth2me/essentials/IEssentials.java

Lines changed: 6 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,7 @@
88
import com.earth2me.essentials.perm.PermissionsHandler;
99
import com.earth2me.essentials.updatecheck.UpdateChecker;
1010
import com.earth2me.essentials.userstorage.IUserMap;
11-
import net.ess3.nms.refl.providers.ReflOnlineModeProvider;
12-
import net.ess3.provider.BannerDataProvider;
13-
import net.ess3.provider.BiomeKeyProvider;
14-
import net.ess3.provider.ContainerProvider;
15-
import net.ess3.provider.DamageEventProvider;
16-
import net.ess3.provider.FormattedCommandAliasProvider;
17-
import net.ess3.provider.InventoryViewProvider;
18-
import net.ess3.provider.ItemUnbreakableProvider;
19-
import net.ess3.provider.KnownCommandsProvider;
20-
import net.ess3.provider.MaterialTagProvider;
21-
import net.ess3.provider.PersistentDataProvider;
22-
import net.ess3.provider.PlayerLocaleProvider;
23-
import net.ess3.provider.SerializationProvider;
24-
import net.ess3.provider.ServerStateProvider;
25-
import net.ess3.provider.SignDataProvider;
26-
import net.ess3.provider.SpawnerBlockProvider;
27-
import net.ess3.provider.SpawnerItemProvider;
28-
import net.ess3.provider.SyncCommandsProvider;
29-
import net.ess3.provider.WorldInfoProvider;
11+
import net.ess3.provider.Provider;
3012
import net.essentialsx.api.v2.services.BalanceTop;
3113
import net.essentialsx.api.v2.services.mail.MailService;
3214
import org.bukkit.Server;
@@ -157,43 +139,11 @@ public interface IEssentials extends Plugin {
157139

158140
Iterable<User> getOnlineUsers();
159141

160-
SpawnerItemProvider getSpawnerItemProvider();
161-
162-
SpawnerBlockProvider getSpawnerBlockProvider();
163-
164-
ServerStateProvider getServerStateProvider();
165-
166-
MaterialTagProvider getMaterialTagProvider();
167-
168-
ContainerProvider getContainerProvider();
169-
170-
KnownCommandsProvider getKnownCommandsProvider();
171-
172-
SerializationProvider getSerializationProvider();
173-
174-
FormattedCommandAliasProvider getFormattedCommandAliasProvider();
175-
176-
SyncCommandsProvider getSyncCommandsProvider();
177-
178-
PersistentDataProvider getPersistentDataProvider();
179-
180-
ReflOnlineModeProvider getOnlineModeProvider();
181-
182-
ItemUnbreakableProvider getItemUnbreakableProvider();
183-
184-
WorldInfoProvider getWorldInfoProvider();
185-
186-
SignDataProvider getSignDataProvider();
187-
188-
PlayerLocaleProvider getPlayerLocaleProvider();
189-
190-
DamageEventProvider getDamageEventProvider();
191-
192-
BiomeKeyProvider getBiomeKeyProvider();
193-
194-
BannerDataProvider getBannerDataProvider();
142+
PluginCommand getPluginCommand(String cmd);
195143

196-
InventoryViewProvider getInventoryViewProvider();
144+
ProviderFactory getProviders();
197145

198-
PluginCommand getPluginCommand(String cmd);
146+
default <P extends Provider> P provider(final Class<P> providerClass) {
147+
return getProviders().get(providerClass);
148+
}
199149
}

Essentials/src/main/java/com/earth2me/essentials/Kit.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import net.ess3.api.IEssentials;
1313
import net.ess3.api.TranslatableException;
1414
import net.ess3.api.events.KitClaimEvent;
15+
import net.ess3.provider.SerializationProvider;
1516
import net.essentialsx.api.v2.events.KitPreExpandItemsEvent;
1617
import org.bukkit.Bukkit;
1718
import org.bukkit.Material;
@@ -191,13 +192,14 @@ public boolean expandItems(final User user, final List<String> items) throws Exc
191192
}
192193

193194
final ItemStack stack;
195+
final SerializationProvider serializationProvider = ess.provider(SerializationProvider.class);
194196

195197
if (kitItem.startsWith("@")) {
196-
if (ess.getSerializationProvider() == null) {
198+
if (serializationProvider == null) {
197199
ess.getLogger().log(Level.WARNING, AdventureUtil.miniToLegacy(tlLiteral("kitError3", kitName, user.getName())));
198200
continue;
199201
}
200-
stack = ess.getSerializationProvider().deserializeItem(Base64Coder.decodeLines(kitItem.substring(1)));
202+
stack = serializationProvider.deserializeItem(Base64Coder.decodeLines(kitItem.substring(1)));
201203
} else {
202204
final String[] parts = kitItem.split(" +");
203205
final ItemStack parseStack = ess.getItemDb().get(parts[0], parts.length > 1 ? Integer.parseInt(parts[1]) : 1);

Essentials/src/main/java/com/earth2me/essentials/MetaItemStack.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
import com.google.common.base.Joiner;
1212
import net.ess3.api.IEssentials;
1313
import net.ess3.api.TranslatableException;
14+
import net.ess3.provider.BannerDataProvider;
15+
import net.ess3.provider.ItemUnbreakableProvider;
16+
import net.ess3.provider.PotionMetaProvider;
1417
import org.bukkit.Color;
1518
import org.bukkit.DyeColor;
1619
import org.bukkit.FireworkEffect;
@@ -565,7 +568,7 @@ public void addPotionMeta(final CommandSource sender, final boolean allowShortNa
565568
}
566569
pmeta.addCustomEffect(pEffect, true);
567570
stack.setItemMeta(pmeta);
568-
ess.getPotionMetaProvider().setSplashPotion(stack, isSplashPotion);
571+
ess.provider(PotionMetaProvider.class).setSplashPotion(stack, isSplashPotion);
569572
resetPotionMeta();
570573
}
571574
}
@@ -655,7 +658,7 @@ public void addBannerMeta(final CommandSource sender, final boolean allowShortNa
655658
final BannerMeta meta = (BannerMeta) stack.getItemMeta();
656659
if (split[0].equalsIgnoreCase("basecolor")) {
657660
final Color color = Color.fromRGB(Integer.parseInt(split[1]));
658-
ess.getBannerDataProvider().setBaseColor(stack, DyeColor.getByColor(color));
661+
ess.provider(BannerDataProvider.class).setBaseColor(stack, DyeColor.getByColor(color));
659662
} else if (patternType != null) {
660663
//noinspection removal
661664
final PatternType type = PatternType.getByIdentifier(split[0]);
@@ -718,7 +721,7 @@ private boolean hasMetaPermission(final User user, final String metaPerm, final
718721

719722
private void setUnbreakable(final IEssentials ess, final ItemStack is, final boolean unbreakable) {
720723
final ItemMeta meta = is.getItemMeta();
721-
ess.getItemUnbreakableProvider().setUnbreakable(meta, unbreakable);
724+
ess.provider(ItemUnbreakableProvider.class).setUnbreakable(meta, unbreakable);
722725
is.setItemMeta(meta);
723726
}
724727
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package com.earth2me.essentials;
2+
3+
import io.papermc.lib.PaperLib;
4+
import net.ess3.provider.Provider;
5+
import net.essentialsx.providers.NullableProvider;
6+
import net.essentialsx.providers.ProviderData;
7+
import net.essentialsx.providers.ProviderTest;
8+
import org.bukkit.plugin.Plugin;
9+
10+
import java.lang.reflect.Constructor;
11+
import java.lang.reflect.InvocationTargetException;
12+
import java.lang.reflect.Method;
13+
import java.util.ArrayList;
14+
import java.util.HashMap;
15+
import java.util.List;
16+
import java.util.Map;
17+
import java.util.logging.Level;
18+
19+
public class ProviderFactory {
20+
private final Map<Class<? extends Provider>, Provider> providers = new HashMap<>();
21+
private final Map<Class<? extends Provider>, List<Class<? extends Provider>>> registeredProviders = new HashMap<>();
22+
private final Essentials essentials;
23+
24+
public ProviderFactory(final Essentials essentials) {
25+
this.essentials = essentials;
26+
}
27+
28+
/**
29+
* Gets the provider which has been selected for the given type.
30+
* @param providerClass The provider type.
31+
* @return the provider or null if no provider could be selected for that type.
32+
*/
33+
public <P extends Provider> P get(final Class<P> providerClass) {
34+
final Provider provider = providers.get(providerClass);
35+
if (provider == null) {
36+
return null;
37+
}
38+
//noinspection unchecked
39+
return (P) provider;
40+
}
41+
42+
@SafeVarargs
43+
public final void registerProvider(final Class<? extends Provider>... toRegister) {
44+
for (final Class<? extends Provider> provider : toRegister) {
45+
final Class<?> superclass = provider.getInterfaces().length > 0 ? provider.getInterfaces()[0] : provider.getSuperclass();
46+
if (Provider.class.isAssignableFrom(superclass)) {
47+
//noinspection unchecked
48+
registeredProviders.computeIfAbsent((Class<? extends Provider>) superclass, k -> new ArrayList<>()).add(provider);
49+
if (essentials.getSettings().isDebug()) {
50+
essentials.getLogger().info("Registered provider " + provider.getSimpleName() + " for " + superclass.getSimpleName());
51+
}
52+
}
53+
}
54+
}
55+
56+
public void finalizeRegistration() {
57+
for (final Map.Entry<Class<? extends Provider>, List<Class<? extends Provider>>> entry : registeredProviders.entrySet()) {
58+
final Class<? extends Provider> providerClass = entry.getKey();
59+
final boolean nullable = providerClass.isAnnotationPresent(NullableProvider.class);
60+
Class<? extends Provider> highestProvider = null;
61+
ProviderData highestProviderData = null;
62+
int highestWeight = -1;
63+
for (final Class<? extends Provider> provider : entry.getValue()) {
64+
try {
65+
final ProviderData providerData = provider.getAnnotation(ProviderData.class);
66+
if (providerData.weight() > highestWeight && testProvider(provider)) {
67+
highestWeight = providerData.weight();
68+
highestProvider = provider;
69+
highestProviderData = providerData;
70+
}
71+
} catch (final Exception e) {
72+
essentials.getLogger().log(Level.SEVERE, "Failed to initialize provider " + provider.getName(), e);
73+
}
74+
}
75+
76+
if (highestProvider != null) {
77+
essentials.getLogger().info("Selected " + highestProviderData.description() + " as the provider for " + providerClass.getSimpleName());
78+
providers.put(providerClass, getProviderInstance(highestProvider));
79+
} else if (!nullable) {
80+
throw new IllegalStateException("No provider found for " + providerClass.getName());
81+
} else {
82+
essentials.getLogger().info("No provider found for " + providerClass.getSimpleName() + ", but it is nullable");
83+
}
84+
}
85+
registeredProviders.clear();
86+
}
87+
88+
private boolean testProvider(final Class<?> providerClass) throws InvocationTargetException, IllegalAccessException {
89+
try {
90+
for (final Method method : providerClass.getMethods()) {
91+
if (method.isAnnotationPresent(ProviderTest.class)) {
92+
return (Boolean) method.invoke(null);
93+
}
94+
}
95+
return true;
96+
} catch (final NoClassDefFoundError ignored) {
97+
return false;
98+
}
99+
}
100+
101+
private <P extends Provider> P getProviderInstance(final Class<P> provider) {
102+
try {
103+
final Constructor<?> constructor = provider.getConstructors()[0];
104+
if (constructor.getParameterTypes().length == 0) {
105+
//noinspection unchecked
106+
return (P) constructor.newInstance();
107+
}
108+
final Object[] args = new Object[constructor.getParameterTypes().length];
109+
110+
/*
111+
Providers can have constructors with any of the following types, and this code will automatically supply them;
112+
- Plugin - The Essentials instance will be passed
113+
- boolean - True will be passed if this server is running Paper, otherwise false.
114+
*/
115+
for (int i = 0; i < args.length; i++) {
116+
final Class<?> paramType = constructor.getParameterTypes()[i];
117+
if (paramType.isAssignableFrom(Plugin.class)) {
118+
args[i] = essentials;
119+
} else if (paramType.isAssignableFrom(boolean.class)) {
120+
args[i] = PaperLib.isPaper();
121+
} else {
122+
throw new IllegalArgumentException("Unsupported parameter type " + paramType.getName());
123+
}
124+
}
125+
126+
//noinspection unchecked
127+
return (P) constructor.newInstance(args);
128+
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
129+
try {
130+
return provider.getConstructor().newInstance();
131+
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException ex) {
132+
e.printStackTrace();
133+
throw new RuntimeException(ex);
134+
}
135+
}
136+
}
137+
}

0 commit comments

Comments
 (0)