Compare commits

..

22 Commits

Author SHA1 Message Date
Auxilor
d081afbd8e Improved command sync 2022-11-06 19:23:11 +00:00
Auxilor
46fd0439a5 Fixed dynamic command reg 2022-11-06 19:17:21 +00:00
Auxilor
ad58ce4a74 GUI Fixes + Improvements 2022-11-06 14:21:49 +00:00
Auxilor
b5cd8f42e0 Fixed illusioner goals 2022-11-05 21:25:52 +00:00
Auxilor
d0baf50709 Fixed illusioner goals 2022-11-04 15:07:34 +00:00
Auxilor
2496f318fa Removed health-fixer 2022-11-04 13:57:16 +00:00
Auxilor
048c200c95 Changed ConfiguredPrice to be a delegate 2022-11-01 22:05:25 +00:00
Auxilor
17446acb2e Fixed javadoc 2022-11-01 21:55:56 +00:00
Auxilor
7929113c91 Improved PriceItem 2022-11-01 21:53:27 +00:00
Auxilor
6acc5864bd Reworked Price API (again) 2022-11-01 21:36:09 +00:00
Auxilor
730c20dbc0 Added Testable Extensions 2022-10-30 16:53:29 +00:00
Auxilor
0c5ae54c3a Codestyle 2022-10-30 16:34:08 +00:00
Auxilor
b48e80837d Fixed javadoc 2022-10-30 16:32:30 +00:00
Auxilor
17eb4cf5f8 Added alias and description support to PluginCommand 2022-10-30 16:02:44 +00:00
Auxilor
890f85fa56 Added Player versions of onExecute and tabComplete 2022-10-30 15:58:14 +00:00
Auxilor
86b427c95e Improved commands 2022-10-30 15:21:21 +00:00
Auxilor
8c1fde57b0 Improved DelegatedBukkitCommand 2022-10-30 15:03:17 +00:00
Auxilor
2efc040a8e Added dynamic command registration 2022-10-29 19:06:15 +01:00
Auxilor
54b2b42512 Added price multipliers 2022-10-29 16:53:24 +01:00
Auxilor
e67d9d634c Fixed javadoc 2022-10-29 16:34:18 +01:00
Auxilor
39fb676b9a Updated to 6.45.0 2022-10-29 16:28:57 +01:00
Auxilor
ec8936b765 Updated price API 2022-10-29 16:28:48 +01:00
36 changed files with 733 additions and 285 deletions

View File

