Compare commits

..

28 Commits

Author SHA1 Message Date
Auxilor
7f42cbe32e Updated to 6.22.2 2022-02-01 18:55:18 +00:00
Auxilor
ae12ab17fe Fixed server profile 2022-02-01 18:55:07 +00:00
Auxilor
9949ed4f5f Updated to 6.22.1 2022-02-01 18:16:47 +00:00
Auxilor
e3f81a51e8 Revert "Fixed WorldGuard antigrief integration"
This reverts commit feebbd8ec7.
2022-02-01 18:16:27 +00:00
Auxilor
a06d782dea Cleaned up StringUtils 2022-02-01 14:12:03 +00:00
Auxilor
7e60ee63ea Merge branch '0ft3n_master' into develop 2022-02-01 14:04:50 +00:00
Auxilor
e349f47e66 Swapped out guava cache for caffeine 2022-02-01 14:04:00 +00:00
Auxilor
f710a69455 Changed cache expiry times 2022-02-01 13:49:35 +00:00
Auxilor
20b06be1f2 Changed item cache off to guava 2022-02-01 13:24:36 +00:00
Auxilor
9992820580 Items changes 2022-02-01 13:17:52 +00:00
0ft3n
feebbd8ec7 Fixed WorldGuard antigrief integration 2022-02-01 15:26:40 +03:00
Auxilor
5302aa07a5 Un-did thing? 2022-02-01 11:19:23 +00:00
Auxilor
d124c5b274 Fixed build issues 2022-02-01 11:08:08 +00:00
Auxilor
f188919197 Fixed wrong suppression 2022-02-01 11:04:24 +00:00
Auxilor
388268e906 Minor changes 2022-02-01 11:03:02 +00:00
Auxilor
6367867d2b Suppressed warnings 2022-02-01 11:01:36 +00:00
Auxilor
291357e235 Updated to 6.22.0 2022-02-01 10:55:13 +00:00
Auxilor
07178b0645 Added cache to string formats 2022-02-01 10:54:13 +00:00
Auxilor
70ef99e875 Added guava caches to performance-sensitive components 2022-02-01 10:44:19 +00:00
Auxilor
885a7835ea Fixed CrashClaim integration not being registered 2022-02-01 10:09:41 +00:00
Auxilor
94e9b47f02 Renaming 2022-02-01 10:08:21 +00:00
Auxilor
e8f4bdd4aa Added toString methods on profile impl 2022-02-01 10:07:25 +00:00
Auxilor
c01e409904 Added ServerProfile, internal annotations 2022-02-01 10:06:39 +00:00
Auxilor
f1cf82160e Rewrote custom recipe listener in kotlin 2022-02-01 09:46:59 +00:00
0ft3n
d1c15f8699 Merge branch 'Auxilor:master' into master 2022-01-29 20:41:22 +03:00
_OfTeN_
be6e7b1f46 Added RPGHorses Antigrief integration
Fixed CustoMCrafting compatibility

Updated CustomCrafting Items lookup integration

Added a warning for empty recipes
2022-01-29 00:25:13 +03:00
Auxilor
b78fc2fb66 Suppressed warning 2022-01-28 09:30:57 +00:00
_OfTeN_
144ea0dd10 Added silent arg parser for entities 2022-01-27 16:51:39 +03:00
47 changed files with 874 additions and 475 deletions

View File