@@ -136,7 +136,6 @@ public interface Eco {
* *
* @param plugin The plugin. * @param plugin The plugin.
*/ */
@NotNull
void createPAPIIntegration(@NotNull EcoPlugin plugin); void createPAPIIntegration(@NotNull EcoPlugin plugin);
/** /**
@@ -169,6 +168,7 @@ public interface Eco {
* @param requiresChangesToSave If the config must be changed in order to save the config. * @param requiresChangesToSave If the config must be changed in order to save the config.
* @return The config implementation. * @return The config implementation.
*/ */
@NotNull
LoadableConfig createUpdatableConfig(@NotNull String configName, LoadableConfig createUpdatableConfig(@NotNull String configName,
@NotNull PluginLike plugin, @NotNull PluginLike plugin,
@NotNull String subDirectoryPath, @NotNull String subDirectoryPath,
@@ -189,6 +189,7 @@ public interface Eco {
* @param requiresChangesToSave If the config must be changed in order to save the config. * @param requiresChangesToSave If the config must be changed in order to save the config.
* @return The config implementation. * @return The config implementation.
*/ */
@NotNull
LoadableConfig createLoadableConfig(@NotNull String configName, LoadableConfig createLoadableConfig(@NotNull String configName,
@NotNull PluginLike plugin, @NotNull PluginLike plugin,
@NotNull String subDirectoryPath, @NotNull String subDirectoryPath,
@@ -202,6 +203,7 @@ public interface Eco {
* @param config The handle. * @param config The handle.
* @return The config implementation. * @return The config implementation.
*/ */
@NotNull
Config wrapConfigurationSection(@NotNull ConfigurationSection config); Config wrapConfigurationSection(@NotNull ConfigurationSection config);
/** /**
@@ -211,6 +213,7 @@ public interface Eco {
* @param type The config type. * @param type The config type.
* @return The config implementation. * @return The config implementation.
*/ */
@NotNull
Config createConfig(@NotNull Map<String, Object> values, Config createConfig(@NotNull Map<String, Object> values,
@NotNull ConfigType type); @NotNull ConfigType type);
@@ -221,6 +224,7 @@ public interface Eco {
* @param type The type. * @param type The type.
* @return The config implementation. * @return The config implementation.
*/ */
@NotNull
Config createConfig(@NotNull String contents, Config createConfig(@NotNull String contents,
@NotNull ConfigType type); @NotNull ConfigType type);
@@ -331,6 +335,7 @@ public interface Eco {
* *
* @return The keys. * @return The keys.
*/ */
@NotNull
Set<PersistentDataKey<?>> getRegisteredPersistentDataKeys(); Set<PersistentDataKey<?>> getRegisteredPersistentDataKeys();
/** /**
@@ -339,6 +344,7 @@ public interface Eco {
* @param uuid The UUID. * @param uuid The UUID.
* @return The profile. * @return The profile.
*/ */
@NotNull
PlayerProfile loadPlayerProfile(@NotNull UUID uuid); PlayerProfile loadPlayerProfile(@NotNull UUID uuid);
/** /**
@@ -346,6 +352,7 @@ public interface Eco {
* *
* @return The profile. * @return The profile.
*/ */
@NotNull
ServerProfile getServerProfile(); ServerProfile getServerProfile();
/** /**
@@ -498,6 +505,11 @@ public interface Eco {
@Nullable @Nullable
Menu getOpenMenu(@NotNull Player player); Menu getOpenMenu(@NotNull Player player);
/**
* Sync commands.
*/
void syncCommands();
/** /**
* Get the instance of eco; the bridge between the api frontend * Get the instance of eco; the bridge between the api frontend
* and the implementation backend. * and the implementation backend.

View File

@@ -1,7 +1,9 @@
package com.willfp.eco.core.command; package com.willfp.eco.core.command;
import com.google.common.collect.ImmutableList;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
@@ -43,8 +45,6 @@ public interface CommandBase {
/** /**
* Handle command execution. * Handle command execution.
* <p>
* Marked as default void with no implementation for backwards compatibility.
* *
* @param sender The sender. * @param sender The sender.
* @param args The args. * @param args The args.
@@ -54,20 +54,43 @@ public interface CommandBase {
// Do nothing. // Do nothing.
} }
/**
* Handle command execution from players.
*
* @param sender The sender.
* @param args The args.
*/
default void onExecute(@NotNull Player sender,
@NotNull List<String> args) {
// Do nothing.
}
/** /**
* Handle tab completion. * Handle tab completion.
* <p>
* Marked as default void with no implementation for backwards compatibility.
* *
* @param sender The sender. * @param sender The sender.
* @param args The args. * @param args The args.
* @return The results. * @return The results.
*/ */
@NotNull
default List<String> tabComplete(@NotNull CommandSender sender, default List<String> tabComplete(@NotNull CommandSender sender,
@NotNull List<String> args) { @NotNull List<String> args) {
return new ArrayList<>(); return new ArrayList<>();
} }
/**
* Handle tab completion.
*
* @param sender The sender.
* @param args The args.
* @return The results.
*/
@NotNull
default List<String> tabComplete(@NotNull Player sender,
@NotNull List<String> args) {
return new ArrayList<>();
}
/** /**
* Get the plugin. * Get the plugin.
* *
@@ -83,7 +106,11 @@ public interface CommandBase {
* @deprecated Use {@link CommandBase#onExecute(CommandSender, List)} instead. * @deprecated Use {@link CommandBase#onExecute(CommandSender, List)} instead.
*/ */
@Deprecated(forRemoval = true) @Deprecated(forRemoval = true)
CommandHandler getHandler(); default CommandHandler getHandler() {
return (a, b) -> {
};
}
/** /**
* Set the handler. * Set the handler.
@@ -93,7 +120,9 @@ public interface CommandBase {
* @deprecated Handlers have been deprecated. * @deprecated Handlers have been deprecated.
*/ */
@Deprecated(forRemoval = true) @Deprecated(forRemoval = true)
void setHandler(@NotNull CommandHandler handler); default void setHandler(@NotNull final CommandHandler handler) {
// Do nothing.
}
/** /**
* Get the tab completer. * Get the tab completer.
@@ -103,7 +132,9 @@ public interface CommandBase {
* @deprecated Use {@link CommandBase#tabComplete(CommandSender, List)} instead. * @deprecated Use {@link CommandBase#tabComplete(CommandSender, List)} instead.
*/ */
@Deprecated(forRemoval = true) @Deprecated(forRemoval = true)
TabCompleteHandler getTabCompleter(); default TabCompleteHandler getTabCompleter() {
return (a, b) -> ImmutableList.of();
}
/** /**
* Set the tab completer. * Set the tab completer.
@@ -113,5 +144,7 @@ public interface CommandBase {
* @deprecated Handlers have been deprecated. * @deprecated Handlers have been deprecated.
*/ */
@Deprecated(forRemoval = true) @Deprecated(forRemoval = true)
void setTabCompleter(@NotNull TabCompleteHandler handler); default void setTabCompleter(@NotNull final TabCompleteHandler handler) {
// Do nothing.
}
} }

View File

@@ -0,0 +1,71 @@
package com.willfp.eco.core.command.impl;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginIdentifiableCommand;
import org.bukkit.command.TabCompleter;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* Delegates a bukkit command to an eco command (for registrations).
*/
public final class DelegatedBukkitCommand extends Command implements TabCompleter, PluginIdentifiableCommand {
/**
* The delegate command.
*/
private final PluginCommand delegate;
/**
* Create a new delegated command.
*
* @param delegate The delegate.
*/
public DelegatedBukkitCommand(@NotNull final PluginCommand delegate) {
super(delegate.getName());
this.delegate = delegate;
}
@Override
public boolean execute(@NotNull final CommandSender commandSender,
@NotNull final String label,
@NotNull final String[] args) {
return delegate.onCommand(commandSender, this, label, args);
}
@Override
public List<String> onTabComplete(@NotNull final CommandSender commandSender,
@NotNull final Command command,
@NotNull final String label,
@NotNull final String[] args) {
return delegate.onTabComplete(commandSender, command, label, args);
}
@NotNull
@Override
public Plugin getPlugin() {
return this.delegate.getPlugin();
}
@Nullable
@Override
public String getPermission() {
return this.delegate.getPermission();
}
@NotNull
@Override
public String getDescription() {
return this.delegate.getDescription() == null ? "" : this.delegate.getDescription();
}
@NotNull
@Override
public List<String> getAliases() {
return this.delegate.getAliases();
}
}

View File

@@ -145,6 +145,9 @@ abstract class HandledCommand implements CommandBase {
this.getHandler().onExecute(sender, Arrays.asList(args)); this.getHandler().onExecute(sender, Arrays.asList(args));
} else { } else {
this.onExecute(sender, Arrays.asList(args)); this.onExecute(sender, Arrays.asList(args));
if (sender instanceof Player player) {
this.onExecute(player, Arrays.asList(args));
}
} }
} }
@@ -202,7 +205,11 @@ abstract class HandledCommand implements CommandBase {
if (this.getTabCompleter() != null) { if (this.getTabCompleter() != null) {
return this.getTabCompleter().tabComplete(sender, Arrays.asList(args)); return this.getTabCompleter().tabComplete(sender, Arrays.asList(args));
} else { } else {
return this.tabComplete(sender, Arrays.asList(args)); List<String> completions = this.tabComplete(sender, Arrays.asList(args));
if (sender instanceof Player player) {
completions.addAll(this.tabComplete(player, Arrays.asList(args)));
}
return completions;
} }
} }

View File

@@ -1,14 +1,18 @@
package com.willfp.eco.core.command.impl; package com.willfp.eco.core.command.impl;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandMap;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter; import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
@@ -38,14 +42,63 @@ public abstract class PluginCommand extends HandledCommand implements CommandExe
/** /**
* Registers the command with the server, * Registers the command with the server,
* <p>
* Requires the command name to exist, defined in plugin.yml.
*/ */
public final void register() { public final void register() {
org.bukkit.command.PluginCommand command = Bukkit.getPluginCommand(this.getName()); org.bukkit.command.PluginCommand command = Bukkit.getPluginCommand(this.getName());
assert command != null; if (command != null) {
command.setExecutor(this); command.setExecutor(this);
command.setTabCompleter(this); command.setTabCompleter(this);
if (this.getDescription() != null) {
command.setDescription(this.getDescription());
}
List<String> aliases = new ArrayList<>(command.getAliases());
aliases.addAll(this.getAliases());
command.setAliases(aliases);
} else {
this.unregister();
CommandMap commandMap = getCommandMap();
commandMap.register(this.getPlugin().getName().toLowerCase(), new DelegatedBukkitCommand(this));
}
Eco.get().syncCommands();
}
/**
* Unregisters the command from the server.
*/
public final void unregister() {
CommandMap commandMap = getCommandMap();
Command found = commandMap.getCommand(this.getName());
if (found != null) {
found.unregister(commandMap);
}
Eco.get().syncCommands();
}
/**
* Get aliases. Leave null if this command is from plugin.yml.
*
* @return The aliases.
*/
@NotNull
public List<String> getAliases() {
return new ArrayList<>();
}
/**
* Get description.
*
* @return The description.
*/
@Nullable
public String getDescription() {
return null;
} }
/** /**
@@ -93,4 +146,19 @@ public abstract class PluginCommand extends HandledCommand implements CommandExe
return this.handleTabCompletion(sender, args); return this.handleTabCompletion(sender, args);
} }
/**
* Get the internal server CommandMap.
*
* @return The CommandMap.
*/
public static CommandMap getCommandMap() {
try {
Field field = Bukkit.getServer().getClass().getDeclaredField("commandMap");
field.setAccessible(true);
return (CommandMap) field.get(Bukkit.getServer());
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new NullPointerException("Command map wasn't found!");
}
}
} }

View File

@@ -31,7 +31,7 @@ public abstract class CustomSlot implements Slot {
} }
@Override @Override
public ItemStack getItemStack(@NotNull final Player player) { public @NotNull ItemStack getItemStack(@NotNull final Player player) {
if (delegate == null) { if (delegate == null) {
throw new IllegalStateException("Custom Slot was not initialized!"); throw new IllegalStateException("Custom Slot was not initialized!");
} }

View File

@@ -29,7 +29,7 @@ public abstract class ReactiveSlot implements Slot {
@NotNull final Menu menu); @NotNull final Menu menu);
@Override @Override
public ItemStack getItemStack(@NotNull final Player player) { public @NotNull ItemStack getItemStack(@NotNull final Player player) {
return new ItemStack(Material.STONE); return new ItemStack(Material.STONE);
} }

View File

@@ -30,6 +30,7 @@ public interface Slot extends GUIComponent {
* @param player The player. * @param player The player.
* @return The ItemStack. * @return The ItemStack.
*/ */
@NotNull
ItemStack getItemStack(@NotNull Player player); ItemStack getItemStack(@NotNull Player player);
/** /**
@@ -60,6 +61,7 @@ public interface Slot extends GUIComponent {
* @param menu The menu. * @param menu The menu.
* @return The slot. * @return The slot.
*/ */
@NotNull
default Slot getActionableSlot(@NotNull final Player player, default Slot getActionableSlot(@NotNull final Player player,
@NotNull final Menu menu) { @NotNull final Menu menu) {
return this; return this;
@@ -125,7 +127,9 @@ public interface Slot extends GUIComponent {
* *
* @param provider The provider. * @param provider The provider.
* @return The builder. * @return The builder.
* @deprecated This method was written incorrectly, should have been a Player + Menu function.
*/ */
@Deprecated(since = "6.45.0", forRemoval = true)
static SlotBuilder builder(@NotNull final Function<Player, ItemStack> provider) { static SlotBuilder builder(@NotNull final Function<Player, ItemStack> provider) {
return Eco.get().createSlotBuilder((player, menu) -> provider.apply(player)); return Eco.get().createSlotBuilder((player, menu) -> provider.apply(player));
} }

View File

@@ -44,4 +44,20 @@ public record MathContext(
Collections.emptyList() Collections.emptyList()
); );
} }
/**
* Copy a MathContext with a player.
*
* @param context The context.
* @param player The player.
* @return The new MathContext.
*/
public static MathContext copyWithPlayer(@NotNull final MathContext context,
@Nullable final Player player) {
return new MathContext(
context.injectableContext(),
player,
context.additionalPlayers()
);
}
} }

View File

@@ -0,0 +1,156 @@
package com.willfp.eco.core.price;
import com.willfp.eco.core.config.interfaces.Config;
import com.willfp.eco.core.math.MathContext;
import com.willfp.eco.core.price.impl.PriceFree;
import com.willfp.eco.core.serialization.ConfigDeserializer;
import com.willfp.eco.util.NumberUtils;
import com.willfp.eco.util.StringUtils;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
/**
* A price that can be shown to a player.
*/
public final class ConfiguredPrice implements Price {
/**
* The deserializer.
*/
private static final ConfigDeserializer<ConfiguredPrice> DESERIALIZER = new Deserializer();
/**
* Free.
*/
private static final ConfiguredPrice FREE = new ConfiguredPrice(
new PriceFree(),
"Free"
);
/**
* The price.
*/
private final Price price;
/**
* The format string.
*/
private final String formatString;
/**
* Create a new Configured Price.
*
* @param price The price.
* @param formatString The format string.
*/
public ConfiguredPrice(@NotNull final Price price,
@NotNull final String formatString) {
this.price = price;
this.formatString = formatString;
}
@Override
public boolean canAfford(@NotNull final Player player) {
return this.price.canAfford(player);
}
@Override
public void pay(@NotNull final Player player) {
this.price.pay(player);
}
@Override
public void giveTo(@NotNull final Player player) {
this.price.giveTo(player);
}
@Override
public double getValue(@NotNull final Player player) {
return this.price.getValue(player);
}
@Override
public double getMultiplier(@NotNull final Player player) {
return this.price.getMultiplier(player);
}
@Override
public void setMultiplier(@NotNull final Player player,
final double multiplier) {
this.price.setMultiplier(player, multiplier);
}
/**
* Get the price that this delegates to.
*
* @return The price.
*/
public Price getPrice() {
return price;
}
/**
* Get the display string for a player.
*
* @param player The player.
* @return The display string.
*/
public String getDisplay(@NotNull final Player player) {
return StringUtils.format(
formatString.replace("%value%", NumberUtils.format(this.getPrice().getValue(player))),
player,
StringUtils.FormatOption.WITH_PLACEHOLDERS
);
}
/**
* Parse a configured price from config.
*
* @param config The config.
* @return The price, or null if it's invalid.
*/
@Nullable
public static ConfiguredPrice create(@NotNull final Config config) {
return DESERIALIZER.deserialize(config);
}
/**
* Parse a configured price from config.
*
* @param config The config.
* @return The price, or free if invalid.
*/
@NotNull
public static ConfiguredPrice createOrFree(@NotNull final Config config) {
return Objects.requireNonNullElse(create(config), FREE);
}
/**
* The deserializer for {@link ConfiguredPrice}.
*/
private static final class Deserializer implements ConfigDeserializer<ConfiguredPrice> {
@Override
@Nullable
public ConfiguredPrice deserialize(@NotNull final Config config) {
if (!(
config.has("value")
&& config.has("type")
&& config.has("display")
)) {
return null;
}
String formatString = config.getString("display");
Price price = Prices.create(
config.getString("value"),
config.getString("type"),
MathContext.of(config)
);
return new ConfiguredPrice(price, formatString);
}
}
}