@@ -67,6 +67,9 @@ allprojects {
// Crunch // Crunch
maven("https://redempt.dev") maven("https://redempt.dev")
// LibsDisguises
maven("https://repo.md-5.net/content/groups/public/")
} }
dependencies { dependencies {
@@ -80,6 +83,10 @@ allprojects {
compileOnly("net.kyori:adventure-api:4.9.3") compileOnly("net.kyori:adventure-api:4.9.3")
compileOnly("net.kyori:adventure-text-serializer-gson:4.9.3") compileOnly("net.kyori:adventure-text-serializer-gson:4.9.3")
compileOnly("net.kyori:adventure-text-serializer-legacy:4.9.3") compileOnly("net.kyori:adventure-text-serializer-legacy:4.9.3")
// Other
compileOnly("com.google.guava:guava:31.0.1-jre")
compileOnly("com.github.ben-manes.caffeine:caffeine:3.0.5")
} }
tasks.withType<JavaCompile> { tasks.withType<JavaCompile> {
@@ -94,14 +101,12 @@ allprojects {
exclude(group = "org.spongepowered", module = "configurate-hocon") exclude(group = "org.spongepowered", module = "configurate-hocon")
exclude(group = "com.darkblade12", module = "particleeffect") exclude(group = "com.darkblade12", module = "particleeffect")
exclude(group = "com.github.cryptomorin", module = "XSeries") exclude(group = "com.github.cryptomorin", module = "XSeries")
exclude(group = "org.apache.commons", module = "commons-lang3")
} }
tasks { tasks {
shadowJar { shadowJar {
relocate("org.bstats", "com.willfp.eco.shaded.bstats") relocate("org.bstats", "com.willfp.eco.shaded.bstats")
relocate("net.kyori.adventure.text.minimessage", "com.willfp.eco.shaded.minimessage") relocate("net.kyori.adventure.text.minimessage", "com.willfp.eco.shaded.minimessage")
relocate("redempt.crunch", "com.willfp.eco.shaded.crunch")
} }
compileJava { compileJava {

View File

@@ -15,7 +15,6 @@ dependencies {
compileOnly 'org.apache.maven:maven-artifact:3.8.1' compileOnly 'org.apache.maven:maven-artifact:3.8.1'
compileOnly 'com.comphenix.protocol:ProtocolLib:4.6.1-SNAPSHOT' compileOnly 'com.comphenix.protocol:ProtocolLib:4.6.1-SNAPSHOT'
compileOnly 'com.google.code.gson:gson:2.8.8' compileOnly 'com.google.code.gson:gson:2.8.8'
compileOnly 'org.apache.commons:commons-lang3:3.0'
} }
java { java {

View File

@@ -4,6 +4,12 @@ import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* Holds the instance of the eco handler for bridging between the frontend * Holds the instance of the eco handler for bridging between the frontend
* and backend. * and backend.
@@ -52,6 +58,24 @@ public final class Eco {
return handler; return handler;
} }
/**
* Eco Handler components are internals, so if a class is marked as a handler component,
* then it should be treated the same as if it was marked with {@link ApiStatus.Internal}.
* <p>
* If a class is marked with {@link HandlerComponent}, <strong>Do not reference it in
* your code!</strong> It can and will contain breaking changes between minor versions and
* even patches, and you will create compatibility issues by using them.
* <p>
* Handler components should also be marked with {@link ApiStatus.Internal} in order to
* cause compiler / IDE warnings.
*/
@Documented
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE})
public @interface HandlerComponent {
}
private Eco() { private Eco() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
} }

View File

@@ -2,7 +2,7 @@ package com.willfp.eco.core;
import com.willfp.eco.core.config.updating.ConfigHandler; import com.willfp.eco.core.config.updating.ConfigHandler;
import com.willfp.eco.core.config.wrapper.ConfigFactory; import com.willfp.eco.core.config.wrapper.ConfigFactory;
import com.willfp.eco.core.data.PlayerProfileHandler; import com.willfp.eco.core.data.ProfileHandler;
import com.willfp.eco.core.data.keys.KeyRegistry; import com.willfp.eco.core.data.keys.KeyRegistry;
import com.willfp.eco.core.drops.DropQueueFactory; import com.willfp.eco.core.drops.DropQueueFactory;
import com.willfp.eco.core.events.EventManager; import com.willfp.eco.core.events.EventManager;
@@ -234,7 +234,7 @@ public interface Handler {
* @return The handler. * @return The handler.
*/ */
@NotNull @NotNull
PlayerProfileHandler getPlayerProfileHandler(); ProfileHandler getProfileHandler();
/** /**
* Create dummy entity - never spawned, exists purely in code. * Create dummy entity - never spawned, exists purely in code.

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.config.wrapper; package com.willfp.eco.core.config.wrapper;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.PluginLike; import com.willfp.eco.core.PluginLike;
import com.willfp.eco.core.config.ConfigType; import com.willfp.eco.core.config.ConfigType;
import com.willfp.eco.core.config.interfaces.Config; import com.willfp.eco.core.config.interfaces.Config;
@@ -14,6 +15,7 @@ import java.util.Map;
* Internal component to create backend config implementations. * Internal component to create backend config implementations.
*/ */
@ApiStatus.Internal @ApiStatus.Internal
@Eco.HandlerComponent
public interface ConfigFactory { public interface ConfigFactory {
/** /**
* Updatable config. * Updatable config.

View File

@@ -1,7 +1,6 @@
package com.willfp.eco.core.data; package com.willfp.eco.core.data;
import com.willfp.eco.core.Eco; import com.willfp.eco.core.Eco;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -12,26 +11,7 @@ import java.util.UUID;
* <p> * <p>
* Profiles save automatically, so there is no need to save after changes. * Profiles save automatically, so there is no need to save after changes.
*/ */
public interface PlayerProfile { public interface PlayerProfile extends Profile {
/**
* Write a key to a player's persistent data.
*
* @param key The key.
* @param value The value.
* @param <T> The type of the key.
*/
<T> void write(@NotNull PersistentDataKey<T> key,
@NotNull T value);
/**
* Read a key from a player's persistent data.
*
* @param key The key.
* @param <T> The type of the key.
* @return The value, or the default value if not found.
*/
<T> @NotNull T read(@NotNull PersistentDataKey<T> key);
/** /**
* Load a player profile. * Load a player profile.
* *
@@ -51,6 +31,6 @@ public interface PlayerProfile {
*/ */
@NotNull @NotNull
static PlayerProfile load(@NotNull final UUID uuid) { static PlayerProfile load(@NotNull final UUID uuid) {
return Eco.getHandler().getPlayerProfileHandler().load(uuid); return Eco.getHandler().getProfileHandler().load(uuid);
} }
} }

View File

@@ -0,0 +1,30 @@
package com.willfp.eco.core.data;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.jetbrains.annotations.NotNull;
/**
* Persistent data storage interface.
* <p>
* Profiles save automatically, so there is no need to save after changes.
*/
public interface Profile {
/**
* Write a key to persistent data.
*
* @param key The key.
* @param value The value.
* @param <T> The type of the key.
*/
<T> void write(@NotNull PersistentDataKey<T> key,
@NotNull T value);
/**
* Read a key from persistent data.
*
* @param key The key.
* @param <T> The type of the key.
* @return The value, or the default value if not found.
*/
<T> @NotNull T read(@NotNull PersistentDataKey<T> key);
}

View File

@@ -1,15 +1,19 @@
package com.willfp.eco.core.data; package com.willfp.eco.core.data;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.data.keys.PersistentDataKey; import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
/** /**
* API to handle player profiles. * API to handle profiles.
*/ */
public interface PlayerProfileHandler { @ApiStatus.Internal
@Eco.HandlerComponent
public interface ProfileHandler {
/** /**
* Load a player profile. * Load a player profile.
* *
@@ -18,6 +22,13 @@ public interface PlayerProfileHandler {
*/ */
PlayerProfile load(@NotNull UUID uuid); PlayerProfile load(@NotNull UUID uuid);
/**
* Load the server profile.
*
* @return The profile.
*/
ServerProfile loadServerProfile();
/** /**
* Unload a player profile from memory. * Unload a player profile from memory.
* <p> * <p>
@@ -37,7 +48,7 @@ public interface PlayerProfileHandler {
*/ */
@Deprecated @Deprecated
default void savePlayer(@NotNull UUID uuid) { default void savePlayer(@NotNull UUID uuid) {
this.saveKeysForPlayer(uuid, PersistentDataKey.values()); this.saveKeysFor(uuid, PersistentDataKey.values());
} }
/** /**
@@ -48,8 +59,8 @@ public interface PlayerProfileHandler {
* @param uuid The uuid. * @param uuid The uuid.
* @param keys The keys. * @param keys The keys.
*/ */
void saveKeysForPlayer(@NotNull UUID uuid, void saveKeysFor(@NotNull UUID uuid,
@NotNull Set<PersistentDataKey<?>> keys); @NotNull Set<PersistentDataKey<?>> keys);
/** /**
* Save all player data. * Save all player data.

View File

@@ -0,0 +1,21 @@
package com.willfp.eco.core.data;
import com.willfp.eco.core.Eco;
import org.jetbrains.annotations.NotNull;
/**
* Persistent data storage interface for servers.
* <p>
* Profiles save automatically, so there is no need to save after changes.
*/
public interface ServerProfile extends Profile {
/**
* Load the server profile.
*
* @return The profile.
*/
@NotNull
static ServerProfile load() {
return Eco.getHandler().getProfileHandler().loadServerProfile();
}
}

View File

@@ -1,13 +1,17 @@
package com.willfp.eco.core.display; package com.willfp.eco.core.display;
import com.willfp.eco.core.Eco;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
/** /**
* Interface for display implementations. * Interface for display implementations.
*/ */
@ApiStatus.Internal
@Eco.HandlerComponent
public interface DisplayHandler { public interface DisplayHandler {
/** /**
* Register display module. * Register display module.

View File

@@ -1,11 +1,15 @@
package com.willfp.eco.core.drops; package com.willfp.eco.core.drops;
import com.willfp.eco.core.Eco;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Internal component to create backend DropQueue implementations. * Internal component to create backend DropQueue implementations.
*/ */
@ApiStatus.Internal
@Eco.HandlerComponent
public interface DropQueueFactory { public interface DropQueueFactory {
/** /**
* Create a DropQueue. * Create a DropQueue.

View File

@@ -1,7 +1,9 @@
package com.willfp.eco.core.drops; package com.willfp.eco.core.drops;
import com.willfp.eco.core.Eco;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Collection; import java.util.Collection;
@@ -9,6 +11,8 @@ import java.util.Collection;
/** /**
* Internal interface for backend DropQueue implementations. * Internal interface for backend DropQueue implementations.
*/ */
@ApiStatus.Internal
@Eco.HandlerComponent
public interface InternalDropQueue { public interface InternalDropQueue {
/** /**
* Add item to queue. * Add item to queue.

View File

@@ -1,15 +1,19 @@
package com.willfp.eco.core.gui; package com.willfp.eco.core.gui;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.gui.menu.MenuBuilder; import com.willfp.eco.core.gui.menu.MenuBuilder;
import com.willfp.eco.core.gui.slot.SlotBuilder; import com.willfp.eco.core.gui.slot.SlotBuilder;
import com.willfp.eco.core.gui.slot.functional.SlotProvider; import com.willfp.eco.core.gui.slot.functional.SlotProvider;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Internal component used by {@link com.willfp.eco.core.gui.menu.Menu#builder(int)} * Internal component used by {@link com.willfp.eco.core.gui.menu.Menu#builder(int)}
* and {@link com.willfp.eco.core.gui.slot.Slot#builder(ItemStack)}. * and {@link com.willfp.eco.core.gui.slot.Slot#builder(ItemStack)}.
*/ */
@ApiStatus.Internal
@Eco.HandlerComponent
public interface GUIFactory { public interface GUIFactory {
/** /**
* Create slot builder. * Create slot builder.

View File

@@ -6,6 +6,7 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
/** /**
@@ -141,4 +142,21 @@ public class PlaceholderEntry {
public void register() { public void register() {
PlaceholderManager.registerPlaceholder(this); PlaceholderManager.registerPlaceholder(this);
} }
@Override
public boolean equals(@Nullable final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof PlaceholderEntry entry)) {
return false;
}
return Objects.equals(this.getIdentifier(), entry.getIdentifier())
&& Objects.equals(this.getPlugin(), entry.getPlugin());
}
@Override
public int hashCode() {
return Objects.hash(this.getIdentifier(), this.getPlugin());
}
} }

View File

@@ -1,5 +1,7 @@
package com.willfp.eco.core.integrations.placeholder; package com.willfp.eco.core.integrations.placeholder;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.willfp.eco.core.Eco; import com.willfp.eco.core.Eco;
import com.willfp.eco.core.EcoPlugin; import com.willfp.eco.core.EcoPlugin;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -12,6 +14,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit;
/** /**
* Class to handle placeholder integrations. * Class to handle placeholder integrations.
@@ -27,10 +30,17 @@ public final class PlaceholderManager {
*/ */
private static final Set<PlaceholderIntegration> REGISTERED_INTEGRATIONS = new HashSet<>(); private static final Set<PlaceholderIntegration> REGISTERED_INTEGRATIONS = new HashSet<>();
/**
* Placeholder Cache.
*/
private static final LoadingCache<EntryWithPlayer, String> PLACEHOLDER_CACHE = Caffeine.newBuilder()
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
.build(key -> key.entry.getResult(key.player));
/** /**
* Register a new placeholder integration. * Register a new placeholder integration.
* *
* @param integration The {@link PlaceholderIntegration} to register. * @param integration The {@link com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration} to register.
*/ */
public static void addIntegration(@NotNull final PlaceholderIntegration integration) { public static void addIntegration(@NotNull final PlaceholderIntegration integration) {
integration.registerIntegration(); integration.registerIntegration();
@@ -40,7 +50,7 @@ public final class PlaceholderManager {
/** /**
* Register a placeholder. * Register a placeholder.
* *
* @param expansion The {@link PlaceholderEntry} to register. * @param expansion The {@link com.willfp.eco.core.integrations.placeholder.PlaceholderEntry} to register.
*/ */
public static void registerPlaceholder(@NotNull final PlaceholderEntry expansion) { public static void registerPlaceholder(@NotNull final PlaceholderEntry expansion) {
EcoPlugin plugin = expansion.getPlugin() == null ? Eco.getHandler().getEcoPlugin() : expansion.getPlugin(); EcoPlugin plugin = expansion.getPlugin() == null ? Eco.getHandler().getEcoPlugin() : expansion.getPlugin();
@@ -94,7 +104,7 @@ public final class PlaceholderManager {
return ""; return "";
} }
return entry.getResult(player); return PLACEHOLDER_CACHE.get(new EntryWithPlayer(entry, player));
} }
/** /**
@@ -128,6 +138,11 @@ public final class PlaceholderManager {
return found; return found;
} }
private static record EntryWithPlayer(@NotNull PlaceholderEntry entry,
@Nullable Player player) {
}
private PlaceholderManager() { private PlaceholderManager() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
} }

View File

@@ -0,0 +1,103 @@
package com.willfp.eco.core.items;
import com.willfp.eco.core.fast.FastItemStack;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* An item and its {@link com.willfp.eco.core.fast.FastItemStack} hash.
*/
public final class HashedItem {
/**
* The item.
*/
private final ItemStack item;
/**
* The hash.
*/
private final int hash;
/**
* Create new hashed item.
*
* @param item The item.
* @param hash The hash.
*/
private HashedItem(@NotNull final ItemStack item,
final int hash) {
this.item = item;
this.hash = hash;
}
/**
* Get the item.
*
* @return The ItemStack.
*/
public ItemStack getItem() {
return this.item;
}
/**
* Get the hash.
*
* @return The hash.
*/
public int getHash() {
return this.hash;
}
/**
* Kotlin destructuring support.
*
* @return The ItemStack.
*/
public ItemStack component1() {
return this.getItem();
}
/**
* Kotlin destructuring support.
*
* @return The hash.
*/
public int component2() {
return this.getHash();
}
@Override
public int hashCode() {
return this.hash;
}
@Override
public boolean equals(@Nullable final Object other) {
if (!(other instanceof HashedItem o)) {
return false;
}
return o.hash == this.hash;
}
/**
* Hashed item from an item.
*
* @param item The item.
* @return The hashed item.
*/
public static HashedItem of(@NotNull final ItemStack item) {
return new HashedItem(item, FastItemStack.wrap(item).hashCode());
}
/**
* Hashed item from a fast item stack.
*
* @param item The item.
* @return The hashed item.
*/
public static HashedItem of(@NotNull final FastItemStack item) {
return new HashedItem(item.unwrap(), item.hashCode());
}
}

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.core.items; package com.willfp.eco.core.items;
import com.willfp.eco.core.fast.FastItemStack; import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.willfp.eco.core.items.args.LookupArgParser; import com.willfp.eco.core.items.args.LookupArgParser;
import com.willfp.eco.core.items.provider.ItemProvider; import com.willfp.eco.core.items.provider.ItemProvider;
import com.willfp.eco.core.recipe.parts.EmptyTestableItem; import com.willfp.eco.core.recipe.parts.EmptyTestableItem;
@@ -14,7 +15,6 @@ import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -25,6 +25,7 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -38,9 +39,23 @@ public final class Items {
private static final Map<NamespacedKey, TestableItem> REGISTRY = new ConcurrentHashMap<>(); private static final Map<NamespacedKey, TestableItem> REGISTRY = new ConcurrentHashMap<>();
/** /**
* Cached custom item lookups, using {@link FastItemStack#hashCode()}. * Cached custom item lookups, using {@link HashedItem}.
*/ */
private static final Map<Integer, Optional<TestableItem>> CACHE = new ConcurrentHashMap<>(); private static final LoadingCache<HashedItem, Optional<TestableItem>> CACHE = Caffeine.newBuilder()
.expireAfterAccess(5, TimeUnit.MINUTES)
.build(
key -> {
TestableItem match = null;
for (TestableItem item : REGISTRY.values()) {
if (item.matches(key.getItem())) {
match = item;
break;
}
}
return Optional.ofNullable(match);
}
);
/** /**
* All item providers. * All item providers.
@@ -202,7 +217,7 @@ public final class Items {
} }
} }
// Marked as redundant but i am covering all bases here // Marked as redundant but I am covering all bases here
if (item == null || item instanceof EmptyTestableItem) { if (item == null || item instanceof EmptyTestableItem) {
return new EmptyTestableItem(); return new EmptyTestableItem();
} }
@@ -295,28 +310,7 @@ public final class Items {
*/ */
@Nullable @Nullable
public static CustomItem getCustomItem(@NotNull final ItemStack itemStack) { public static CustomItem getCustomItem(@NotNull final ItemStack itemStack) {
int hash = FastItemStack.wrap(itemStack).hashCode(); return CACHE.get(HashedItem.of(itemStack)).map(Items::getOrWrap).orElse(null);
if (CACHE.containsKey(hash)) {
return CACHE.get(hash).map(Items::getOrWrap).orElse(null);
}
TestableItem match = null;
for (TestableItem item : REGISTRY.values()) {
if (item.matches(itemStack)) {
match = item;
break;
}
}
// Cache even if not matched; allows for marking hashes as definitely not custom.
CACHE.put(hash, Optional.ofNullable(match));
if (match == null) {
return null;
}
return getOrWrap(match);
} }
/** /**
@@ -350,14 +344,6 @@ public final class Items {
} }
} }
/**
* Clear the lookup cache.
*/
@ApiStatus.Internal
public static void clearCache() {
CACHE.clear();
}
private Items() { private Items() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
} }

View File

@@ -7,6 +7,7 @@ import com.willfp.eco.core.items.Items;
import com.willfp.eco.core.recipe.recipes.CraftingRecipe; import com.willfp.eco.core.recipe.recipes.CraftingRecipe;
import com.willfp.eco.core.recipe.recipes.ShapedCraftingRecipe; import com.willfp.eco.core.recipe.recipes.ShapedCraftingRecipe;
import com.willfp.eco.util.NamespacedKeyUtils; import com.willfp.eco.util.NamespacedKeyUtils;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -96,6 +97,7 @@ public final class Recipes {
* @param permission The permission. * @param permission The permission.
* @return The recipe. * @return The recipe.
*/ */
@Nullable
public static CraftingRecipe createAndRegisterRecipe(@NotNull final EcoPlugin plugin, public static CraftingRecipe createAndRegisterRecipe(@NotNull final EcoPlugin plugin,
@NotNull final String key, @NotNull final String key,
@NotNull final ItemStack output, @NotNull final ItemStack output,
@@ -109,6 +111,12 @@ public final class Recipes {
builder.setRecipePart(i, Items.lookup(recipeStrings.get(i))); builder.setRecipePart(i, Items.lookup(recipeStrings.get(i)));
} }
if (builder.isAir()) {
Bukkit.getLogger().warning("RECIPE ERROR! " + plugin.getName() + ":" + key + " consists only");
Bukkit.getLogger().warning("of air or invalid items! Please change that or disable this recipe.");
return null;
}
ShapedCraftingRecipe recipe = builder.build(); ShapedCraftingRecipe recipe = builder.build();
recipe.register(); recipe.register();

View File

@@ -287,6 +287,20 @@ public final class ShapedCraftingRecipe extends PluginDependent<EcoPlugin> imple
return this; return this;
} }
/**
* Check if recipe parts are all air.
*
* @return If recipe parts are all air.
*/
public boolean isAir() {
for (TestableItem recipePart : this.recipeParts) {
if (recipePart!= null && !(recipePart instanceof EmptyTestableItem)) {
return false;
}
}
return true;
}
/** /**
* Build the recipe. * Build the recipe.
* *

View File

@@ -1,10 +1,14 @@
package com.willfp.eco.core.requirement; package com.willfp.eco.core.requirement;
import com.willfp.eco.core.Eco;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Interface for internal requirement factory implementations. * Interface for internal requirement factory implementations.
*/ */
@ApiStatus.Internal
@Eco.HandlerComponent
public interface RequirementFactory { public interface RequirementFactory {
/** /**
* Create a requirement. * Create a requirement.

View File

@@ -1,5 +1,7 @@
package com.willfp.eco.util; package com.willfp.eco.util;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
@@ -20,6 +22,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -66,6 +69,42 @@ public final class StringUtils {
.emitLegacyHoverEvent() .emitLegacyHoverEvent()
.build(); .build();
/**
* String format cache.
*/
private static final LoadingCache<String, String> STRING_FORMAT_CACHE = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build(StringUtils::processFormatting);
/**
* Json -> Legacy Cache.
*/
private static final LoadingCache<String, String> JSON_TO_LEGACY = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build(
json -> {
try {
Component component = GSON_COMPONENT_SERIALIZER.deserialize(json);
return LEGACY_COMPONENT_SERIALIZER.serialize(component);
} catch (JsonSyntaxException e) {
return json;
}
}
);
/**
* Legacy -> Json Cache.
*/
private static final LoadingCache<String, String> LEGACY_TO_JSON = Caffeine.newBuilder()
.expireAfterAccess(10, TimeUnit.SECONDS)
.build(
legacy -> GSON_COMPONENT_SERIALIZER.serialize(
Component.empty().decoration(TextDecoration.ITALIC, false).append(
LEGACY_COMPONENT_SERIALIZER.deserialize(legacy)
)
)
);
/** /**
* Color map. * Color map.
*/ */
@@ -272,6 +311,11 @@ public final class StringUtils {
if (option == FormatOption.WITH_PLACEHOLDERS) { if (option == FormatOption.WITH_PLACEHOLDERS) {
processedMessage = PlaceholderManager.translatePlaceholders(processedMessage, player); processedMessage = PlaceholderManager.translatePlaceholders(processedMessage, player);
} }
return STRING_FORMAT_CACHE.get(processedMessage);
}
private static String processFormatting(@NotNull final String message) {
String processedMessage = message;
processedMessage = ChatColor.translateAlternateColorCodes('&', processedMessage); processedMessage = ChatColor.translateAlternateColorCodes('&', processedMessage);
processedMessage = translateGradients(processedMessage); processedMessage = translateGradients(processedMessage);
processedMessage = translateHexColorCodes(processedMessage); processedMessage = translateHexColorCodes(processedMessage);
@@ -423,11 +467,8 @@ public final class StringUtils {
if (legacy == null) { if (legacy == null) {
processed = ""; processed = "";
} }
return GSON_COMPONENT_SERIALIZER.serialize(
Component.empty().decoration(TextDecoration.ITALIC, false).append( return LEGACY_TO_JSON.get(processed);
LEGACY_COMPONENT_SERIALIZER.deserialize(processed)
)
);
} }
/** /**
@@ -442,12 +483,7 @@ public final class StringUtils {
return ""; return "";
} }
try { return JSON_TO_LEGACY.get(json);
Component component = GSON_COMPONENT_SERIALIZER.deserialize(json);
return LEGACY_COMPONENT_SERIALIZER.serialize(component);
} catch (JsonSyntaxException e) {
return json;
}
} }
/** /**

View File

@@ -7,6 +7,5 @@ dependencies {
compileOnly 'org.reflections:reflections:0.9.12' compileOnly 'org.reflections:reflections:0.9.12'
compileOnly 'net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT' compileOnly 'net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT'
compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0' compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0'
compileOnly 'com.google.guava:guava:31.0.1-jre'
compileOnly 'org.objenesis:objenesis:3.2' compileOnly 'org.objenesis:objenesis:3.2'
} }

View File

@@ -0,0 +1,30 @@
package com.willfp.eco.internal.entities
import com.willfp.eco.core.entities.args.EntityArgParseResult
import com.willfp.eco.core.entities.args.EntityArgParser
import org.bukkit.entity.Animals
class EntityArgParserSilent : EntityArgParser {
override fun parseArguments(args: Array<out String>): EntityArgParseResult? {
var silent = false
for (arg in args) {
if (arg.equals("silent", true)) {
silent = true
}
}
if (!silent) {
return null
}
return EntityArgParseResult(
{
it.isSilent
},
{
it.isSilent = true
}
)
}
}

View File

@@ -40,10 +40,9 @@ dependencies {
compileOnly 'com.bgsoftware:SuperiorSkyblockAPI:1.8.3' compileOnly 'com.bgsoftware:SuperiorSkyblockAPI:1.8.3'
compileOnly 'com.github.MilkBowl:VaultAPI:1.7' compileOnly 'com.github.MilkBowl:VaultAPI:1.7'
compileOnly 'world.bentobox:bentobox:1.17.3-SNAPSHOT' compileOnly 'world.bentobox:bentobox:1.17.3-SNAPSHOT'
compileOnly 'com.google.guava:guava:31.0.1-jre'
compileOnly 'com.iridium:IridiumSkyblock:3.1.2' compileOnly 'com.iridium:IridiumSkyblock:3.1.2'
compileOnly 'com.github.WhipDevelopment:CrashClaim:f9cd7d92eb' compileOnly 'com.github.WhipDevelopment:CrashClaim:f9cd7d92eb'
compileOnly 'com.wolfyscript.wolfyutilities:wolfyutilities:1.7.8.1' compileOnly 'com.wolfyscript.wolfyutilities:wolfyutilities:3.16.0.0'
compileOnly 'com.github.decentsoftware-eu:decentholograms:2.1.2' compileOnly 'com.github.decentsoftware-eu:decentholograms:2.1.2'
compileOnly 'io.lumine.xikage:MythicMobs:4.9.1' compileOnly 'io.lumine.xikage:MythicMobs:4.9.1'
@@ -55,6 +54,9 @@ dependencies {
compileOnly 'com.github.sirblobman.combatlogx:api:11.0.0.0-SNAPSHOT' compileOnly 'com.github.sirblobman.combatlogx:api:11.0.0.0-SNAPSHOT'
compileOnly 'com.github.sirblobman.combatlogx.expansion:newbie-helper:11.0.0.0-SNAPSHOT' compileOnly 'com.github.sirblobman.combatlogx.expansion:newbie-helper:11.0.0.0-SNAPSHOT'
// LibsDisguises
compileOnly 'LibsDisguises:LibsDisguises:10.0.26'
compileOnly fileTree(dir: '../../lib', include: ['*.jar']) compileOnly fileTree(dir: '../../lib', include: ['*.jar'])
} }

View File

@@ -1,339 +0,0 @@
package com.willfp.eco.internal.spigot.recipes;
import com.willfp.eco.core.EcoPlugin;
import com.willfp.eco.core.PluginDependent;
import com.willfp.eco.core.items.Items;
import com.willfp.eco.core.items.TestableItem;
import com.willfp.eco.core.recipe.Recipes;
import com.willfp.eco.core.recipe.parts.MaterialTestableItem;
import com.willfp.eco.core.recipe.parts.ModifiedTestableItem;
import com.willfp.eco.core.recipe.parts.TestableStack;
import com.willfp.eco.core.recipe.recipes.CraftingRecipe;
import com.willfp.eco.core.recipe.recipes.ShapedCraftingRecipe;
import org.bukkit.Keyed;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.event.inventory.PrepareItemCraftEvent;
import org.bukkit.event.player.PlayerRecipeDiscoverEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapedRecipe;
import org.jetbrains.annotations.NotNull;
public class ShapedRecipeListener extends PluginDependent<EcoPlugin> implements Listener {
public ShapedRecipeListener(@NotNull final EcoPlugin plugin) {
super(plugin);
}
private void allow(@NotNull final Event event,
@NotNull final CraftingRecipe recipe) {
if (event instanceof PrepareItemCraftEvent) {
((PrepareItemCraftEvent) event).getInventory().setResult(recipe.getOutput());
}
if (event instanceof CraftItemEvent) {
((CraftItemEvent) event).getInventory().setResult(recipe.getOutput());
}
}
private void deny(@NotNull final Event event) {
if (event instanceof PrepareItemCraftEvent) {
((PrepareItemCraftEvent) event).getInventory().setResult(new ItemStack(Material.AIR));
}
if (event instanceof CraftItemEvent) {
((CraftItemEvent) event).getInventory().setResult(new ItemStack(Material.AIR));
((CraftItemEvent) event).setResult(Event.Result.DENY);
((CraftItemEvent) event).setCancelled(true);
}
}
@EventHandler
public void complexRecipeListener(@NotNull final PrepareItemCraftEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe recipe)) {
return;
}
if (!EcoPlugin.getPluginNames().contains(recipe.getKey().getNamespace())) {
return;
}
if (!(event.getInventory().getViewers().get(0) instanceof Player player)) {
return;
}
ItemStack[] matrix = event.getInventory().getMatrix();
CraftingRecipe matched = Recipes.getMatch(matrix);
if (matched == null) {
deny(event);
return;
}
if (matched.test(matrix)) {
if (matched.getPermission() != null) {
if (player.hasPermission(matched.getPermission())) {
allow(event, matched);
} else {
deny(event);
}
} else {
allow(event, matched);
}
} else {
deny(event);
}
}
@EventHandler
public void complexRecipeListener(@NotNull final CraftItemEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe recipe)) {
return;
}
if (!EcoPlugin.getPluginNames().contains(recipe.getKey().getNamespace())) {
return;
}
if (!(event.getInventory().getViewers().get(0) instanceof Player player)) {
return;
}
ItemStack[] matrix = event.getInventory().getMatrix();
CraftingRecipe matched = Recipes.getMatch(matrix);
if (matched == null) {
deny(event);
return;
}
if (matched.test(matrix)) {
if (matched.getPermission() != null) {
if (player.hasPermission(matched.getPermission())) {
allow(event, matched);
} else {
deny(event);
}
} else {
allow(event, matched);
}
} else {
deny(event);
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void stackedRecipeListener(@NotNull final CraftItemEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe recipe)) {
return;
}
if (!EcoPlugin.getPluginNames().contains(recipe.getKey().getNamespace())) {
return;
}
ItemStack[] matrix = event.getInventory().getMatrix();
CraftingRecipe matched = Recipes.getMatch(matrix);
if (matched == null) {
return;
}
boolean isStackedRecipe = false;
int upperBound = 64;
for (int i = 0; i < 9; i++) {
ItemStack inMatrix = event.getInventory().getMatrix()[i];
TestableItem inRecipe = matched.getParts().get(i);
if (inRecipe instanceof TestableStack testableStack) {
int max = Math.floorDiv(inMatrix.getAmount(), testableStack.getAmount());
if (max < upperBound) {
upperBound = max;
}
isStackedRecipe = true;
} else if (inMatrix != null) {
int max = inMatrix.getAmount();
if (max < upperBound) {
upperBound = max;
}
}
}
if (!isStackedRecipe) {
return;
}
int toGivePerRecipe = event.getRecipe().getResult().getAmount();
int maxStackSize = event.getRecipe().getResult().getMaxStackSize();
while (toGivePerRecipe * upperBound > maxStackSize) {
upperBound--;
}
for (int i = 0; i < 9; i++) {
ItemStack inMatrix = event.getInventory().getMatrix()[i];
TestableItem inRecipe = matched.getParts().get(i);
if (inRecipe instanceof TestableStack testableStack) {
if (event.isShiftClick()) {
int amount = inMatrix.getAmount() + 1;
for (int j = 0; j < upperBound; j++) {
amount -= testableStack.getAmount();
}
inMatrix.setAmount(amount);
} else {
inMatrix.setAmount(inMatrix.getAmount() - (testableStack.getAmount() - 1));
}
}
}
int finalUpperBound = upperBound;
if (event.isShiftClick()) {
ItemStack result = event.getInventory().getResult();
if (result == null) {
return;
}
result.setAmount(result.getAmount() * finalUpperBound);
event.getInventory().setResult(result);
}
}
@EventHandler
public void preventUsingComplexPartInEcoRecipe(@NotNull final PrepareItemCraftEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe recipe)) {
return;
}
CraftingRecipe craftingRecipe = Recipes.getRecipe(recipe.getKey());
if (!(craftingRecipe instanceof ShapedCraftingRecipe shapedCraftingRecipe)) {
return;
}
for (int i = 0; i < 9; i++) {
ItemStack itemStack = event.getInventory().getMatrix()[i];
TestableItem part = shapedCraftingRecipe.getParts().get(i);
if (part instanceof MaterialTestableItem) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
return;
}
}
if (part instanceof ModifiedTestableItem modified) {
if (modified.getHandle() instanceof MaterialTestableItem) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
return;
}
}
}
if (part instanceof TestableStack modified) {
if (modified.getHandle() instanceof MaterialTestableItem) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
return;
}
}
}
}
}
@EventHandler
public void preventUsingComplexPartInEcoRecipe(@NotNull final CraftItemEvent event) {
if (!(event.getRecipe() instanceof ShapedRecipe recipe)) {
return;
}
CraftingRecipe craftingRecipe = Recipes.getRecipe(recipe.getKey());
if (!(craftingRecipe instanceof ShapedCraftingRecipe shapedCraftingRecipe)) {
return;
}
for (int i = 0; i < 9; i++) {
ItemStack itemStack = event.getInventory().getMatrix()[i];
TestableItem part = shapedCraftingRecipe.getParts().get(i);
if (part instanceof MaterialTestableItem) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
event.setResult(Event.Result.DENY);
event.setCancelled(true);
return;
}
}
if (part instanceof ModifiedTestableItem modified) {
if (modified.getHandle() instanceof MaterialTestableItem) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
event.setResult(Event.Result.DENY);
event.setCancelled(true);
return;
}
}
}
if (part instanceof TestableStack modified) {
if (modified.getHandle() instanceof MaterialTestableItem) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
return;
}
}
}
}
}
@EventHandler
public void preventUsingComplexPartInVanillaRecipe(@NotNull final PrepareItemCraftEvent event) {
if (!(event.getRecipe() instanceof Keyed recipe)) {
return;
}
if (EcoPlugin.getPluginNames().contains(recipe.getKey().getNamespace())) {
return;
}
for (ItemStack itemStack : event.getInventory().getMatrix()) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
return;
}
}
}
@EventHandler
public void preventUsingComplexPartInVanillaRecipe(@NotNull final CraftItemEvent event) {
if (!(event.getRecipe() instanceof Keyed recipe)) {
return;
}
if (EcoPlugin.getPluginNames().contains(recipe.getKey().getNamespace())) {
return;
}
for (ItemStack itemStack : event.getInventory().getMatrix()) {
if (Items.isCustomItem(itemStack)) {
event.getInventory().setResult(new ItemStack(Material.AIR));
event.setResult(Event.Result.DENY);
event.setCancelled(true);
return;
}
}
}
@EventHandler
public void preventLearningDisplayedRecipes(@NotNull final PlayerRecipeDiscoverEvent event) {
if (!EcoPlugin.getPluginNames().contains(event.getRecipe().getNamespace())) {
return;
}
if (event.getRecipe().getKey().contains("_displayed")) {
event.setCancelled(true);
}
}
}

View File

@@ -24,7 +24,7 @@ import com.willfp.eco.internal.proxy.EcoProxyFactory
import com.willfp.eco.internal.requirement.EcoRequirementFactory import com.willfp.eco.internal.requirement.EcoRequirementFactory
import com.willfp.eco.internal.scheduling.EcoScheduler import com.willfp.eco.internal.scheduling.EcoScheduler
import com.willfp.eco.internal.spigot.data.EcoKeyRegistry import com.willfp.eco.internal.spigot.data.EcoKeyRegistry
import com.willfp.eco.internal.spigot.data.EcoPlayerProfileHandler import com.willfp.eco.internal.spigot.data.EcoProfileHandler
import com.willfp.eco.internal.spigot.data.storage.MySQLDataHandler import com.willfp.eco.internal.spigot.data.storage.MySQLDataHandler
import com.willfp.eco.internal.spigot.data.storage.YamlDataHandler import com.willfp.eco.internal.spigot.data.storage.YamlDataHandler
import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler
@@ -43,10 +43,12 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
private val requirementFactory = EcoRequirementFactory() private val requirementFactory = EcoRequirementFactory()
private var adventure: BukkitAudiences? = null private var adventure: BukkitAudiences? = null
private val keyRegistry = EcoKeyRegistry(this) private val keyRegistry = EcoKeyRegistry(this)
private val playerProfileHandler = EcoPlayerProfileHandler( private val playerProfileHandler = EcoProfileHandler(
if (this.configYml.getBool("mysql.enabled")) if (this.configYml.getBool("mysql.enabled"))
MySQLDataHandler(this) else YamlDataHandler(this) MySQLDataHandler(this) else YamlDataHandler(this)
) )
@Suppress("RedundantNullableReturnType")
private val keyFactory: InternalNamespacedKeyFactory? = private val keyFactory: InternalNamespacedKeyFactory? =
if (this.configYml.getBool("use-safer-namespacedkey-creation")) if (this.configYml.getBool("use-safer-namespacedkey-creation"))
SafeInternalNamespacedKeyFactory() else FastInternalNamespacedKeyFactory() SafeInternalNamespacedKeyFactory() else FastInternalNamespacedKeyFactory()
@@ -143,7 +145,7 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
return keyRegistry return keyRegistry
} }
override fun getPlayerProfileHandler(): EcoPlayerProfileHandler { override fun getProfileHandler(): EcoProfileHandler {
return playerProfileHandler return playerProfileHandler
} }

View File

@@ -33,6 +33,7 @@ import com.willfp.eco.internal.entities.EntityArgParserKnockback
import com.willfp.eco.internal.entities.EntityArgParserKnockbackResistance import com.willfp.eco.internal.entities.EntityArgParserKnockbackResistance
import com.willfp.eco.internal.entities.EntityArgParserName import com.willfp.eco.internal.entities.EntityArgParserName
import com.willfp.eco.internal.entities.EntityArgParserNoAI import com.willfp.eco.internal.entities.EntityArgParserNoAI
import com.willfp.eco.internal.entities.EntityArgParserSilent
import com.willfp.eco.internal.entities.EntityArgParserSize import com.willfp.eco.internal.entities.EntityArgParserSize
import com.willfp.eco.internal.entities.EntityArgParserSpawnReinforcements import com.willfp.eco.internal.entities.EntityArgParserSpawnReinforcements
import com.willfp.eco.internal.entities.EntityArgParserSpeed import com.willfp.eco.internal.entities.EntityArgParserSpeed
@@ -74,12 +75,14 @@ import com.willfp.eco.internal.spigot.integrations.anticheat.AnticheatVulcan
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefBentoBox import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefBentoBox
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV10 import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV10
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV11 import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCombatLogXV11
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefCrashClaim
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefDeluxeCombat import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefDeluxeCombat
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefFactionsUUID import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefFactionsUUID
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefGriefPrevention import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefGriefPrevention
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefIridiumSkyblock import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefIridiumSkyblock
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefKingdoms import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefKingdoms
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefLands import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefLands
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefRPGHorses
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefSuperiorSkyblock2 import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefSuperiorSkyblock2
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefTowny import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefTowny
import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefWorldGuard import com.willfp.eco.internal.spigot.integrations.antigrief.AntigriefWorldGuard
@@ -89,6 +92,7 @@ import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsExecut
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsHeadDatabase import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsHeadDatabase
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsItemsAdder import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsItemsAdder
import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsOraxen import com.willfp.eco.internal.spigot.integrations.customitems.CustomItemsOraxen
import com.willfp.eco.internal.spigot.integrations.customrecipes.CustomRecipeCustomCrafting
import com.willfp.eco.internal.spigot.integrations.economy.EconomyVault import com.willfp.eco.internal.spigot.integrations.economy.EconomyVault
import com.willfp.eco.internal.spigot.integrations.hologram.HologramCMI import com.willfp.eco.internal.spigot.integrations.hologram.HologramCMI
import com.willfp.eco.internal.spigot.integrations.hologram.HologramDecentHolograms import com.willfp.eco.internal.spigot.integrations.hologram.HologramDecentHolograms
@@ -102,6 +106,9 @@ import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy
import com.willfp.eco.internal.spigot.proxy.SkullProxy import com.willfp.eco.internal.spigot.proxy.SkullProxy
import com.willfp.eco.internal.spigot.proxy.TPSProxy import com.willfp.eco.internal.spigot.proxy.TPSProxy
import com.willfp.eco.internal.spigot.recipes.ShapedRecipeListener import com.willfp.eco.internal.spigot.recipes.ShapedRecipeListener
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInComplex
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInEco
import com.willfp.eco.internal.spigot.recipes.listeners.ComplexInVanilla
import com.willfp.eco.util.BlockUtils import com.willfp.eco.util.BlockUtils
import com.willfp.eco.util.NumberUtils import com.willfp.eco.util.NumberUtils
import com.willfp.eco.util.ServerUtils import com.willfp.eco.util.ServerUtils
@@ -145,6 +152,11 @@ abstract class EcoSpigotPlugin : EcoPlugin(
Entities.registerArgParser(EntityArgParserAdult()) Entities.registerArgParser(EntityArgParserAdult())
Entities.registerArgParser(EntityArgParserCharged()) Entities.registerArgParser(EntityArgParserCharged())
Entities.registerArgParser(EntityArgParserExplosionRadius()) Entities.registerArgParser(EntityArgParserExplosionRadius())
Entities.registerArgParser(EntityArgParserSilent())
ShapedRecipeListener.registerListener(ComplexInComplex())
ShapedRecipeListener.registerListener(ComplexInEco())
ShapedRecipeListener.registerListener(ComplexInVanilla())
val skullProxy = getProxy(SkullProxy::class.java) val skullProxy = getProxy(SkullProxy::class.java)
SkullUtils.initialize( SkullUtils.initialize(
@@ -183,7 +195,7 @@ abstract class EcoSpigotPlugin : EcoPlugin(
override fun handleDisable() { override fun handleDisable() {
this.logger.info("Saving player data...") this.logger.info("Saving player data...")
val start = System.currentTimeMillis() val start = System.currentTimeMillis()
Eco.getHandler().playerProfileHandler.save() Eco.getHandler().profileHandler.save()
this.logger.info("Saved player data! Took ${System.currentTimeMillis() - start}ms") this.logger.info("Saved player data! Took ${System.currentTimeMillis() - start}ms")
Eco.getHandler().adventure?.close() Eco.getHandler().adventure?.close()
} }
@@ -192,11 +204,6 @@ abstract class EcoSpigotPlugin : EcoPlugin(
CollatedRunnable(this) CollatedRunnable(this)
DropManager.update(this) DropManager.update(this)
ProfileSaver(this) ProfileSaver(this)
this.scheduler.runTimer(
{ Items.clearCache() },
this.configYml.getInt("item-cache-ttl").toLong(),
this.configYml.getInt("item-cache-ttl").toLong()
)
this.scheduler.runTimer( this.scheduler.runTimer(
{ clearFrames() }, { clearFrames() },
this.configYml.getInt("display-frame-ttl").toLong(), this.configYml.getInt("display-frame-ttl").toLong(),
@@ -223,7 +230,8 @@ abstract class EcoSpigotPlugin : EcoPlugin(
IntegrationLoader("Towny") { AntigriefManager.register(AntigriefTowny()) }, IntegrationLoader("Towny") { AntigriefManager.register(AntigriefTowny()) },
IntegrationLoader("Lands") { AntigriefManager.register(AntigriefLands(this)) }, IntegrationLoader("Lands") { AntigriefManager.register(AntigriefLands(this)) },
IntegrationLoader("Kingdoms") { AntigriefManager.register(AntigriefKingdoms()) }, IntegrationLoader("Kingdoms") { AntigriefManager.register(AntigriefKingdoms()) },
//IntegrationLoader("CrashClaim") { AntigriefManager.register(AntigriefCrashClaim()) }, IntegrationLoader("RPGHorses") { AntigriefManager.register(AntigriefRPGHorses()) },
IntegrationLoader("CrashClaim") { AntigriefManager.register(AntigriefCrashClaim()) },
IntegrationLoader("CombatLogX") { IntegrationLoader("CombatLogX") {
val pluginManager = Bukkit.getPluginManager() val pluginManager = Bukkit.getPluginManager()
val combatLogXPlugin = pluginManager.getPlugin("CombatLogX") ?: return@IntegrationLoader val combatLogXPlugin = pluginManager.getPlugin("CombatLogX") ?: return@IntegrationLoader
@@ -252,7 +260,11 @@ abstract class EcoSpigotPlugin : EcoPlugin(
IntegrationLoader("ItemsAdder") { CustomItemsManager.register(CustomItemsItemsAdder()) }, IntegrationLoader("ItemsAdder") { CustomItemsManager.register(CustomItemsItemsAdder()) },
IntegrationLoader("HeadDatabase") { CustomItemsManager.register(CustomItemsHeadDatabase(this)) }, IntegrationLoader("HeadDatabase") { CustomItemsManager.register(CustomItemsHeadDatabase(this)) },
IntegrationLoader("ExecutableItems") { CustomItemsManager.register(CustomItemsExecutableItems()) }, IntegrationLoader("ExecutableItems") { CustomItemsManager.register(CustomItemsExecutableItems()) },
IntegrationLoader("CustomCrafting") { CustomItemsManager.register(CustomItemsCustomCrafting()) }, IntegrationLoader("CustomCrafting") {
CustomItemsManager.register(CustomItemsCustomCrafting()); ShapedRecipeListener.registerValidator(
CustomRecipeCustomCrafting()
)
},
// Shop // Shop
IntegrationLoader("ShopGUIPlus") { ShopManager.register(ShopShopGuiPlus()) }, IntegrationLoader("ShopGUIPlus") { ShopManager.register(ShopShopGuiPlus()) },
@@ -302,7 +314,7 @@ abstract class EcoSpigotPlugin : EcoPlugin(
NaturalExpGainListeners(), NaturalExpGainListeners(),
ArmorListener(), ArmorListener(),
EntityDeathByEntityListeners(this), EntityDeathByEntityListeners(this),
ShapedRecipeListener(this), ShapedRecipeListener(),
GUIListener(this), GUIListener(this),
ArrowDataListener(this), ArrowDataListener(this),
ArmorChangeEventListeners(this), ArmorChangeEventListeners(this),

View File

@@ -15,7 +15,7 @@ class DataListener(
) : Listener { ) : Listener {
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
fun onLeave(event: PlayerQuitEvent) { fun onLeave(event: PlayerQuitEvent) {
Eco.getHandler().playerProfileHandler.unloadPlayer(event.player.uniqueId) Eco.getHandler().profileHandler.unloadPlayer(event.player.uniqueId)
} }
@EventHandler @EventHandler
@@ -27,6 +27,6 @@ class DataListener(
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
fun onLogin(event: PlayerLoginEvent) { fun onLogin(event: PlayerLoginEvent) {
Eco.getHandler().playerProfileHandler.unloadPlayer(event.player.uniqueId) Eco.getHandler().profileHandler.unloadPlayer(event.player.uniqueId)
} }
} }

View File

@@ -21,7 +21,7 @@ class EcoKeyRegistry(
this.registry[key.key] = key this.registry[key.key] = key
(Eco.getHandler().playerProfileHandler as EcoPlayerProfileHandler).updateKeys() (Eco.getHandler().profileHandler as EcoProfileHandler).updateKeys()
} }
override fun getRegisteredKeys(): MutableSet<PersistentDataKey<*>> { override fun getRegisteredKeys(): MutableSet<PersistentDataKey<*>> {

View File

@@ -1,16 +1,18 @@
package com.willfp.eco.internal.spigot.data package com.willfp.eco.internal.spigot.data
import com.willfp.eco.core.data.PlayerProfile import com.willfp.eco.core.data.PlayerProfile
import com.willfp.eco.core.data.Profile
import com.willfp.eco.core.data.ServerProfile
import com.willfp.eco.core.data.keys.PersistentDataKey import com.willfp.eco.core.data.keys.PersistentDataKey
import com.willfp.eco.internal.spigot.data.storage.DataHandler import com.willfp.eco.internal.spigot.data.storage.DataHandler
import java.util.UUID import java.util.UUID
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
class EcoPlayerProfile( abstract class EcoProfile(
val data: MutableMap<PersistentDataKey<*>, Any>, val data: MutableMap<PersistentDataKey<*>, Any>,
val uuid: UUID, val uuid: UUID,
private val handler: DataHandler private val handler: DataHandler
) : PlayerProfile { ) : Profile {
override fun <T : Any> write(key: PersistentDataKey<T>, value: T) { override fun <T : Any> write(key: PersistentDataKey<T>, value: T) {
this.data[key] = value this.data[key] = value
@@ -30,22 +32,37 @@ class EcoPlayerProfile(
} }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (other !is EcoPlayerProfile) { if (other !is EcoProfile) {
return false return false
} }
return this.data == other.data return this.data == other.data && this.uuid == other.uuid
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return data.hashCode() return this.data.hashCode()
}
override fun toString(): String {
return "EcoPlayerProfile{$data}"
} }
companion object { companion object {
val CHANGE_MAP: MutableMap<UUID, MutableSet<PersistentDataKey<*>>> = ConcurrentHashMap() val CHANGE_MAP: MutableMap<UUID, MutableSet<PersistentDataKey<*>>> = ConcurrentHashMap()
} }
}
class EcoPlayerProfile(
data: MutableMap<PersistentDataKey<*>, Any>,
uuid: UUID,
handler: DataHandler
) : EcoProfile(data, uuid, handler), PlayerProfile {
override fun toString(): String {
return "EcoPlayerProfile{uuid=$uuid}"
}
}
class EcoServerProfile(
data: MutableMap<PersistentDataKey<*>, Any>,
handler: DataHandler
) : EcoProfile(data, serverProfileUUID, handler), ServerProfile {
override fun toString(): String {
return "EcoServerProfile"
}
} }

View File

@@ -1,17 +1,21 @@
package com.willfp.eco.internal.spigot.data package com.willfp.eco.internal.spigot.data
import com.willfp.eco.core.data.PlayerProfile import com.willfp.eco.core.data.PlayerProfile
import com.willfp.eco.core.data.PlayerProfileHandler import com.willfp.eco.core.data.Profile
import com.willfp.eco.core.data.ProfileHandler
import com.willfp.eco.core.data.ServerProfile
import com.willfp.eco.core.data.keys.PersistentDataKey import com.willfp.eco.core.data.keys.PersistentDataKey
import com.willfp.eco.internal.spigot.data.storage.DataHandler import com.willfp.eco.internal.spigot.data.storage.DataHandler
import java.util.UUID import java.util.UUID
class EcoPlayerProfileHandler( val serverProfileUUID = UUID(0, 0)
private val handler: DataHandler
) : PlayerProfileHandler {
private val loaded = mutableMapOf<UUID, PlayerProfile>()
override fun load(uuid: UUID): PlayerProfile { class EcoProfileHandler(
private val handler: DataHandler
) : ProfileHandler {
private val loaded = mutableMapOf<UUID, Profile>()
private fun loadGenericProfile(uuid: UUID): Profile {
val found = loaded[uuid] val found = loaded[uuid]
if (found != null) { if (found != null) {
return found return found
@@ -19,12 +23,22 @@ class EcoPlayerProfileHandler(
val data = mutableMapOf<PersistentDataKey<*>, Any>() val data = mutableMapOf<PersistentDataKey<*>, Any>()
val profile = EcoPlayerProfile(data, uuid, handler) val profile = if (uuid == serverProfileUUID)
EcoServerProfile(data, handler) else EcoPlayerProfile(data, uuid, handler)
loaded[uuid] = profile loaded[uuid] = profile
return profile return profile
} }
override fun saveKeysForPlayer(uuid: UUID, keys: Set<PersistentDataKey<*>>) { override fun load(uuid: UUID): PlayerProfile {
return loadGenericProfile(uuid) as PlayerProfile
}
override fun loadServerProfile(): ServerProfile {
return loadGenericProfile(serverProfileUUID) as ServerProfile
}
override fun saveKeysFor(uuid: UUID, keys: Set<PersistentDataKey<*>>) {
val profile = PlayerProfile.load(uuid) val profile = PlayerProfile.load(uuid)
for (key in keys) { for (key in keys) {

View File

@@ -2,15 +2,15 @@ package com.willfp.eco.internal.spigot.data.storage
import com.willfp.eco.core.Eco import com.willfp.eco.core.Eco
import com.willfp.eco.core.EcoPlugin import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.internal.spigot.data.EcoPlayerProfile import com.willfp.eco.internal.spigot.data.EcoProfile
class ProfileSaver(plugin: EcoPlugin) { class ProfileSaver(plugin: EcoPlugin) {
init { init {
plugin.scheduler.runTimer({ plugin.scheduler.runTimer({
for ((uuid, set) in EcoPlayerProfile.CHANGE_MAP) { for ((uuid, set) in EcoProfile.CHANGE_MAP) {
Eco.getHandler().playerProfileHandler.saveKeysForPlayer(uuid, set) Eco.getHandler().profileHandler.saveKeysFor(uuid, set)
} }
EcoPlayerProfile.CHANGE_MAP.clear() EcoProfile.CHANGE_MAP.clear()
}, 1, 1) }, 1, 1)
} }
} }

View File

@@ -9,9 +9,8 @@ import com.willfp.eco.core.AbstractPacketAdapter
import com.willfp.eco.core.Eco import com.willfp.eco.core.Eco
import com.willfp.eco.core.EcoPlugin import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.display.Display import com.willfp.eco.core.display.Display
import com.willfp.eco.core.fast.FastItemStack import com.willfp.eco.core.items.HashedItem
import com.willfp.eco.internal.spigot.display.frame.DisplayFrame import com.willfp.eco.internal.spigot.display.frame.DisplayFrame
import com.willfp.eco.internal.spigot.display.frame.HashedItem
import com.willfp.eco.internal.spigot.display.frame.lastDisplayFrame import com.willfp.eco.internal.spigot.display.frame.lastDisplayFrame
import com.willfp.eco.util.ServerUtils import com.willfp.eco.util.ServerUtils
import org.bukkit.entity.Player import org.bukkit.entity.Player
@@ -138,8 +137,7 @@ class PacketWindowItems(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, Packe
val frameMap = mutableMapOf<Byte, HashedItem>() val frameMap = mutableMapOf<Byte, HashedItem>()
for (index in itemStacks.indices) { for (index in itemStacks.indices) {
frameMap[index.toByte()] = frameMap[index.toByte()] = HashedItem.of(itemStacks[index])
HashedItem(FastItemStack.wrap(itemStacks[index]).hashCode(), itemStacks[index])
} }
val newFrame = DisplayFrame(frameMap) val newFrame = DisplayFrame(frameMap)

View File

@@ -1,12 +1,11 @@
package com.willfp.eco.internal.spigot.display.frame package com.willfp.eco.internal.spigot.display.frame
import com.willfp.eco.core.items.HashedItem
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import java.util.UUID import java.util.UUID
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
data class HashedItem(val hash: Int, val item: ItemStack)
data class DisplayFrame(val items: Map<Byte, HashedItem>) { data class DisplayFrame(val items: Map<Byte, HashedItem>) {
fun getChangedSlots(newFrame: DisplayFrame): List<Byte> { fun getChangedSlots(newFrame: DisplayFrame): List<Byte> {
val changes = mutableListOf<Byte>() val changes = mutableListOf<Byte>()

View File

@@ -0,0 +1,47 @@
package com.willfp.eco.internal.spigot.integrations.antigrief
import com.willfp.eco.core.integrations.antigrief.AntigriefWrapper
import org.bukkit.Location
import org.bukkit.block.Block
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Player
import org.plugins.rpghorses.RPGHorsesMain
class AntigriefRPGHorses : AntigriefWrapper {
override fun canBreakBlock(
player: Player,
block: Block
): Boolean {
return true
}
override fun canCreateExplosion(
player: Player,
location: Location
): Boolean {
return true
}
override fun canPlaceBlock(
player: Player,
block: Block
): Boolean {
return true
}
override fun canInjure(
player: Player,
victim: LivingEntity
): Boolean {
val horse = RPGHorsesMain.getInstance().rpgHorseManager.getRPGHorse(victim)?: return true
return horse.horseOwner.uuid.equals(player.uniqueId)
}
override fun canPickupItem(player: Player, location: Location): Boolean {
return true
}
override fun getPluginName(): String {
return "RPGHorses"
}
}

View File

@@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")
package com.willfp.eco.internal.spigot.integrations.customitems package com.willfp.eco.internal.spigot.integrations.customitems
import com.willfp.eco.core.integrations.customitems.CustomItemsWrapper import com.willfp.eco.core.integrations.customitems.CustomItemsWrapper
@@ -10,13 +12,16 @@ import me.wolfyscript.utilities.util.NamespacedKey
import me.wolfyscript.utilities.util.Registry import me.wolfyscript.utilities.util.Registry
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import java.util.function.Predicate import java.util.function.Predicate
class CustomItemsCustomCrafting: CustomItemsWrapper {
class CustomItemsCustomCrafting : CustomItemsWrapper {
override fun registerAllItems() { override fun registerAllItems() {
Items.registerItemProvider(CustomCraftingProvider()) Items.registerItemProvider(CustomCraftingProvider())
} }
override fun getPluginName(): String { override fun getPluginName(): String {
return "CustomCrafting" return "CustomCrafting"
} }
private class CustomCraftingProvider : ItemProvider("customcrafting") { private class CustomCraftingProvider : ItemProvider("customcrafting") {
override fun provideForKey(key: String): TestableItem? { override fun provideForKey(key: String): TestableItem? {
val nKey = key.replace("customcrafting:", "", ignoreCase = true) val nKey = key.replace("customcrafting:", "", ignoreCase = true)
@@ -27,7 +32,9 @@ class CustomItemsCustomCrafting: CustomItemsWrapper {
return CustomItem( return CustomItem(
namespacedKey, namespacedKey,
Predicate { test: ItemStack -> Predicate { test: ItemStack ->
val customStack = me.wolfyscript.utilities.api.inventory.custom_items.CustomItem.getByItemStack(test) ?: return@Predicate false val customStack =
me.wolfyscript.utilities.api.inventory.custom_items.CustomItem.getByItemStack(test)
?: return@Predicate false
val iKey = customStack.namespacedKey ?: return@Predicate false val iKey = customStack.namespacedKey ?: return@Predicate false
iKey.equals(key) iKey.equals(key)
}, },

View File

@@ -0,0 +1,18 @@
package com.willfp.eco.internal.spigot.integrations.customrecipes
import com.willfp.eco.core.integrations.Integration
import com.willfp.eco.internal.spigot.recipes.GenericCraftEvent
import com.willfp.eco.internal.spigot.recipes.RecipeValidator
import me.wolfyscript.customcrafting.CustomCrafting
import org.bukkit.entity.Player
class CustomRecipeCustomCrafting : RecipeValidator, Integration {
override fun validate(event: GenericCraftEvent): Boolean {
val player = event.inventory.viewers.getOrNull(0) as? Player ?: return false
return CustomCrafting.inst().craftManager.has(player.uniqueId)
}
override fun getPluginName(): String {
return "CustomCrafting"
}
}

View File

@@ -0,0 +1,64 @@
package com.willfp.eco.internal.spigot.recipes
import com.willfp.eco.core.recipe.recipes.CraftingRecipe
import org.bukkit.Keyed
import org.bukkit.Material
import org.bukkit.event.Event
import org.bukkit.event.inventory.CraftItemEvent
import org.bukkit.event.inventory.PrepareItemCraftEvent
import org.bukkit.inventory.CraftingInventory
import org.bukkit.inventory.ItemStack
interface RecipeValidator {
fun validate(event: GenericCraftEvent): Boolean
}
interface RecipeListener {
fun handle(event: GenericCraftEvent)
}
interface GenericCraftEvent {
val inventory: CraftingInventory
val recipe: Keyed
fun allow(recipe: CraftingRecipe)
fun deny()
}
class WrappedPrepareItemCraftEvent(
private val event: PrepareItemCraftEvent
) : GenericCraftEvent {
override val inventory: CraftingInventory
get() = event.inventory
override val recipe: Keyed
get() = event.recipe as Keyed
override fun allow(recipe: CraftingRecipe) {
this.inventory.result = recipe.output
}
override fun deny() {
this.inventory.result = ItemStack(Material.AIR)
}
}
class WrappedCraftItemEvent(
private val event: CraftItemEvent
) : GenericCraftEvent {
override val inventory: CraftingInventory
get() = event.inventory
override val recipe: Keyed
get() = event.recipe as Keyed
override fun allow(recipe: CraftingRecipe) {
this.inventory.result = recipe.output
}
override fun deny() {
this.inventory.result = ItemStack(Material.AIR)
event.result = Event.Result.DENY
event.isCancelled = true
}
}

View File

@@ -0,0 +1,138 @@
package com.willfp.eco.internal.spigot.recipes
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.recipe.Recipes
import com.willfp.eco.core.recipe.parts.TestableStack
import org.bukkit.Keyed
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.inventory.CraftItemEvent
import org.bukkit.event.inventory.PrepareItemCraftEvent
import org.bukkit.event.player.PlayerRecipeDiscoverEvent
import org.bukkit.inventory.ShapedRecipe
class ShapedRecipeListener : Listener {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
fun stackedRecipeListener(event: CraftItemEvent) {
val recipe = event.recipe as? ShapedRecipe ?: return
if (!EcoPlugin.getPluginNames().contains(recipe.key.namespace)) {
return
}
val matrix = event.inventory.matrix
val wrapped = WrappedCraftItemEvent(event)
if (validators.any { it.validate(wrapped) }) {
return
}
val matched = Recipes.getMatch(matrix)
if (matched == null) {
wrapped.deny()
return
}
var isStackedRecipe = false
var upperBound = 64
for (i in 0..8) {
val inMatrix = event.inventory.matrix.getOrNull(i)
val inRecipe = matched.parts[i]
if (inRecipe is TestableStack) {
val max = Math.floorDiv(inMatrix!!.amount, inRecipe.amount)
if (max < upperBound) {
upperBound = max
}
isStackedRecipe = true
} else if (inMatrix != null) {
val max = inMatrix.amount
if (max < upperBound) {
upperBound = max
}
}
}
if (!isStackedRecipe) {
return
}
val toGivePerRecipe = event.recipe.result.amount
val maxStackSize = event.recipe.result.maxStackSize
while (toGivePerRecipe * upperBound > maxStackSize) {
upperBound--
}
for (i in 0..8) {
val inMatrix = event.inventory.matrix[i]
val inRecipe = matched.parts[i]
if (inRecipe is TestableStack) {
if (event.isShiftClick) {
var amount = inMatrix.amount + 1
for (j in 0..upperBound) {
amount -= inRecipe.amount
}
inMatrix.amount = amount
} else {
inMatrix.amount = inMatrix.amount - (inRecipe.amount - 1)
}
}
}
if (event.isShiftClick) {
val result = event.inventory.result ?: return
result.amount = result.amount * upperBound
event.inventory.result = result
}
}
@EventHandler
fun preventLearningDisplayedRecipes(event: PlayerRecipeDiscoverEvent) {
if (!EcoPlugin.getPluginNames().contains(event.recipe.namespace)) {
return
}
if (event.recipe.key.contains("_displayed")) {
event.isCancelled = true
}
}
@EventHandler
fun processListeners(event: PrepareItemCraftEvent) {
if (event.recipe !is Keyed) {
return
}
for (listener in listeners) {
listener.handle(WrappedPrepareItemCraftEvent(event))
}
}
@EventHandler
fun processListeners(event: CraftItemEvent) {
if (event.recipe !is Keyed) {
return
}
for (listener in listeners) {
listener.handle(WrappedCraftItemEvent(event))
}
}
companion object {
val validators = mutableListOf<RecipeValidator>()
private val listeners = mutableListOf<RecipeListener>()
fun registerValidator(validator: RecipeValidator) {
validators.add(validator)
}
fun registerListener(listener: RecipeListener) {
listeners.add(listener)
}
}
}

View File

@@ -0,0 +1,47 @@
package com.willfp.eco.internal.spigot.recipes.listeners
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.recipe.Recipes
import com.willfp.eco.internal.spigot.recipes.GenericCraftEvent
import com.willfp.eco.internal.spigot.recipes.RecipeListener
import com.willfp.eco.internal.spigot.recipes.ShapedRecipeListener
import org.bukkit.entity.Player
class ComplexInComplex : RecipeListener {
override fun handle(event: GenericCraftEvent) {
val recipe = event.recipe
if (!EcoPlugin.getPluginNames().contains(recipe.key.namespace)) {
return
}
val player = event.inventory.viewers.getOrNull(0) as? Player ?: return
val matrix = event.inventory.matrix
if (ShapedRecipeListener.validators.any { it.validate(event) }) {
return
}
val matched = Recipes.getMatch(matrix)
if (matched == null) {
event.deny()
return
}
if (matched.test(matrix)) {
if (matched.permission != null) {
if (player.hasPermission(matched.permission!!)) {
event.allow(matched)
} else {
event.deny()
}
} else {
event.allow(matched)
}
} else {
event.deny()
}
}
}

View File

@@ -0,0 +1,51 @@
package com.willfp.eco.internal.spigot.recipes.listeners
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.recipe.Recipes
import com.willfp.eco.core.recipe.parts.MaterialTestableItem
import com.willfp.eco.core.recipe.parts.ModifiedTestableItem
import com.willfp.eco.core.recipe.parts.TestableStack
import com.willfp.eco.core.recipe.recipes.ShapedCraftingRecipe
import com.willfp.eco.internal.spigot.recipes.GenericCraftEvent
import com.willfp.eco.internal.spigot.recipes.RecipeListener
import com.willfp.eco.internal.spigot.recipes.ShapedRecipeListener
class ComplexInEco : RecipeListener {
override fun handle(event: GenericCraftEvent) {
val craftingRecipe = Recipes.getRecipe(event.recipe.key)
if (craftingRecipe !is ShapedCraftingRecipe) {
return
}
if (ShapedRecipeListener.validators.any { it.validate(event) }) {
return
}
for (i in 0..8) {
val itemStack = event.inventory.matrix[i]
val part = craftingRecipe.parts[i]
when (part) {
is MaterialTestableItem -> {
if (Items.isCustomItem(itemStack)) {
event.deny()
}
}
is ModifiedTestableItem -> {
if (part.handle is MaterialTestableItem) {
if (Items.isCustomItem(itemStack)) {
event.deny()
}
}
}
is TestableStack -> {
if (part.handle is MaterialTestableItem) {
if (Items.isCustomItem(itemStack)) {
event.deny()
}
}
}
}
}
}
}

View File

@@ -0,0 +1,25 @@
package com.willfp.eco.internal.spigot.recipes.listeners
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.items.Items
import com.willfp.eco.internal.spigot.recipes.GenericCraftEvent
import com.willfp.eco.internal.spigot.recipes.RecipeListener
import com.willfp.eco.internal.spigot.recipes.ShapedRecipeListener
class ComplexInVanilla : RecipeListener {
override fun handle(event: GenericCraftEvent) {
if (EcoPlugin.getPluginNames().contains(event.recipe.key.namespace)) {
return
}
if (ShapedRecipeListener.validators.any { it.validate(event) }) {
return
}
for (itemStack in event.inventory.matrix) {
if (Items.isCustomItem(itemStack)) {
event.deny()
}
}
}
}

View File

@@ -41,11 +41,6 @@ use-display-frame: true
# that display frames will be cleared / deleted. # that display frames will be cleared / deleted.
display-frame-ttl: 17 display-frame-ttl: 17
# Time to live for storing hashes against custom item keys. Increasing this value
# can benefit performance under load (e.g. from ShopGUI+ sells) but can increase
# memory use.
item-cache-ttl: 6000
# The default bukkit NamespacedKey creation can cause decent amounts of lag under # The default bukkit NamespacedKey creation can cause decent amounts of lag under
# load due to the use of regex validation in the constructor. eco has its own system # load due to the use of regex validation in the constructor. eco has its own system
# to create NamespacedKeys, however it can be unsafe as it skips most validation checks. # to create NamespacedKeys, however it can be unsafe as it skips most validation checks.

View File

@@ -42,6 +42,7 @@ softdepend:
- MythicMobs - MythicMobs
- CustomCrafting - CustomCrafting
- ExecutableItems - ExecutableItems
- RPGHorses
libraries: libraries:
- 'org.reflections:reflections:0.9.12' - 'org.reflections:reflections:0.9.12'
- 'org.apache.maven:maven-artifact:3.0.3' - 'org.apache.maven:maven-artifact:3.0.3'
@@ -56,5 +57,5 @@ libraries:
- 'mysql:mysql-connector-java:8.0.25' - 'mysql:mysql-connector-java:8.0.25'
- 'com.google.guava:guava:31.0.1-jre' - 'com.google.guava:guava:31.0.1-jre'
- 'com.zaxxer:HikariCP:5.0.0' - 'com.zaxxer:HikariCP:5.0.0'
- 'org.apache.commons:commons-lang3:3.0' - 'org.objenesis:objenesis:3.2'
- 'org.objenesis:objenesis:3.2' - 'com.github.ben-manes.caffeine:caffeine:3.0.5'

View File

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

BIN
lib/RPGHorses.jar Normal file

Binary file not shown.

Binary file not shown.