View File

@@ -24,11 +24,35 @@ public interface Price {
*/ */
void pay(@NotNull Player player); void pay(@NotNull Player player);
/**
* Give the value of the price to the player.
* <p>
* You should override this method, it's only marked as default for
* backwards compatibility purposes.
*
* @param player The player.
*/
default void giveTo(@NotNull Player player) {
// Override when needed.
}
/**
* If the price is backed by a value, get it here.
*
* @param player The player.
* @return The value.
*/
default double getValue(@NotNull final Player player) {
return 0;
}
/** /**
* If the price is backed by a value, get it here. * If the price is backed by a value, get it here.
* *
* @return The value. * @return The value.
* @deprecated Use getValue(Player) instead.
*/ */
@Deprecated(since = "6.45.0", forRemoval = true)
default double getValue() { default double getValue() {
return 0; return 0;
} }
@@ -37,8 +61,31 @@ public interface Price {
* If the price is backed by a value, set it here. * If the price is backed by a value, set it here.
* *
* @param value The value. * @param value The value.
* @deprecated Values shouldn't be fixed.
*/ */
@Deprecated(since = "6.45.0", forRemoval = true)
default void setValue(final double value) { default void setValue(final double value) {
// Override when needed. // Override when needed.
} }
/**
* Get the price multiplier for a player.
*
* @param player The player.
* @return The value.
*/
default double getMultiplier(@NotNull final Player player) {
return 1;
}
/**
* Set the price multiplier for a player.
*
* @param player The player.
* @param multiplier The multiplier.
*/
default void setMultiplier(@NotNull final Player player,
final double multiplier) {
// Override when needed.
}
} }

View File

@@ -1,11 +1,16 @@
package com.willfp.eco.core.price; package com.willfp.eco.core.price;
import com.willfp.eco.core.math.MathContext;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
import java.util.function.Function;
/** /**
* Create prices. * Create prices.
* <p>
* You must override one of the create methods.
*/ */
public interface PriceFactory { public interface PriceFactory {
/** /**
@@ -23,5 +28,19 @@ public interface PriceFactory {
* @param value The value. * @param value The value.
* @return The price. * @return The price.
*/ */
@NotNull Price create(double value); default @NotNull Price create(final double value) {
return create(MathContext.EMPTY, (ctx) -> value);
}
/**
* Create the price.
*
* @param baseContext The base MathContext.
* @param function The function to use. Should use {@link MathContext#copyWithPlayer(MathContext, Player)} on calls.
* @return The price.
*/
default @NotNull Price create(@NotNull final MathContext baseContext,
@NotNull final Function<MathContext, Double> function) {
return create(function.apply(baseContext));
}
} }

View File

@@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
/** /**
* Class to manage prices. * Class to manage prices.
@@ -65,18 +66,18 @@ public final class Prices {
public static Price create(@NotNull final String expression, public static Price create(@NotNull final String expression,
@Nullable final String priceName, @Nullable final String priceName,
@NotNull final MathContext context) { @NotNull final MathContext context) {
double value = NumberUtils.evaluateExpression( Function<MathContext, Double> function = (ctx) -> NumberUtils.evaluateExpression(
expression, expression,
context ctx
); );
if (value <= 0) { if (function.apply(context) <= 0) {
return new PriceFree(); return new PriceFree();
} }
// Default to economy // Default to economy
if (priceName == null) { if (priceName == null) {
return new PriceEconomy(value); return new PriceEconomy(context, function);
} }
// Find price factory // Find price factory
@@ -90,9 +91,9 @@ public final class Prices {
return new PriceFree(); return new PriceFree();
} }
return new PriceItem((int) Math.round(value), item); return new PriceItem(context, function, item);
} else { } else {
return factory.create(value); return factory.create(context, function);
} }
} }

View File

@@ -1,10 +1,16 @@
package com.willfp.eco.core.price.impl; package com.willfp.eco.core.price.impl;
import com.willfp.eco.core.integrations.economy.EconomyManager; import com.willfp.eco.core.integrations.economy.EconomyManager;
import com.willfp.eco.core.math.MathContext;
import com.willfp.eco.core.price.Price; import com.willfp.eco.core.price.Price;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
/** /**
* Economy-based price (for Vault, Treasury, etc.) * Economy-based price (for Vault, Treasury, etc.)
*/ */
@@ -12,7 +18,17 @@ public final class PriceEconomy implements Price {
/** /**
* The value of the price. * The value of the price.
*/ */
private double value; private final Function<MathContext, Double> function;
/**
* The base math context.
*/
private final MathContext baseContext;
/**
* The multipliers.
*/
private final Map<UUID, Double> multipliers = new HashMap<>();
/** /**
* Create a new economy-based price. * Create a new economy-based price.
@@ -20,26 +36,49 @@ public final class PriceEconomy implements Price {
* @param value The value. * @param value The value.
*/ */
public PriceEconomy(final double value) { public PriceEconomy(final double value) {
this.value = value; this(MathContext.EMPTY, ctx -> value);
}
/**
* Create a new economy-based price.
*
* @param baseContext The base context.
* @param function The function.
*/
public PriceEconomy(@NotNull final MathContext baseContext,
@NotNull final Function<MathContext, Double> function) {
this.baseContext = baseContext;
this.function = function;
} }
@Override @Override
public boolean canAfford(@NotNull Player player) { public boolean canAfford(@NotNull final Player player) {
return EconomyManager.getBalance(player) >= value; return EconomyManager.getBalance(player) >= getValue(player);
} }
@Override @Override
public void pay(@NotNull Player player) { public void pay(@NotNull final Player player) {
EconomyManager.removeMoney(player, value); EconomyManager.removeMoney(player, getValue(player));
} }
@Override @Override
public double getValue() { public void giveTo(@NotNull final Player player) {
return value; EconomyManager.giveMoney(player, getValue(player));
} }
@Override @Override
public void setValue(final double value) { public double getValue(@NotNull final Player player) {
this.value = value; return this.function.apply(MathContext.copyWithPlayer(baseContext, player)) * getMultiplier(player);
}
@Override
public double getMultiplier(@NotNull final Player player) {
return this.multipliers.getOrDefault(player.getUniqueId(), 1.0);
}
@Override
public void setMultiplier(@NotNull final Player player,
final double multiplier) {
this.multipliers.put(player.getUniqueId(), multiplier);
} }
} }

View File

@@ -16,12 +16,12 @@ public final class PriceFree implements Price {
} }
@Override @Override
public boolean canAfford(@NotNull Player player) { public boolean canAfford(@NotNull final Player player) {
return true; return true;
} }
@Override @Override
public void pay(@NotNull Player player) { public void pay(@NotNull final Player player) {
// Do nothing. // Do nothing.
} }
} }

View File

@@ -1,20 +1,32 @@
package com.willfp.eco.core.price.impl; package com.willfp.eco.core.price.impl;
import com.willfp.eco.core.drops.DropQueue;
import com.willfp.eco.core.items.TestableItem; import com.willfp.eco.core.items.TestableItem;
import com.willfp.eco.core.math.MathContext;
import com.willfp.eco.core.price.Price; import com.willfp.eco.core.price.Price;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
/** /**
* Item-based price. * Item-based price.
*/ */
public final class PriceItem implements Price { public final class PriceItem implements Price {
/**
* The base MathContext.
*/
private final MathContext baseContext;
/** /**
* The amount of items. * The amount of items.
*/ */
private final int amountToRemove; private final Function<MathContext, Double> function;
/** /**
* The item. * The item.
@@ -22,14 +34,33 @@ public final class PriceItem implements Price {
private final TestableItem item; private final TestableItem item;
/** /**
* Create a new economy-based price. * The multipliers.
*/
private final Map<UUID, Double> multipliers = new HashMap<>();
/**
* Create a new item-based price.
* *
* @param amount The amount. * @param amount The amount.
* @param item The item. * @param item The item.
*/ */
public PriceItem(final int amount, public PriceItem(final int amount,
@NotNull final TestableItem item) { @NotNull final TestableItem item) {
this.amountToRemove = Math.max(0, amount); this(MathContext.EMPTY, ctx -> (double) amount, item);
}
/**
* Create a new item-based price.
*
* @param baseContext The base MathContext.
* @param function The function to get the amount of items to remove.
* @param item The item.
*/
public PriceItem(@NotNull final MathContext baseContext,
@NotNull final Function<MathContext, Double> function,
@NotNull final TestableItem item) {
this.baseContext = baseContext;
this.function = function;
this.item = item; this.item = item;
} }
@@ -43,8 +74,9 @@ public final class PriceItem implements Price {
} }
@Override @Override
public boolean canAfford(@NotNull Player player) { public boolean canAfford(@NotNull final Player player) {
if (amountToRemove == 0) { int toRemove = (int) getValue(player);
if (toRemove <= 0) {
return true; return true;
} }
@@ -56,26 +88,27 @@ public final class PriceItem implements Price {
} }
} }
return count >= amountToRemove; return count >= toRemove;
} }
@Override @Override
public void pay(@NotNull Player player) { public void pay(@NotNull final Player player) {
int toRemove = (int) getValue(player);
int count = 0; int count = 0;
for (ItemStack itemStack : player.getInventory().getContents()) { for (ItemStack itemStack : player.getInventory().getContents()) {
if (count >= amountToRemove) { if (count >= toRemove) {
break; break;
} }
if (item.matches(itemStack)) { if (item.matches(itemStack)) {
int itemAmount = itemStack.getAmount(); int itemAmount = itemStack.getAmount();
if (itemAmount > amountToRemove) { if (itemAmount > toRemove) {
itemStack.setAmount(itemAmount - amountToRemove); itemStack.setAmount(itemAmount - toRemove);
} }
if (itemAmount <= amountToRemove) { if (itemAmount <= toRemove) {
itemStack.setAmount(0); itemStack.setAmount(0);
itemStack.setType(Material.AIR); itemStack.setType(Material.AIR);
} }
@@ -84,4 +117,33 @@ public final class PriceItem implements Price {
} }
} }
} }
@Override
public void giveTo(@NotNull final Player player) {
ItemStack itemStack = item.getItem().clone();
itemStack.setAmount((int) getValue(player));
new DropQueue(player)
.addItem(itemStack)
.forceTelekinesis()
.push();
}
@Override
public double getValue(@NotNull final Player player) {
return Math.toIntExact(Math.round(
this.function.apply(MathContext.copyWithPlayer(baseContext, player)) * getMultiplier(player)
));
}
@Override
public double getMultiplier(@NotNull final Player player) {
return this.multipliers.getOrDefault(player.getUniqueId(), 1.0);
}
@Override
public void setMultiplier(@NotNull final Player player,
final double multiplier) {
this.multipliers.put(player.getUniqueId(), multiplier);
}
} }

View File

@@ -0,0 +1,7 @@
@file:JvmName("TestableExtensions")
package com.willfp.eco.core.lookup
/** @see Testable.matches */
fun <T> T?.matches(test: Testable<T>) =
test.matches(this)

View File

@@ -31,9 +31,7 @@ class RenderedInventory(
val state = mutableMapOf<String, Any?>() val state = mutableMapOf<String, Any?>()
fun render() { fun render() {
val previousCaptive = captiveItems.toMap() val newCaptive = mutableMapOf<GUIPosition, ItemStack>()
captiveItems.clear()
for (row in (1..menu.rows)) { for (row in (1..menu.rows)) {
for (column in (1..menu.columns)) { for (column in (1..menu.columns)) {
@@ -48,11 +46,11 @@ class RenderedInventory(
if (slot.isCaptiveFromEmpty) { if (slot.isCaptiveFromEmpty) {
if (!actualItem.isEmpty) { if (!actualItem.isEmpty) {
captiveItems[position] = actualItem newCaptive[position] = actualItem
} }
} else { } else {
if (actualItem != renderedItem && !EmptyTestableItem().matches(actualItem)) { if (actualItem != renderedItem && !EmptyTestableItem().matches(actualItem)) {
captiveItems[position] = actualItem newCaptive[position] = actualItem
} }
} }
} else { } else {
@@ -61,6 +59,10 @@ class RenderedInventory(
} }
} }
val previousCaptive = captiveItems.toMap()
captiveItems.clear()
captiveItems.putAll(newCaptive)
menu.runOnRender(player) menu.runOnRender(player)
// Run second render if captive items changed // Run second render if captive items changed

View File

@@ -1,8 +1,10 @@
package com.willfp.eco.internal.price package com.willfp.eco.internal.price
import com.willfp.eco.core.math.MathContext
import com.willfp.eco.core.price.Price import com.willfp.eco.core.price.Price
import com.willfp.eco.core.price.PriceFactory import com.willfp.eco.core.price.PriceFactory
import com.willfp.eco.core.price.impl.PriceEconomy import com.willfp.eco.core.price.impl.PriceEconomy
import java.util.function.Function
object PriceFactoryEconomy : PriceFactory { object PriceFactoryEconomy : PriceFactory {
override fun getNames() = listOf( override fun getNames() = listOf(
@@ -10,5 +12,7 @@ object PriceFactoryEconomy : PriceFactory {
"$" "$"
) )
override fun create(value: Double): Price = PriceEconomy(value) override fun create(baseContext: MathContext, function: Function<MathContext, Double>): Price {
return PriceEconomy(baseContext, function)
}
} }

View File

@@ -1,8 +1,11 @@
package com.willfp.eco.internal.price package com.willfp.eco.internal.price
import com.willfp.eco.core.math.MathContext
import com.willfp.eco.core.price.Price import com.willfp.eco.core.price.Price
import com.willfp.eco.core.price.PriceFactory import com.willfp.eco.core.price.PriceFactory
import org.bukkit.entity.Player import org.bukkit.entity.Player
import java.util.UUID
import java.util.function.Function
import kotlin.math.roundToInt import kotlin.math.roundToInt
object PriceFactoryXP : PriceFactory { object PriceFactoryXP : PriceFactory {
@@ -12,15 +15,36 @@ object PriceFactoryXP : PriceFactory {
"experience" "experience"
) )
override fun create(value: Double): Price = PriceXP(value.roundToInt()) override fun create(baseContext: MathContext, function: Function<MathContext, Double>): Price {
return PriceXP(baseContext) { function.apply(it).roundToInt() }
}
private class PriceXP( private class PriceXP(
private val xp: Int private val baseContext: MathContext,
private val xp: (MathContext) -> Int
) : Price { ) : Price {
override fun canAfford(player: Player) = player.totalExperience >= xp private val multipliers = mutableMapOf<UUID, Double>()
override fun canAfford(player: Player) = player.totalExperience >= getValue(player)
override fun pay(player: Player) { override fun pay(player: Player) {
player.totalExperience -= xp player.totalExperience -= getValue(player).roundToInt()
}
override fun giveTo(player: Player) {
player.totalExperience += getValue(player).roundToInt()
}
override fun getValue(player: Player): Double {
return xp(MathContext.copyWithPlayer(baseContext, player)) * getMultiplier(player)
}
override fun getMultiplier(player: Player): Double {
return multipliers[player.uniqueId] ?: 1.0
}
override fun setMultiplier(player: Player, multiplier: Double) {
multipliers[player.uniqueId] = multiplier.roundToInt().toDouble()
} }
} }
} }

View File

@@ -1,8 +1,11 @@
package com.willfp.eco.internal.price package com.willfp.eco.internal.price
import com.willfp.eco.core.math.MathContext
import com.willfp.eco.core.price.Price import com.willfp.eco.core.price.Price
import com.willfp.eco.core.price.PriceFactory import com.willfp.eco.core.price.PriceFactory
import org.bukkit.entity.Player import org.bukkit.entity.Player
import java.util.UUID
import java.util.function.Function
import kotlin.math.roundToInt import kotlin.math.roundToInt
object PriceFactoryXPLevels : PriceFactory { object PriceFactoryXPLevels : PriceFactory {
@@ -13,15 +16,36 @@ object PriceFactoryXPLevels : PriceFactory {
"explevels", "explevels",
) )
override fun create(value: Double): Price = PriceXPLevel(value.roundToInt()) override fun create(baseContext: MathContext, function: Function<MathContext, Double>): Price {
return PriceXPLevel(baseContext) { function.apply(it).roundToInt() }
}
private class PriceXPLevel( private class PriceXPLevel(
private val levels: Int private val baseContext: MathContext,
private val level: (MathContext) -> Int
) : Price { ) : Price {
override fun canAfford(player: Player) = player.level >= levels private val multipliers = mutableMapOf<UUID, Double>()
override fun canAfford(player: Player) = player.level >= getValue(player)
override fun pay(player: Player) { override fun pay(player: Player) {
player.level -= levels player.level -= getValue(player).roundToInt()
}
override fun giveTo(player: Player) {
player.level += getValue(player).roundToInt()
}
override fun getValue(player: Player): Double {
return level(MathContext.copyWithPlayer(baseContext, player)) * getMultiplier(player)
}
override fun getMultiplier(player: Player): Double {
return multipliers[player.uniqueId] ?: 1.0
}
override fun setMultiplier(player: Player, multiplier: Double) {
multipliers[player.uniqueId] = multiplier.roundToInt().toDouble()
} }
} }
} }

View File

@@ -1,21 +1,23 @@
package com.willfp.eco.internal.spigot.proxy.common.ai.entity package com.willfp.eco.internal.spigot.proxy.common.ai.entity
import com.willfp.eco.core.entities.ai.entity.EntityGoalLeapAtTarget import com.willfp.eco.core.entities.ai.entity.EntityGoalIllusionerBlindnessSpell
import com.willfp.eco.internal.spigot.proxy.common.ai.EntityGoalFactory import com.willfp.eco.internal.spigot.proxy.common.ai.EntityGoalFactory
import com.willfp.eco.internal.spigot.proxy.common.ai.opengoals.IllusionerBlindnessSpellGoal
import net.minecraft.world.entity.PathfinderMob import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.goal.Goal import net.minecraft.world.entity.ai.goal.Goal
import net.minecraft.world.entity.monster.Illusioner import net.minecraft.world.entity.monster.Illusioner
object IllusionerBlindnessSpellGoalFactory : EntityGoalFactory<EntityGoalLeapAtTarget> { object IllusionerBlindnessSpellGoalFactory : EntityGoalFactory<EntityGoalIllusionerBlindnessSpell> {
override fun create(apiGoal: EntityGoalLeapAtTarget, entity: PathfinderMob): Goal? { override fun create(apiGoal: EntityGoalIllusionerBlindnessSpell, entity: PathfinderMob): Goal? {
if (entity !is Illusioner) return null if (entity !is Illusioner) return null
return IllusionerBlindnessSpellGoal( // Have to use reflection for it to work
entity return Illusioner::class.java.declaredClasses[1]
) .getDeclaredConstructor(Illusioner::class.java)
.apply { isAccessible = true }
.newInstance(entity) as Goal
} }
override fun isGoalOfType(goal: Goal) = goal is IllusionerBlindnessSpellGoal override fun isGoalOfType(goal: Goal): Boolean {
|| goal::class.java.name.contains("IllusionerBlindnessSpellGoal") return Illusioner::class.java.declaredClasses[1].isInstance(goal)
}
} }

View File

@@ -1,21 +1,23 @@
package com.willfp.eco.internal.spigot.proxy.common.ai.entity package com.willfp.eco.internal.spigot.proxy.common.ai.entity
import com.willfp.eco.core.entities.ai.entity.EntityGoalLeapAtTarget import com.willfp.eco.core.entities.ai.entity.EntityGoalIllusionerMirrorSpell
import com.willfp.eco.internal.spigot.proxy.common.ai.EntityGoalFactory import com.willfp.eco.internal.spigot.proxy.common.ai.EntityGoalFactory
import com.willfp.eco.internal.spigot.proxy.common.ai.opengoals.IllusionerMirrorSpellGoal
import net.minecraft.world.entity.PathfinderMob import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.goal.Goal import net.minecraft.world.entity.ai.goal.Goal
import net.minecraft.world.entity.monster.Illusioner import net.minecraft.world.entity.monster.Illusioner
object IllusionerMirrorSpellGoalFactory : EntityGoalFactory<EntityGoalLeapAtTarget> { object IllusionerMirrorSpellGoalFactory : EntityGoalFactory<EntityGoalIllusionerMirrorSpell> {
override fun create(apiGoal: EntityGoalLeapAtTarget, entity: PathfinderMob): Goal? { override fun create(apiGoal: EntityGoalIllusionerMirrorSpell, entity: PathfinderMob): Goal? {
if (entity !is Illusioner) return null if (entity !is Illusioner) return null
return IllusionerMirrorSpellGoal( // Have to use reflection for it to work
entity return Illusioner::class.java.declaredClasses[0]
) .getDeclaredConstructor(Illusioner::class.java)
.apply { isAccessible = true }
.newInstance(entity) as Goal
} }
override fun isGoalOfType(goal: Goal) = goal is IllusionerMirrorSpellGoal override fun isGoalOfType(goal: Goal): Boolean {
|| goal::class.java.name.contains("IllusionerMirrorSpellGoal") return Illusioner::class.java.declaredClasses[0].isInstance(goal)
}
} }

View File

@@ -1,50 +0,0 @@
package com.willfp.eco.internal.spigot.proxy.common.ai.opengoals
import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundEvents
import net.minecraft.world.Difficulty
import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.monster.Illusioner
import net.minecraft.world.entity.monster.SpellcasterIllager
import org.bukkit.event.entity.EntityPotionEffectEvent
class IllusionerBlindnessSpellGoal(
private val illusioner: Illusioner
) : OpenUseSpellGoal(illusioner) {
override val castingInterval = 180
override val castingTime = 20
override val spellPrepareSound: SoundEvent = SoundEvents.ILLUSIONER_PREPARE_BLINDNESS
override val spell: SpellcasterIllager.IllagerSpell = SpellcasterIllager.IllagerSpell.BLINDNESS
private var lastTargetId = 0
override fun canUse(): Boolean {
return if (super.canUse()) {
false
} else if (illusioner.target == null) {
false
} else if (illusioner.target!!.id == lastTargetId) {
false
} else {
illusioner.level.getCurrentDifficultyAt(illusioner.blockPosition()).isHarderThan(
Difficulty.NORMAL.ordinal.toFloat()
)
}
}
override fun start() {
super.start()
if (illusioner.target != null) {
lastTargetId = illusioner.target!!.id
}
}
override fun performSpellCasting() {
illusioner.target?.addEffect(
MobEffectInstance(MobEffects.BLINDNESS, 400),
illusioner,
EntityPotionEffectEvent.Cause.ATTACK
) // CraftBukkit
}
}

View File

@@ -1,29 +0,0 @@
package com.willfp.eco.internal.spigot.proxy.common.ai.opengoals
import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundEvents
import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.monster.Illusioner
import net.minecraft.world.entity.monster.SpellcasterIllager
import org.bukkit.event.entity.EntityPotionEffectEvent
class IllusionerMirrorSpellGoal(
private val illusioner: Illusioner
) : OpenUseSpellGoal(illusioner) {
override val castingInterval = 340
override val castingTime = 20
override val spellPrepareSound: SoundEvent = SoundEvents.ILLUSIONER_PREPARE_MIRROR
override val spell: SpellcasterIllager.IllagerSpell = SpellcasterIllager.IllagerSpell.DISAPPEAR
override fun canUse(): Boolean {
return if (!super.canUse()) false else !illusioner.hasEffect(MobEffects.INVISIBILITY)
}
override fun performSpellCasting() {
illusioner.addEffect(
MobEffectInstance(MobEffects.INVISIBILITY, 1200),
EntityPotionEffectEvent.Cause.ILLUSION
)
}
}

View File

@@ -1,79 +0,0 @@
package com.willfp.eco.internal.spigot.proxy.common.ai.opengoals
import net.minecraft.sounds.SoundEvent
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.goal.Goal
import net.minecraft.world.entity.monster.SpellcasterIllager
@Suppress("UNCHECKED_CAST")
class DelegatedSpellcaster(private val handle: SpellcasterIllager) : SpellcasterIllager(
handle.type as EntityType<out SpellcasterIllager>,
handle.level
) {
var openSpellCastingTickCount
get() = this.spellCastingTickCount
set(value) {
this.spellCastingTickCount = value
}
val openCastingSoundEvent = this.castingSoundEvent
override fun applyRaidBuffs(wave: Int, unused: Boolean) {
handle.applyRaidBuffs(wave, unused)
}
override fun getCelebrateSound(): SoundEvent {
return handle.celebrateSound
}
override fun getCastingSoundEvent(): SoundEvent {
return this.openCastingSoundEvent
}
}
@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
abstract class OpenUseSpellGoal(
private val handle: SpellcasterIllager
) : Goal() {
private var attackWarmupDelay = 0
private var nextAttackTickCount = 0
private val openHandle = DelegatedSpellcaster(handle)
override fun canUse(): Boolean {
val entityliving: LivingEntity = handle.target ?: return false
return if (entityliving.isAlive) if (handle.isCastingSpell) false else handle.tickCount >= nextAttackTickCount else false
}
override fun canContinueToUse(): Boolean {
val entityliving: LivingEntity = handle.target ?: return false
return entityliving.isAlive && attackWarmupDelay > 0
}
override fun start() {
attackWarmupDelay = castWarmupTime
openHandle.openSpellCastingTickCount = castingTime
nextAttackTickCount = handle.tickCount + castingInterval
val soundeffect = spellPrepareSound
if (soundeffect != null) {
handle.playSound(soundeffect, 1.0f, 1.0f)
}
handle.setIsCastingSpell(spell)
}
override fun tick() {
--attackWarmupDelay
if (attackWarmupDelay == 0) {
performSpellCasting()
handle.playSound(openHandle.openCastingSoundEvent, 1.0f, 1.0f)
}
}
protected abstract fun performSpellCasting()
protected abstract val castingTime: Int
protected abstract val castingInterval: Int
protected abstract val spellPrepareSound: SoundEvent?
protected abstract val spell: SpellcasterIllager.IllagerSpell?
protected open val castWarmupTime: Int = 60
}

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_17_R1
import com.willfp.eco.internal.spigot.proxy.SyncCommandsProxy
import org.bukkit.Bukkit
import org.bukkit.craftbukkit.v1_17_R1.CraftServer
class SyncCommands : SyncCommandsProxy {
override fun syncCommands() {
(Bukkit.getServer() as CraftServer).syncCommands()
}
}

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R1
import com.willfp.eco.internal.spigot.proxy.SyncCommandsProxy
import org.bukkit.Bukkit
import org.bukkit.craftbukkit.v1_18_R1.CraftServer
class SyncCommands : SyncCommandsProxy {
override fun syncCommands() {
(Bukkit.getServer() as CraftServer).syncCommands()
}
}

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_18_R2
import com.willfp.eco.internal.spigot.proxy.SyncCommandsProxy
import org.bukkit.Bukkit
import org.bukkit.craftbukkit.v1_18_R2.CraftServer
class SyncCommands : SyncCommandsProxy {
override fun syncCommands() {
(Bukkit.getServer() as CraftServer).syncCommands()
}
}

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.internal.spigot.proxy.v1_19_R1
import com.willfp.eco.internal.spigot.proxy.SyncCommandsProxy
import org.bukkit.Bukkit
import org.bukkit.craftbukkit.v1_19_R1.CraftServer
class SyncCommands : SyncCommandsProxy {
override fun syncCommands() {
(Bukkit.getServer() as CraftServer).syncCommands()
}
}

View File

@@ -50,6 +50,7 @@ import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
import com.willfp.eco.internal.spigot.proxy.MiniMessageTranslatorProxy import com.willfp.eco.internal.spigot.proxy.MiniMessageTranslatorProxy
import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy import com.willfp.eco.internal.spigot.proxy.SNBTConverterProxy
import com.willfp.eco.internal.spigot.proxy.SkullProxy import com.willfp.eco.internal.spigot.proxy.SkullProxy
import com.willfp.eco.internal.spigot.proxy.SyncCommandsProxy
import com.willfp.eco.internal.spigot.proxy.TPSProxy import com.willfp.eco.internal.spigot.proxy.TPSProxy
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.NamespacedKey import org.bukkit.NamespacedKey
@@ -282,4 +283,7 @@ class EcoImpl : EcoSpigotPlugin(), Eco {
override fun getOpenMenu(player: Player) = override fun getOpenMenu(player: Player) =
player.renderedInventory?.menu player.renderedInventory?.menu
override fun syncCommands() =
this.getProxy(SyncCommandsProxy::class.java).syncCommands()
} }

View File

@@ -118,7 +118,6 @@ import com.willfp.eco.internal.spigot.integrations.shop.ShopDeluxeSellwands
import com.willfp.eco.internal.spigot.integrations.shop.ShopEconomyShopGUI import com.willfp.eco.internal.spigot.integrations.shop.ShopEconomyShopGUI
import com.willfp.eco.internal.spigot.integrations.shop.ShopShopGuiPlus import com.willfp.eco.internal.spigot.integrations.shop.ShopShopGuiPlus
import com.willfp.eco.internal.spigot.integrations.shop.ShopZShop import com.willfp.eco.internal.spigot.integrations.shop.ShopZShop
import com.willfp.eco.internal.spigot.player.PlayerHealthFixer
import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
import com.willfp.eco.internal.spigot.recipes.CraftingRecipeListener import com.willfp.eco.internal.spigot.recipes.CraftingRecipeListener
import com.willfp.eco.internal.spigot.recipes.StackedRecipeListener import com.willfp.eco.internal.spigot.recipes.StackedRecipeListener
@@ -369,7 +368,6 @@ abstract class EcoSpigotPlugin : EcoPlugin() {
ArmorChangeEventListeners(this), ArmorChangeEventListeners(this),
DataListener(this), DataListener(this),
PlayerBlockListener(this), PlayerBlockListener(this),
PlayerHealthFixer(this),
ServerLocking ServerLocking
) )

View File

@@ -1,42 +0,0 @@
package com.willfp.eco.internal.spigot.player
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.data.keys.PersistentDataKey
import com.willfp.eco.core.data.keys.PersistentDataKeyType
import com.willfp.eco.core.data.profile
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.player.PlayerQuitEvent
class PlayerHealthFixer(
private val plugin: EcoPlugin
): Listener {
private val lastHealthKey = PersistentDataKey(
plugin.createNamespacedKey("last_health"),
PersistentDataKeyType.DOUBLE,
0.0
)
@EventHandler
fun onLeave(event: PlayerQuitEvent) {
if (!plugin.configYml.getBool("health-fixer")) {
return
}
val player = event.player
player.profile.write(lastHealthKey, player.health)
}
@EventHandler
fun onJoin(event: PlayerJoinEvent) {
if (!plugin.configYml.getBool("health-fixer")) {
return
}
val player = event.player
plugin.scheduler.runLater(2) {
player.health = player.profile.read(lastHealthKey)
}
}
}

View File

@@ -73,9 +73,6 @@ log-full-extension-errors: false
# a custom crafting table, though, this won't affect anything, and you should disable the option. # a custom crafting table, though, this won't affect anything, and you should disable the option.
displayed-recipes: true displayed-recipes: true
# Save health on leave and set it back on join - works around attribute modifiers.
health-fixer: false
# If eco plugins should not check for updates; only enable this if you know what you're doing # If eco plugins should not check for updates; only enable this if you know what you're doing
# as there can be urgent hotfixes that you are then not notified about. If you're confident # as there can be urgent hotfixes that you are then not notified about. If you're confident
# that you can manage updates on your own, turn this on. # that you can manage updates on your own, turn this on.

View File

@@ -0,0 +1,5 @@
package com.willfp.eco.internal.spigot.proxy
interface SyncCommandsProxy {
fun syncCommands()
}

View File

@@ -1,3 +1,3 @@
version = 6.44.1 version = 6.45.0
plugin-name = eco plugin-name = eco
kotlin.code.style = official kotlin.code.style = official