Compare commits

..

58 Commits

Author SHA1 Message Date
Auxilor
08c14f4def Cleaned up BentoBox 2021-11-02 19:28:19 +00:00
Auxilor
0fa6f972c0 Fixed BentoBox 2021-11-02 19:26:34 +00:00
Auxilor
8837fecfa0 Added support for BentoBox 2021-11-02 19:24:34 +00:00
Auxilor
af1841770e (Hopefully) fixed HologramCMI 2021-11-02 18:54:21 +00:00
Auxilor
1d85dbf08d Altered rate limit settings 2021-11-02 18:52:57 +00:00
Auxilor
ba9812534a Increased timeframe to 2 2021-11-02 18:46:28 +00:00
Auxilor
1f95a33385 Added log errors option for async display 2021-11-02 18:39:29 +00:00
Auxilor
bc652a8154 MySQLDataHandler changes 2021-11-02 18:37:01 +00:00
Auxilor
0c2e1f0cae Fixed ServerUtils 2021-11-02 18:29:17 +00:00
Auxilor
39d6eb7f9a Updated to 6.13.0 2021-11-02 18:17:57 +00:00
Auxilor
61bae6de55 Rearranged config.yml 2021-11-02 18:17:40 +00:00
Auxilor
aa4ac4c6d1 Added option to set rate limit timeframe 2021-11-02 17:44:57 +00:00
Auxilor
7141b12e95 Removed redundant explicit type 2021-11-02 17:42:27 +00:00
Auxilor
2382548629 Added in rate limiting for PacketWindowItems.kt 2021-11-02 17:39:41 +00:00
Auxilor
0c4bd182f7 Ignored async exceptions in PacketWindowItems.kt 2021-11-02 17:09:48 +00:00
Auxilor
e90e053b45 Added emergency async display and ServerUtils 2021-11-02 16:50:04 +00:00
Auxilor
742c1abb00 Cleaned up async display 2021-11-02 14:10:57 +00:00
Auxilor
c0686ca386 Added guava and asynchronous window items processing 2021-11-02 13:53:30 +00:00
Auxilor
db2ea7daa9 Updated to 6.12.2 2021-11-02 09:24:23 +00:00
Auxilor
ed4f0b2ab6 Fixed EconomyManager and ListUtils 2021-11-02 09:24:16 +00:00
Auxilor
6decc68d1b Updated to 6.12.1 2021-11-02 08:30:39 +00:00
Auxilor
1e061313a4 Codestyle 2021-11-02 08:30:27 +00:00
Auxilor
4762004e94 @NotNull'ed PlayerProfile#read 2021-11-02 08:29:00 +00:00
Auxilor
0d9889ef43 Fixed paste calling the callback three times 2021-11-01 21:14:56 +00:00
Auxilor
b2a23e80a1 Added missing nullable annotation 2021-11-01 21:06:50 +00:00
Auxilor
0e439db7b3 Auto-registered PersistentDataKeys 2021-11-01 21:01:57 +00:00
Auxilor
f615006b23 Added missing PlayerProfile javadoc 2021-11-01 21:00:58 +00:00
Auxilor
d952dbc61b Added ListUtils#listToFrequencyMap 2021-11-01 20:00:46 +00:00
Auxilor
d95a96f4c6 Added in support for economy via vault 2021-11-01 19:55:47 +00:00
Auxilor
33940f5778 Improved MySQLDataHandler.kt 2021-11-01 19:38:30 +00:00
Auxilor
173d04595f Removed duplicate uuid field from Players table 2021-11-01 19:04:16 +00:00
Auxilor
c7c4ca3777 Updated plugin.yml 2021-11-01 19:02:40 +00:00
Auxilor
cbf7316db9 Fixed public static variable in display 2021-11-01 18:55:01 +00:00
Auxilor
601cadd582 Fixed weird IntelliJ bug 2021-11-01 18:54:25 +00:00
Auxilor
877647db03 Fixed various codestyle issues 2021-11-01 18:53:36 +00:00
Auxilor
81196bb132 Added PotionUtils 2021-11-01 18:44:44 +00:00
Auxilor
ef701f1f86 Added BlockUtils#isPlayerPlaced 2021-11-01 18:38:58 +00:00
Auxilor
58d8f72cf5 Fixed javadoc 2021-11-01 16:21:44 +00:00
Auxilor
3abf916f18 Fixed SuperiorSkyblock2 integration 2021-11-01 16:18:31 +00:00
Auxilor
b459a746e3 Merge branch 'master' into develop
# Conflicts:
#	eco-core/core-plugin/build.gradle
2021-11-01 16:15:00 +00:00
Will FP
30c37078a2 Merge pull request #47
Added SuperiorSkyblock2 Antigrief integration
2021-11-01 16:14:35 +00:00
Auxilor
36ccfb5fc6 Fixed McmmoIntegrationImpl.kt 2021-11-01 16:13:51 +00:00
Auxilor
c84f1a060a Fixed KingdomsX version 2021-11-01 16:12:23 +00:00
Auxilor
d8d5609f6b Renamed consumer to callback 2021-11-01 16:09:23 +00:00
Auxilor
462abd46c6 Marked Handler as internal 2021-11-01 16:07:14 +00:00
Auxilor
e89008cf97 Fixed SkullUtils#getSkullTexture 2021-11-01 16:00:38 +00:00
Auxilor
d34e43797d Registering a duplicate key will now replace the existing key 2021-11-01 15:51:22 +00:00
Auxilor
63ee83c795 Added Essentials / CMI AFK integrations 2021-11-01 15:50:10 +00:00
Auxilor
2eec17698e Updated paste 2021-11-01 15:34:02 +00:00
Auxilor
ad52c2a086 Improved EcoPlayerProfileHandler.kt 2021-11-01 15:31:10 +00:00
Auxilor
6e482cccda Registered player name key 2021-11-01 15:24:11 +00:00
Auxilor
899b4297f7 Added saved display name utils with persistent meta 2021-11-01 14:17:29 +00:00
Auxilor
ceb95e20b5 Added in hologram integrations for CMI/GHolo/HolographicDisplays 2021-11-01 14:09:41 +00:00
Auxilor
bdfeb9a0ab Updated to 6.12.0 2021-11-01 13:29:03 +00:00
Auxilor
e0707e2afa Added missing handler implementations 2021-11-01 13:28:51 +00:00
Auxilor
e8048f5a0a Added in persistent data storage 2021-11-01 13:25:14 +00:00
0ft3n
a36018e31a Merge branch 'Auxilor:master' into master 2021-10-27 22:45:29 +03:00
_OfTeN_
a34c63161d Added SuperiorSkyblock2 Antigrief integration 2021-10-27 22:44:45 +03:00
77 changed files with 1857 additions and 148 deletions

View File

@@ -157,7 +157,7 @@ Here's a list of some (not all) of the features of eco:
<h1 align="center"> <h1 align="center">
<br> <br>
<a href="http://gamersupps.gg/discount/Auxilor?afmc=Auxilor" target="_blank"> <a href="https://gamersupps.gg/discount/Auxilor?afmc=Auxilor" target="_blank">
<img src="https://i.imgur.com/uFDpBAC.png" alt="supps banner"> <img src="https://i.imgur.com/uFDpBAC.png" alt="supps banner">
</a> </a>
<a href="https://dedimc.promo/Auxilor" target="_blank"> <a href="https://dedimc.promo/Auxilor" target="_blank">

View File

@@ -25,11 +25,14 @@ allprojects {
mavenLocal() mavenLocal()
maven { url 'https://jitpack.io' } maven { url 'https://jitpack.io' }
// SuperiorSkyblock2
maven { url 'https://repo.bg-software.com/repository/api/' }
// NMS (for jitpack compilation) // NMS (for jitpack compilation)
maven { url 'https://repo.codemc.org/repository/nms/' } maven { url 'https://repo.codemc.org/repository/nms/' }
// bStats, mcMMO // bStats, mcMMO, BentoBox
maven { url 'https://repo.codemc.org/repository/maven-public' } maven { url 'https://repo.codemc.org/repository/maven-public/' }
// Spigot API // Spigot API
maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' } maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }

View File

@@ -9,15 +9,15 @@ dependencies {
// Adventure // Adventure
compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0' compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0'
compileOnly 'net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT' compileOnly 'net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT'
compileOnly 'net.kyori:adventure-api:4.9.1' compileOnly 'net.kyori:adventure-api:4.9.2'
compileOnly 'net.kyori:adventure-text-serializer-gson:4.9.2' compileOnly 'net.kyori:adventure-text-serializer-gson:4.9.2'
compileOnly 'net.kyori:adventure-text-serializer-legacy:4.8.1' compileOnly 'net.kyori:adventure-text-serializer-legacy:4.9.2'
// Other // Other
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT' compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
compileOnly 'org.apache.maven:maven-artifact:3.0.3' compileOnly 'org.apache.maven:maven-artifact:3.8.1'
compileOnly 'com.comphenix.protocol:ProtocolLib:4.7.1-SNAPSHOT' compileOnly 'com.comphenix.protocol:ProtocolLib:4.7.1-SNAPSHOT'
compileOnly 'com.google.code.gson:gson:2.8.7' compileOnly 'com.google.code.gson:gson:2.8.8'
} }
java { java {

View File

@@ -1,6 +1,5 @@
package com.willfp.eco.core; package com.willfp.eco.core;
import lombok.Getter;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
@@ -15,20 +14,12 @@ import org.jetbrains.annotations.NotNull;
public class Eco { public class Eco {
/** /**
* Instance of eco handler. * Instance of eco handler.
* <p>
* The handler is, in essence, a way to interface between the eco-api
* frontend module, and the eco-backend implementations.
* <p>
* There shouldn't really be any reason to ever use the handler
* in your own plugins, but if you want to then you can - it's
* just a part of the API like any other.
*/ */
@Getter @ApiStatus.Internal
private Handler handler; private Handler handler;
/** /**
* Set the handler. * Set the handler.
*
* @param handler The handler. * @param handler The handler.
*/ */
@ApiStatus.Internal @ApiStatus.Internal
@@ -37,4 +28,25 @@ public class Eco {
Eco.handler = handler; Eco.handler = handler;
} }
/**
* Get the instance of the eco handler.
* <p>
* The handler is, in essence, a way to interface between the eco-api
* frontend module, and the eco-backend implementations.
* <p>
* There shouldn't really be any reason to ever use the handler
* in your own plugins, and you are likely to break things. All parts of
* the handler are abstracted into logically named parts of the API.
* <p>
* In versions of eco before 6.12.0, the handler was considered part of
* the eco API, however it has since been moved into an internal component
* that shouldn't be used in your plugins.
*
* @return The handler.
*/
@ApiStatus.Internal
public Handler getHandler() {
return handler;
}
} }

View File

@@ -2,6 +2,8 @@ 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.keys.KeyRegistry;
import com.willfp.eco.core.data.PlayerProfileHandler;
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;
import com.willfp.eco.core.extensions.ExtensionLoader; import com.willfp.eco.core.extensions.ExtensionLoader;
@@ -17,6 +19,7 @@ import com.willfp.eco.core.requirement.RequirementFactory;
import com.willfp.eco.core.scheduling.Scheduler; import com.willfp.eco.core.scheduling.Scheduler;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
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;
@@ -24,8 +27,9 @@ import java.util.List;
import java.util.logging.Logger; import java.util.logging.Logger;
/** /**
* @see Eco * @see Eco#getHandler()
*/ */
@ApiStatus.Internal
public interface Handler { public interface Handler {
/** /**
* Create a scheduler. * Create a scheduler.
@@ -212,4 +216,19 @@ public interface Handler {
*/ */
@Nullable @Nullable
BukkitAudiences getAdventure(); BukkitAudiences getAdventure();
/**
* Get the key registry.
*
* @return The registry.
*/
@NotNull
KeyRegistry getKeyRegistry();
/**
* Get the PlayerProfile handler.
*
* @return The handler.
*/
PlayerProfileHandler getPlayerProfileHandler();
} }

View File

@@ -9,7 +9,7 @@ import org.jetbrains.annotations.NotNull;
* *
* @param <T> The eco plugin type. * @param <T> The eco plugin type.
*/ */
public abstract class PluginDependent<@NotNull T extends EcoPlugin> { public abstract class PluginDependent<T extends EcoPlugin> {
/** /**
* The {@link EcoPlugin} that is stored. * The {@link EcoPlugin} that is stored.
*/ */

View File

@@ -34,7 +34,7 @@ public interface LoadableConfig {
File getConfigFile(); File getConfigFile();
/** /**
* Get the config name (including extension) * Get the config name (including extension).
* *
* @return The name. * @return The name.
*/ */

View File

@@ -75,4 +75,4 @@ public abstract class JSONBaseConfig extends LoadableJSONConfigWrapper {
@NotNull final EcoPlugin plugin) { @NotNull final EcoPlugin plugin) {
this(configName, removeUnused, (PluginLike) plugin); this(configName, removeUnused, (PluginLike) plugin);
} }
} }

View File

@@ -0,0 +1,56 @@
package com.willfp.eco.core.data;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
/**
* Persistent data storage interface for players.
* <p>
* Profiles save automatically, so there is no need to save after changes.
*/
public interface PlayerProfile {
/**
* 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.
*
* @param player The player.
* @return The profile.
*/
@NotNull
static PlayerProfile load(@NotNull final OfflinePlayer player) {
return load(player.getUniqueId());
}
/**
* Load a player profile.
*
* @param uuid The player's UUID.
* @return The profile.
*/
@NotNull
static PlayerProfile load(@NotNull final UUID uuid) {
return Eco.getHandler().getPlayerProfileHandler().load(uuid);
}
}

View File

@@ -0,0 +1,32 @@
package com.willfp.eco.core.data;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
/**
* API to handle player profiles.
*/
public interface PlayerProfileHandler {
/**
* Load a player profile.
*
* @param uuid The UUID.
* @return The profile.
*/
PlayerProfile load(@NotNull UUID uuid);
/**
* Save a player profile.
*
* @param uuid The uuid.
*/
void savePlayer(@NotNull UUID uuid);
/**
* Save all player data.
*
* @param async If the saving should be done asynchronously.
*/
void saveAll(boolean async);
}

View File

@@ -0,0 +1,24 @@
package com.willfp.eco.core.data.keys;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
/**
* API to register persistent data keys.
*/
public interface KeyRegistry {
/**
* Register a persistent data key to be stored.
*
* @param key The key.
*/
void registerKey(@NotNull PersistentDataKey<?> key);
/**
* Get all registered keys.
*
* @return The keys.
*/
Set<PersistentDataKey<?>> getRegisteredKeys();
}

View File

@@ -0,0 +1,57 @@
package com.willfp.eco.core.data.keys;
import com.willfp.eco.core.Eco;
import lombok.Getter;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull;
/**
* A persistent data key is a key with a type that can be stored about an offline player.
*
* @param <T> The type of the data.
*/
public class PersistentDataKey<T> {
/**
* The key of the persistent data value.
*/
@Getter
private final NamespacedKey key;
/**
* The default value for the key.
*/
@Getter
private final T defaultValue;
/**
* The persistent data key type.
*/
@Getter
private final PersistentDataKeyType type;
/**
* Create a new Persistent Data Key.
*
* @param key The key.
* @param type The data type.
* @param defaultValue The default value.
*/
public PersistentDataKey(@NotNull final NamespacedKey key,
@NotNull final PersistentDataKeyType type,
@NotNull final T defaultValue) {
this.key = key;
this.defaultValue = defaultValue;
this.type = type;
Eco.getHandler().getKeyRegistry().registerKey(this);
}
@Override
public String toString() {
return "PersistentDataKey{"
+ "key=" + key
+ ", defaultValue=" + defaultValue
+ ", type=" + type
+ '}';
}
}

View File

@@ -0,0 +1,26 @@
package com.willfp.eco.core.data.keys;
/**
* All storable data key types.
*/
public enum PersistentDataKeyType {
/**
* String.
*/
STRING,
/**
* Boolean.
*/
BOOLEAN,
/**
* Integer.
*/
INT,
/**
* Double.
*/
DOUBLE
}

View File

@@ -20,7 +20,7 @@ public class Display {
/** /**
* The display handler. * The display handler.
*/ */
public static DisplayHandler handler = null; private static DisplayHandler handler = null;
/** /**
* Display on ItemStacks. * Display on ItemStacks.
@@ -160,4 +160,20 @@ public class Display {
module.display(itemStack, player, args); module.display(itemStack, player, args);
} }
} }
/**
* Set the display handler.
* <p>
* Internal API component, you will cause bugs if you create your own handler.
*
* @param handler The handler.
*/
@ApiStatus.Internal
public static void setHandler(@NotNull final DisplayHandler handler) {
if (Display.handler != null) {
throw new IllegalStateException("Display already initialized!");
}
Display.handler = handler;
}
} }

View File

@@ -23,8 +23,8 @@ public interface DisplayHandler {
* @param player The player. * @param player The player.
* @return The ItemStack. * @return The ItemStack.
*/ */
ItemStack display(@NotNull final ItemStack itemStack, ItemStack display(@NotNull ItemStack itemStack,
@Nullable final Player player); @Nullable Player player);
/** /**
* Revert on ItemStacks. * Revert on ItemStacks.
@@ -32,7 +32,7 @@ public interface DisplayHandler {
* @param itemStack The item. * @param itemStack The item.
* @return The ItemStack. * @return The ItemStack.
*/ */
ItemStack revert(@NotNull final ItemStack itemStack); ItemStack revert(@NotNull ItemStack itemStack);
/** /**
* Finalize an ItemStacks. * Finalize an ItemStacks.
@@ -40,7 +40,7 @@ public interface DisplayHandler {
* @param itemStack The item. * @param itemStack The item.
* @return The ItemStack. * @return The ItemStack.
*/ */
ItemStack finalize(@NotNull final ItemStack itemStack); ItemStack finalize(@NotNull ItemStack itemStack);
/** /**
* Unfinalize an ItemStacks. * Unfinalize an ItemStacks.
@@ -48,7 +48,7 @@ public interface DisplayHandler {
* @param itemStack The item. * @param itemStack The item.
* @return The ItemStack. * @return The ItemStack.
*/ */
ItemStack unfinalize(@NotNull final ItemStack itemStack); ItemStack unfinalize(@NotNull ItemStack itemStack);
/** /**
* If an item is finalized. * If an item is finalized.
@@ -56,5 +56,5 @@ public interface DisplayHandler {
* @param itemStack The item. * @param itemStack The item.
* @return If finalized. * @return If finalized.
*/ */
boolean isFinalized(@NotNull final ItemStack itemStack); boolean isFinalized(@NotNull ItemStack itemStack);
} }

View File

@@ -107,7 +107,7 @@ public interface FastItemStack {
* @param itemStack The ItemStack. * @param itemStack The ItemStack.
* @return The FastItemStack. * @return The FastItemStack.
*/ */
static FastItemStack wrap(final ItemStack itemStack) { static FastItemStack wrap(@Nullable final ItemStack itemStack) {
return Eco.getHandler().createFastItemStack(Objects.requireNonNullElseGet(itemStack, () -> new ItemStack(Material.AIR))); return Eco.getHandler().createFastItemStack(Objects.requireNonNullElseGet(itemStack, () -> new ItemStack(Material.AIR)));
} }
} }

View File

@@ -0,0 +1,44 @@
package com.willfp.eco.core.integrations.afk;
import lombok.experimental.UtilityClass;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
/**
* Class to handle afk integrations.
*/
@UtilityClass
public class AFKManager {
/**
* A set of all registered integrations.
*/
private final Set<AFKWrapper> registered = new HashSet<>();
/**
* Register a new integration.
*
* @param integration The integration to register.
*/
public void register(@NotNull final AFKWrapper integration) {
registered.add(integration);
}
/**
* Get if a player is afk.
*
* @param player The player.
* @return If afk.
*/
public boolean isAfk(@NotNull final Player player) {
for (AFKWrapper afkWrapper : registered) {
if (afkWrapper.isAfk(player)) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,18 @@
package com.willfp.eco.core.integrations.afk;
import com.willfp.eco.core.integrations.Integration;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* Wrapper class for afk integrations.
*/
public interface AFKWrapper extends Integration {
/**
* Get if a player is afk.
*
* @param player The player.
* @return If afk.
*/
boolean isAfk(@NotNull Player player);
}

View File

@@ -0,0 +1,99 @@
package com.willfp.eco.core.integrations.economy;
import lombok.experimental.UtilityClass;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
/**
* Class to handle economy.
*/
@UtilityClass
public class EconomyManager {
/**
* A set of all registered integrations.
*/
private final Set<EconomyWrapper> registered = new HashSet<>();
/**
* Register a new integration.
*
* @param integration The integration to register.
*/
public void register(@NotNull final EconomyWrapper integration) {
registered.add(integration);
}
/**
* Get if any economy registrations are registered.
*
* @return If any economy.
*/
public boolean hasRegistrations() {
return !registered.isEmpty();
}
/**
* Get if a player has a certain amount.
*
* @param player The player.
* @param amount The amount.
* @return If the player has the amount.
*/
public boolean hasAmount(@NotNull final OfflinePlayer player,
final double amount) {
for (EconomyWrapper wrapper : registered) {
return wrapper.hasAmount(player, amount);
}
return false;
}
/**
* Give money to a player.
*
* @param player The player.
* @param amount The amount to give.
* @return If the transaction was a success.
*/
public boolean giveMoney(@NotNull final OfflinePlayer player,
final double amount) {
for (EconomyWrapper wrapper : registered) {
return wrapper.giveMoney(player, amount);
}
return false;
}
/**
* Remove money from a player.
*
* @param player The player.
* @param amount The amount to remove.
* @return If the transaction was a success.
*/
public boolean removeMoney(@NotNull final OfflinePlayer player,
final double amount) {
for (EconomyWrapper wrapper : registered) {
return wrapper.removeMoney(player, amount);
}
return false;
}
/**
* Get the balance of a player.
*
* @param player The player.
* @return The balance.
*/
public double getBalance(@NotNull final OfflinePlayer player) {
for (EconomyWrapper wrapper : registered) {
return wrapper.getBalance(player);
}
return 0;
}
}

View File

@@ -0,0 +1,48 @@
package com.willfp.eco.core.integrations.economy;
import com.willfp.eco.core.integrations.Integration;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
/**
* Wrapper class for economy integrations.
*/
public interface EconomyWrapper extends Integration {
/**
* Get if a player has a certain amount.
*
* @param player The player.
* @param amount The amount.
* @return If the player has the amount.
*/
boolean hasAmount(@NotNull OfflinePlayer player,
double amount);
/**
* Give money to a player.
*
* @param player The player.
* @param amount The amount to give.
* @return If the transaction was a success.
*/
boolean giveMoney(@NotNull OfflinePlayer player,
double amount);
/**
* Remove money from a player.
*
* @param player The player.
* @param amount The amount to remove.
* @return If the transaction was a success.
*/
boolean removeMoney(@NotNull OfflinePlayer player,
double amount);
/**
* Get the balance of a player.
*
* @param player The player.
* @return The balance.
*/
double getBalance(@NotNull OfflinePlayer player);
}

View File

@@ -0,0 +1,20 @@
package com.willfp.eco.core.integrations.hologram;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Dummy hologram, created if no integrations are present on the server.
*/
class DummyHologram implements Hologram {
@Override
public void remove() {
// Do nothing.
}
@Override
public void setContents(@NotNull final List<String> contents) {
// Do nothing.
}
}

View File

@@ -0,0 +1,22 @@
package com.willfp.eco.core.integrations.hologram;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Wrapper class for plugin-specific holograms.
*/
public interface Hologram {
/**
* Remove the hologram.
*/
void remove();
/**
* Set the hologram contents.
*
* @param contents The contents.
*/
void setContents(@NotNull List<String> contents);
}

View File

@@ -0,0 +1,45 @@
package com.willfp.eco.core.integrations.hologram;
import lombok.experimental.UtilityClass;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Class to handle hologram integrations.
*/
@UtilityClass
public class HologramManager {
/**
* A set of all registered integrations.
*/
private final Set<HologramWrapper> registered = new HashSet<>();
/**
* Register a new integration.
*
* @param integration The integration to register.
*/
public void register(@NotNull final HologramWrapper integration) {
registered.add(integration);
}
/**
* Create hologram.
*
* @param location The location.
* @param contents The contents for the hologram.
* @return The hologram.
*/
public Hologram createHologram(@NotNull final Location location,
@NotNull final List<String> contents) {
for (HologramWrapper wrapper : registered) {
return wrapper.createHologram(location, contents);
}
return new DummyHologram();
}
}

View File

@@ -0,0 +1,22 @@
package com.willfp.eco.core.integrations.hologram;
import com.willfp.eco.core.integrations.Integration;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* Wrapper class for hologram integrations.
*/
public interface HologramWrapper extends Integration {
/**
* Create hologram.
*
* @param location The location.
* @param contents The contents for the hologram.
* @return The hologram.
*/
Hologram createHologram(@NotNull Location location,
@NotNull List<String> contents);
}

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.core.integrations.mcmmo; package com.willfp.eco.core.integrations.mcmmo;
import com.willfp.eco.core.integrations.Integration;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -7,7 +8,7 @@ import org.jetbrains.annotations.NotNull;
/** /**
* Wrapper class for mcmmo integrations. * Wrapper class for mcmmo integrations.
*/ */
public interface McmmoWrapper { public interface McmmoWrapper extends Integration {
/** /**
* Get bonus drop count of block. * Get bonus drop count of block.
* *

View File

@@ -8,9 +8,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
/** /**
* Class to handle placeholder integrations. * Class to handle placeholder integrations.

View File

@@ -2,7 +2,6 @@ package com.willfp.eco.core.items;
import com.willfp.eco.core.Eco; import com.willfp.eco.core.Eco;
import lombok.Getter; import lombok.Getter;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@@ -12,7 +11,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate; import java.util.function.Predicate;
/** /**
* A custom item has 3 components: * A custom item has 3 components.
* *
* <ul> * <ul>
* <li>The key to identify it</li> * <li>The key to identify it</li>

View File

@@ -49,7 +49,7 @@ public class TextureArgParser implements LookupArgParser {
assert testMeta != null; assert testMeta != null;
if (testMeta instanceof SkullMeta skullMeta && finalSkullTexture != null) { if (testMeta instanceof SkullMeta skullMeta) {
return finalSkullTexture.equalsIgnoreCase(SkullUtils.getSkullTexture(skullMeta)); return finalSkullTexture.equalsIgnoreCase(SkullUtils.getSkullTexture(skullMeta));
} }

View File

@@ -36,5 +36,5 @@ public abstract class ItemProvider {
* @return The TestableItem, or null if not found. * @return The TestableItem, or null if not found.
*/ */
@Nullable @Nullable
public abstract TestableItem provideForKey(@NotNull final String key); public abstract TestableItem provideForKey(@NotNull String key);
} }

View File

@@ -2,7 +2,6 @@ package com.willfp.eco.core.recipe.parts;
import com.willfp.eco.core.items.TestableItem; import com.willfp.eco.core.items.TestableItem;
import lombok.Getter; import lombok.Getter;
import org.apache.commons.lang.Validate;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;

View File

@@ -4,6 +4,7 @@ import com.willfp.eco.core.Eco;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
@@ -11,7 +12,6 @@ import java.io.InputStreamReader;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -40,45 +40,42 @@ public class Paste {
* <p> * <p>
* Runs asynchronously to avoid hangups. * Runs asynchronously to avoid hangups.
* *
* @param responseHandler The consumer to accept the response token. * @param callback The consumer to accept the response token.
*/ */
public void getHastebinToken(@NotNull final Consumer<String> responseHandler) { public void getHastebinToken(@NotNull final Consumer<String> callback) {
Eco.getHandler().getEcoPlugin().getScheduler().runAsync(() -> { Eco.getHandler().getEcoPlugin().getScheduler().runAsync(() -> {
try { try {
String url = "https://hastebin.com/documents"; byte[] postData = contents.getBytes(StandardCharsets.UTF_8);
URL obj = new URL(url); int postDataLength = postData.length;
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST"); String requestURL = "https://hastebin.com/documents";
con.setRequestProperty("Content-Type", "application/json"); URL url = new URL(requestURL);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setInstanceFollowRedirects(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("User-Agent", "eco-Hastebin");
conn.setRequestProperty("Content-Length", Integer.toString(postDataLength));
conn.setUseCaches(false);
con.setDoOutput(true); String response;
DataOutputStream wr = new DataOutputStream(con.getOutputStream()); DataOutputStream wr;
wr.writeBytes(URLEncoder.encode(contents, StandardCharsets.UTF_8));
wr.flush();
wr.close();
BufferedReader iny = new BufferedReader( wr = new DataOutputStream(conn.getOutputStream());
new InputStreamReader(con.getInputStream())); wr.write(postData);
String output; BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder responseBuilder = new StringBuilder(); response = reader.readLine();
while ((output = iny.readLine()) != null) { assert response != null;
responseBuilder.append(output);
if (response.contains("\"key\"")) {
response = response.substring(response.indexOf(":") + 2, response.length() - 2);
callback.accept(response);
} }
iny.close();
String responseString = responseBuilder.toString();
responseString = responseString.replace("{\"key\":\"", "");
responseString = responseString.replace("\"}", "");
responseHandler.accept(responseString);
} catch (IOException e) { } catch (IOException e) {
responseHandler.accept(e.getMessage()); callback.accept(e.getMessage());
} }
responseHandler.accept("");
}); });
} }
@@ -96,7 +93,7 @@ public class Paste {
conn.setRequestMethod("GET"); conn.setRequestMethod("GET");
try (var reader = new BufferedReader( try (var reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) { new InputStreamReader(conn.getInputStream()))) {
for (String line; (line = reader.readLine()) != null; ) { for (String line; (line = reader.readLine()) != null;) {
result.append(line); result.append(line);
} }
} }

View File

@@ -26,9 +26,9 @@ public class UpdateChecker extends PluginDependent<EcoPlugin> {
/** /**
* Get the latest version of the plugin. * Get the latest version of the plugin.
* *
* @param consumer The process to run after checking. * @param callback The process to run after checking.
*/ */
public void getVersion(@NotNull final Consumer<? super String> consumer) { public void getVersion(@NotNull final Consumer<? super String> callback) {
this.getPlugin().getScheduler().runAsync(() -> { this.getPlugin().getScheduler().runAsync(() -> {
try { try {
InputStream inputStream = new URL( InputStream inputStream = new URL(
@@ -37,7 +37,7 @@ public class UpdateChecker extends PluginDependent<EcoPlugin> {
Scanner scanner = new Scanner(inputStream); Scanner scanner = new Scanner(inputStream);
if (scanner.hasNext()) { if (scanner.hasNext()) {
consumer.accept(scanner.next()); callback.accept(scanner.next());
} }
} catch (IOException e) { } catch (IOException e) {
this.getPlugin().getLogger().warning("Failed to check for updates: " + e.getMessage()); this.getPlugin().getLogger().warning("Failed to check for updates: " + e.getMessage());

View File

@@ -2,12 +2,14 @@ package com.willfp.eco.util;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -92,6 +94,21 @@ public class BlockUtils {
blockBreakConsumer.accept(player, block); blockBreakConsumer.accept(player, block);
} }
/**
* Get if a block was placed by a player.
*
* @param block The block.
* @return If placed by a player.
*/
public boolean isPlayerPlaced(@NotNull final Block block) {
Chunk chunk = block.getChunk();
return chunk.getPersistentDataContainer().has(
NamespacedKeyUtils.createEcoKey(Integer.toString(block.getLocation().hashCode(), 16)),
PersistentDataType.INTEGER
);
}
/** /**
* Initialize the block break function. * Initialize the block break function.
* *

View File

@@ -5,7 +5,9 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Utilities / API methods for lists. * Utilities / API methods for lists.
@@ -21,8 +23,8 @@ public class ListUtils {
* @return The list, filled will null objects. * @return The list, filled will null objects.
*/ */
@NotNull @NotNull
public <@Nullable T> List<List<T>> create2DList(final int rows, public static <@Nullable T> List<List<T>> create2DList(final int rows,
final int columns) { final int columns) {
List<List<T>> list = new ArrayList<>(rows); List<List<T>> list = new ArrayList<>(rows);
while (list.size() < rows) { while (list.size() < rows) {
List<T> row = new ArrayList<>(columns); List<T> row = new ArrayList<>(columns);
@@ -34,4 +36,25 @@ public class ListUtils {
return list; return list;
} }
/**
* Convert a list potentially containing duplicates to a map where the value is the frequency of the key.
*
* @param list The list.
* @param <T> The type parameter of the list.
* @return The frequency map.
*/
@NotNull
public static <T> Map<T, Integer> listToFrequencyMap(@NotNull final List<T> list) {
Map<T, Integer> frequencyMap = new HashMap<>();
for (T object : list) {
if (frequencyMap.containsKey(object)) {
frequencyMap.put(object, frequencyMap.get(object) + 1);
} else {
frequencyMap.put(object, 1);
}
}
return frequencyMap;
}
} }

View File

@@ -1,6 +1,5 @@
package com.willfp.eco.util; package com.willfp.eco.util;
import lombok.experimental.NonFinal;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

View File

@@ -2,9 +2,13 @@ package com.willfp.eco.util;
import com.willfp.eco.core.Eco; import com.willfp.eco.core.Eco;
import com.willfp.eco.core.Prerequisite; import com.willfp.eco.core.Prerequisite;
import com.willfp.eco.core.data.PlayerProfile;
import com.willfp.eco.core.data.keys.PersistentDataKey;
import com.willfp.eco.core.data.keys.PersistentDataKeyType;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import net.kyori.adventure.audience.Audience; import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -14,6 +18,15 @@ import org.jetbrains.annotations.NotNull;
*/ */
@UtilityClass @UtilityClass
public class PlayerUtils { public class PlayerUtils {
/**
* The data key for saved player names.
*/
private static final PersistentDataKey<String> PLAYER_NAME_KEY = new PersistentDataKey<>(
NamespacedKeyUtils.createEcoKey("player_name"),
PersistentDataKeyType.STRING,
"Unknown Player"
);
/** /**
* Get the audience from a player. * Get the audience from a player.
* *
@@ -63,4 +76,30 @@ public class PlayerUtils {
} }
} }
} }
/**
* Get saved display name for an offline player.
*
* @param player The player.
* @return The player name.
*/
public String getSavedDisplayName(@NotNull final OfflinePlayer player) {
PlayerProfile profile = PlayerProfile.load(player);
if (player instanceof Player onlinePlayer) {
profile.write(PLAYER_NAME_KEY, onlinePlayer.getDisplayName());
}
return profile.read(PLAYER_NAME_KEY);
}
/**
* Update the saved display name for a player.
*
* @param player The player.
*/
public void updateSavedDisplayName(@NotNull final Player player) {
PlayerProfile profile = PlayerProfile.load(player);
profile.write(PLAYER_NAME_KEY, player.getDisplayName());
}
} }

View File

@@ -0,0 +1,47 @@
package com.willfp.eco.util;
import lombok.experimental.UtilityClass;
import org.bukkit.potion.PotionData;
import org.jetbrains.annotations.NotNull;
/**
* Utilities / API methods for potions.
*/
@UtilityClass
public class PotionUtils {
/**
* Get the duration (in ticks) for potion data.
*
* @param data The data.
* @return The duration.
*/
public int getDuration(@NotNull final PotionData data) {
if (data.isExtended()) {
return switch (data.getType()) {
case INSTANT_DAMAGE, INSTANT_HEAL: yield 0;
case POISON, REGEN: yield 1800;
case SLOW_FALLING, WEAKNESS, SLOWNESS: yield 4800;
case TURTLE_MASTER: yield 800;
default: yield 9600;
};
}
if (data.isUpgraded()) {
return switch (data.getType()) {
case INSTANT_DAMAGE, INSTANT_HEAL: yield 0;
case POISON, REGEN: yield 420;
case SLOW_FALLING, WEAKNESS, SLOWNESS: yield 440;
case TURTLE_MASTER: yield 400;
default: yield 1800;
};
}
return switch (data.getType()) {
case INSTANT_DAMAGE, INSTANT_HEAL: yield 0;
case POISON, REGEN: yield 900;
case SLOW_FALLING, WEAKNESS, SLOWNESS: yield 400;
case TURTLE_MASTER: yield 1800;
default: yield 3600;
};
}
}

View File

@@ -0,0 +1,48 @@
package com.willfp.eco.util;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.function.Supplier;
/**
* Utilities / API methods for the server.
*/
@UtilityClass
public class ServerUtils {
/**
* The TPS supplier.
*/
private Supplier<Double> tpsSupplier = null;
/**
* Get the current server TPS.
*
* @return The TPS.
*/
public double getTps() {
Validate.notNull(tpsSupplier, "Not initialized!");
double tps = tpsSupplier.get();
if (tps > 20) {
return 20;
} else {
return tps;
}
}
/**
* Initialize the tps supplier function.
*
* @param function The function.
*/
@ApiStatus.Internal
public void initialize(@NotNull final Supplier<Double> function) {
Validate.isTrue(tpsSupplier == null, "Already initialized!");
tpsSupplier = function;
}
}

View File

@@ -16,7 +16,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.awt.*; import java.awt.Color;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;

View File

@@ -7,4 +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'
} }

View File

@@ -1,6 +1,5 @@
package com.willfp.eco.internal.config package com.willfp.eco.internal.config
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.PluginLike import com.willfp.eco.core.PluginLike
import com.willfp.eco.core.config.interfaces.Config import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.config.interfaces.JSONConfig import com.willfp.eco.core.config.interfaces.JSONConfig

View File

@@ -2,7 +2,12 @@ package com.willfp.eco.internal.config.json
import com.willfp.eco.core.PluginLike import com.willfp.eco.core.PluginLike
import com.willfp.eco.core.config.interfaces.LoadableConfig import com.willfp.eco.core.config.interfaces.LoadableConfig
import java.io.* import java.io.File
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.FileReader
import java.io.IOException
import java.io.OutputStream
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.StandardOpenOption import java.nio.file.StandardOpenOption
@@ -76,7 +81,7 @@ open class EcoLoadableJSONConfig(
} }
init { init {
val directory: File = File(this.plugin.dataFolder, subDirectoryPath) val directory = File(this.plugin.dataFolder, subDirectoryPath)
if (!directory.exists()) { if (!directory.exists()) {
directory.mkdirs() directory.mkdirs()
} }

View File

@@ -0,0 +1,17 @@
package com.willfp.eco.internal.data
import com.willfp.eco.core.data.PlayerProfile
import com.willfp.eco.core.data.keys.PersistentDataKey
class EcoPlayerProfile(
val data: MutableMap<PersistentDataKey<*>, Any>
) : PlayerProfile {
override fun <T : Any> write(key: PersistentDataKey<T>, value: T) {
this.data[key] = value
}
override fun <T : Any> read(key: PersistentDataKey<T>): T {
@Suppress("UNCHECKED_CAST")
return this.data[key] as T? ?: key.defaultValue
}
}

View File

@@ -1,5 +1,6 @@
package com.willfp.eco.internal.display package com.willfp.eco.internal.display
import com.google.common.util.concurrent.ThreadFactoryBuilder
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.display.DisplayHandler import com.willfp.eco.core.display.DisplayHandler
@@ -10,16 +11,11 @@ import org.bukkit.NamespacedKey
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.persistence.PersistentDataType import org.bukkit.persistence.PersistentDataType
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
class EcoDisplayHandler(plugin: EcoPlugin) : DisplayHandler { class EcoDisplayHandler(plugin: EcoPlugin) : DisplayHandler {
/**
* All registered display modules.
*/
private val registeredModules = mutableMapOf<DisplayPriority, MutableList<DisplayModule>>() private val registeredModules = mutableMapOf<DisplayPriority, MutableList<DisplayModule>>()
/**
* NamespacedKey for finalizing.
*/
private val finalizeKey: NamespacedKey = plugin.namespacedKeyFactory.create("finalized") private val finalizeKey: NamespacedKey = plugin.namespacedKeyFactory.create("finalized")
init { init {

View File

@@ -12,10 +12,9 @@ import org.bukkit.event.player.PlayerExpChangeEvent
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.util.Vector import org.bukkit.util.Vector
open class EcoDropQueue(player: Player) : InternalDropQueue { open class EcoDropQueue(val player: Player) : InternalDropQueue {
val items = mutableListOf<ItemStack>() val items = mutableListOf<ItemStack>()
var xp: Int = 0 var xp: Int = 0
val player: Player
var loc: Location var loc: Location
var hasTelekinesis = false var hasTelekinesis = false
@@ -79,7 +78,6 @@ open class EcoDropQueue(player: Player) : InternalDropQueue {
} }
init { init {
this.player = player
loc = player.location loc = player.location
} }
} }

View File

@@ -36,8 +36,9 @@ class Skull : SkullProxy {
profile = meta.javaClass.getDeclaredField("profile") profile = meta.javaClass.getDeclaredField("profile")
profile.isAccessible = true profile.isAccessible = true
} }
val profile = profile[meta] as GameProfile? val profile = profile[meta] as GameProfile? ?: return null
val property = profile?.properties?.get("textures") as Property? val properties = profile.properties ?: return null
return property?.value val prop = properties["textures"] ?: return null
return prop.toMutableList().firstOrNull()?.name
} }
} }

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.proxy.v1_16_R3
import com.willfp.eco.proxy.TPSProxy
import org.bukkit.Bukkit
import org.bukkit.craftbukkit.v1_16_R3.CraftServer
class TPS : TPSProxy {
override fun getTPS(): Double {
return (Bukkit.getServer() as CraftServer).handle.server.recentTps[0]
}
}

View File

@@ -36,8 +36,9 @@ class Skull : SkullProxy {
profile = meta.javaClass.getDeclaredField("profile") profile = meta.javaClass.getDeclaredField("profile")
profile.isAccessible = true profile.isAccessible = true
} }
val profile = profile[meta] as GameProfile? val profile = profile[meta] as GameProfile? ?: return null
val property = profile?.properties?.get("textures") as Property? val properties = profile.properties ?: return null
return property?.value val prop = properties["textures"] ?: return null
return prop.toMutableList().firstOrNull()?.name
} }
} }

View File

@@ -0,0 +1,11 @@
package com.willfp.eco.proxy.v1_17_R1
import com.willfp.eco.proxy.TPSProxy
import org.bukkit.Bukkit
import org.bukkit.craftbukkit.v1_17_R1.CraftServer
class TPS : TPSProxy {
override fun getTPS(): Double {
return (Bukkit.getServer() as CraftServer).handle.server.recentTps[0]
}
}

View File

@@ -7,11 +7,11 @@ dependencies {
exclude group: 'net.kyori', module: 'adventure-api' exclude group: 'net.kyori', module: 'adventure-api'
} }
compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0' compileOnly 'net.kyori:adventure-platform-bukkit:4.0.0'
compileOnly 'net.kyori:adventure-api:4.9.1' compileOnly 'net.kyori:adventure-api:4.9.2'
compileOnly 'net.kyori:adventure-text-serializer-gson:4.9.2' compileOnly 'net.kyori:adventure-text-serializer-gson:4.9.2'
compileOnly 'net.kyori:adventure-text-serializer-legacy:4.8.1' compileOnly 'net.kyori:adventure-text-serializer-legacy:4.9.2'
compileOnly 'org.apache.maven:maven-artifact:3.0.3' compileOnly 'org.apache.maven:maven-artifact:3.8.1'
compileOnly 'com.google.code.gson:gson:2.8.7' compileOnly 'com.google.code.gson:gson:2.8.8'
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT' compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
compileOnly project(":eco-core:core-proxy") compileOnly project(":eco-core:core-proxy")
compileOnly project(":eco-core:core-backend") compileOnly project(":eco-core:core-backend")
@@ -19,7 +19,7 @@ dependencies {
compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.0.7-SNAPSHOT' compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.0.7-SNAPSHOT'
compileOnly 'com.github.TechFortress:GriefPrevention:16.17.1' compileOnly 'com.github.TechFortress:GriefPrevention:16.17.1'
compileOnly 'com.massivecraft:Factions:1.6.9.5-U0.5.10' compileOnly 'com.massivecraft:Factions:1.6.9.5-U0.5.10'
compileOnly 'com.github.cryptomorin:kingdoms:1.10.14' compileOnly 'com.github.cryptomorin:kingdoms:1.11.9'
compileOnly 'com.github.TownyAdvanced:Towny:0.97.2.6' compileOnly 'com.github.TownyAdvanced:Towny:0.97.2.6'
compileOnly 'com.github.angeschossen:LandsAPI:5.15.2' compileOnly 'com.github.angeschossen:LandsAPI:5.15.2'
compileOnly 'fr.neatmonster:nocheatplus:3.16.1-SNAPSHOT' compileOnly 'fr.neatmonster:nocheatplus:3.16.1-SNAPSHOT'
@@ -30,6 +30,16 @@ dependencies {
compileOnly 'com.github.brcdev-minecraft:shopgui-api:2.2.0' compileOnly 'com.github.brcdev-minecraft:shopgui-api:2.2.0'
compileOnly 'com.github.LoneDev6:API-ItemsAdder:2.4.7' compileOnly 'com.github.LoneDev6:API-ItemsAdder:2.4.7'
compileOnly 'com.arcaniax:HeadDatabase-API:1.3.0' compileOnly 'com.arcaniax:HeadDatabase-API:1.3.0'
compileOnly 'org.jetbrains.exposed:exposed-core:0.35.1'
compileOnly 'org.jetbrains.exposed:exposed-dao:0.35.1'
compileOnly 'org.jetbrains.exposed:exposed-jdbc:0.35.1'
compileOnly 'mysql:mysql-connector-java:8.0.25'
compileOnly 'com.gmail.filoghost.holographicdisplays:holographicdisplays-api:2.4.0'
compileOnly 'net.essentialsx:EssentialsX:2.19.0'
compileOnly 'com.bgsoftware:SuperiorSkyblockAPI:latest'
compileOnly 'com.github.MilkBowl:VaultAPI:1.7'
compileOnly 'world.bentobox:bentobox:1.17.3-SNAPSHOT'
compileOnly 'com.google.guava:guava:31.0.1-jre'
// CombatLogX V10 + NewbieHelper Expansion // CombatLogX V10 + NewbieHelper Expansion
compileOnly 'com.SirBlobman.combatlogx:CombatLogX-API:10.0.0.0-SNAPSHOT' compileOnly 'com.SirBlobman.combatlogx:CombatLogX-API:10.0.0.0-SNAPSHOT'

View File

@@ -4,6 +4,8 @@ import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.Handler import com.willfp.eco.core.Handler
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.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
import com.willfp.eco.core.extensions.ExtensionLoader import com.willfp.eco.core.extensions.ExtensionLoader
@@ -34,6 +36,8 @@ 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.proxy.FastItemStackFactoryProxy import com.willfp.eco.proxy.FastItemStackFactoryProxy
import com.willfp.eco.spigot.data.EcoKeyRegistry
import com.willfp.eco.spigot.data.EcoPlayerProfileHandler
import com.willfp.eco.spigot.integrations.bstats.MetricHandler import com.willfp.eco.spigot.integrations.bstats.MetricHandler
import net.kyori.adventure.platform.bukkit.BukkitAudiences import net.kyori.adventure.platform.bukkit.BukkitAudiences
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
@@ -44,6 +48,8 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
private val cleaner = EcoCleaner() private val cleaner = EcoCleaner()
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 playerProfileHandler = EcoPlayerProfileHandler(this)
override fun createScheduler(plugin: EcoPlugin): Scheduler { override fun createScheduler(plugin: EcoPlugin): Scheduler {
return EcoScheduler(plugin) return EcoScheduler(plugin)
@@ -133,6 +139,14 @@ class EcoHandler : EcoSpigotPlugin(), Handler {
return adventure return adventure
} }
override fun getKeyRegistry(): KeyRegistry {
return keyRegistry
}
override fun getPlayerProfileHandler(): PlayerProfileHandler {
return playerProfileHandler
}
fun setAdventure(adventure: BukkitAudiences) { fun setAdventure(adventure: BukkitAudiences) {
this.adventure = adventure this.adventure = adventure
} }

View File

@@ -6,9 +6,12 @@ import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.Prerequisite import com.willfp.eco.core.Prerequisite
import com.willfp.eco.core.display.Display import com.willfp.eco.core.display.Display
import com.willfp.eco.core.integrations.IntegrationLoader import com.willfp.eco.core.integrations.IntegrationLoader
import com.willfp.eco.core.integrations.afk.AFKManager
import com.willfp.eco.core.integrations.anticheat.AnticheatManager import com.willfp.eco.core.integrations.anticheat.AnticheatManager
import com.willfp.eco.core.integrations.antigrief.AntigriefManager import com.willfp.eco.core.integrations.antigrief.AntigriefManager
import com.willfp.eco.core.integrations.customitems.CustomItemsManager import com.willfp.eco.core.integrations.customitems.CustomItemsManager
import com.willfp.eco.core.integrations.economy.EconomyManager
import com.willfp.eco.core.integrations.hologram.HologramManager
import com.willfp.eco.core.integrations.mcmmo.McmmoManager import com.willfp.eco.core.integrations.mcmmo.McmmoManager
import com.willfp.eco.core.integrations.shop.ShopManager import com.willfp.eco.core.integrations.shop.ShopManager
import com.willfp.eco.core.items.Items import com.willfp.eco.core.items.Items
@@ -19,8 +22,20 @@ import com.willfp.eco.internal.drops.DropManager
import com.willfp.eco.proxy.BlockBreakProxy import com.willfp.eco.proxy.BlockBreakProxy
import com.willfp.eco.proxy.FastItemStackFactoryProxy import com.willfp.eco.proxy.FastItemStackFactoryProxy
import com.willfp.eco.proxy.SkullProxy import com.willfp.eco.proxy.SkullProxy
import com.willfp.eco.proxy.TPSProxy
import com.willfp.eco.spigot.arrows.ArrowDataListener import com.willfp.eco.spigot.arrows.ArrowDataListener
import com.willfp.eco.spigot.display.* import com.willfp.eco.spigot.data.DataListener
import com.willfp.eco.spigot.data.EcoPlayerProfileHandler
import com.willfp.eco.spigot.data.PlayerBlockListener
import com.willfp.eco.spigot.data.storage.DataHandler
import com.willfp.eco.spigot.data.storage.MySQLDataHandler
import com.willfp.eco.spigot.data.storage.YamlDataHandler
import com.willfp.eco.spigot.display.PacketAutoRecipe
import com.willfp.eco.spigot.display.PacketChat
import com.willfp.eco.spigot.display.PacketOpenWindowMerchant
import com.willfp.eco.spigot.display.PacketSetCreativeSlot
import com.willfp.eco.spigot.display.PacketSetSlot
import com.willfp.eco.spigot.display.PacketWindowItems
import com.willfp.eco.spigot.display.frame.clearFrames import com.willfp.eco.spigot.display.frame.clearFrames
import com.willfp.eco.spigot.drops.CollatedRunnable import com.willfp.eco.spigot.drops.CollatedRunnable
import com.willfp.eco.spigot.eventlisteners.EntityDeathByEntityListeners import com.willfp.eco.spigot.eventlisteners.EntityDeathByEntityListeners
@@ -29,25 +44,44 @@ import com.willfp.eco.spigot.eventlisteners.PlayerJumpListeners
import com.willfp.eco.spigot.eventlisteners.armor.ArmorChangeEventListeners import com.willfp.eco.spigot.eventlisteners.armor.ArmorChangeEventListeners
import com.willfp.eco.spigot.eventlisteners.armor.ArmorListener import com.willfp.eco.spigot.eventlisteners.armor.ArmorListener
import com.willfp.eco.spigot.gui.GUIListener import com.willfp.eco.spigot.gui.GUIListener
import com.willfp.eco.spigot.integrations.anticheat.* import com.willfp.eco.spigot.integrations.afk.AFKIntegrationCMI
import com.willfp.eco.spigot.integrations.antigrief.* import com.willfp.eco.spigot.integrations.afk.AFKIntegrationEssentials
import com.willfp.eco.spigot.integrations.anticheat.AnticheatAAC
import com.willfp.eco.spigot.integrations.anticheat.AnticheatAlice
import com.willfp.eco.spigot.integrations.anticheat.AnticheatMatrix
import com.willfp.eco.spigot.integrations.anticheat.AnticheatNCP
import com.willfp.eco.spigot.integrations.anticheat.AnticheatSpartan
import com.willfp.eco.spigot.integrations.anticheat.AnticheatVulcan
import com.willfp.eco.spigot.integrations.antigrief.AntigriefBentoBox
import com.willfp.eco.spigot.integrations.antigrief.AntigriefCombatLogXV10
import com.willfp.eco.spigot.integrations.antigrief.AntigriefCombatLogXV11
import com.willfp.eco.spigot.integrations.antigrief.AntigriefFactionsUUID
import com.willfp.eco.spigot.integrations.antigrief.AntigriefGriefPrevention
import com.willfp.eco.spigot.integrations.antigrief.AntigriefKingdoms
import com.willfp.eco.spigot.integrations.antigrief.AntigriefLands
import com.willfp.eco.spigot.integrations.antigrief.AntigriefSuperiorSkyblock2
import com.willfp.eco.spigot.integrations.antigrief.AntigriefTowny
import com.willfp.eco.spigot.integrations.antigrief.AntigriefWorldGuard
import com.willfp.eco.spigot.integrations.customitems.CustomItemsHeadDatabase import com.willfp.eco.spigot.integrations.customitems.CustomItemsHeadDatabase
import com.willfp.eco.spigot.integrations.customitems.CustomItemsItemsAdder import com.willfp.eco.spigot.integrations.customitems.CustomItemsItemsAdder
import com.willfp.eco.spigot.integrations.customitems.CustomItemsOraxen import com.willfp.eco.spigot.integrations.customitems.CustomItemsOraxen
import com.willfp.eco.spigot.integrations.economy.EconomyVault
import com.willfp.eco.spigot.integrations.hologram.HologramCMI
import com.willfp.eco.spigot.integrations.hologram.HologramGHolo
import com.willfp.eco.spigot.integrations.hologram.HologramHolographicDisplays
import com.willfp.eco.spigot.integrations.mcmmo.McmmoIntegrationImpl import com.willfp.eco.spigot.integrations.mcmmo.McmmoIntegrationImpl
import com.willfp.eco.spigot.integrations.multiverseinventories.MultiverseInventoriesIntegration import com.willfp.eco.spigot.integrations.multiverseinventories.MultiverseInventoriesIntegration
import com.willfp.eco.spigot.integrations.shop.ShopShopGuiPlus import com.willfp.eco.spigot.integrations.shop.ShopShopGuiPlus
import com.willfp.eco.spigot.recipes.ShapedRecipeListener import com.willfp.eco.spigot.recipes.ShapedRecipeListener
import com.willfp.eco.util.BlockUtils import com.willfp.eco.util.BlockUtils
import com.willfp.eco.util.ServerUtils
import com.willfp.eco.util.SkullUtils import com.willfp.eco.util.SkullUtils
import net.kyori.adventure.platform.bukkit.BukkitAudiences import net.kyori.adventure.platform.bukkit.BukkitAudiences
import net.milkbowl.vault.economy.Economy
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.block.Block
import org.bukkit.entity.Player
import org.bukkit.event.Listener import org.bukkit.event.Listener
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.SkullMeta
abstract class EcoSpigotPlugin : EcoPlugin( abstract class EcoSpigotPlugin : EcoPlugin(
773, 773,
@@ -55,24 +89,32 @@ abstract class EcoSpigotPlugin : EcoPlugin(
"com.willfp.eco.proxy", "com.willfp.eco.proxy",
"&a" "&a"
) { ) {
lateinit var dataHandler: DataHandler
init { init {
Items.registerArgParser(EnchantmentArgParser()) Items.registerArgParser(EnchantmentArgParser())
Items.registerArgParser(TextureArgParser()) Items.registerArgParser(TextureArgParser())
val skullProxy = getProxy(SkullProxy::class.java) val skullProxy = getProxy(SkullProxy::class.java)
SkullUtils.initialize( SkullUtils.initialize(
{ meta: SkullMeta, base64: String -> skullProxy.setSkullTexture(meta, base64) }, { meta, base64 -> skullProxy.setSkullTexture(meta, base64) },
{ meta: SkullMeta -> skullProxy.getSkullTexture(meta) } { meta -> skullProxy.getSkullTexture(meta) }
) )
val blockBreakProxy = getProxy(BlockBreakProxy::class.java) val blockBreakProxy = getProxy(BlockBreakProxy::class.java)
BlockUtils.initialize { player: Player, block: Block -> blockBreakProxy.breakBlock(player, block) } BlockUtils.initialize { player, block -> blockBreakProxy.breakBlock(player, block) }
val tpsProxy = getProxy(TPSProxy::class.java)
ServerUtils.initialize { tpsProxy.getTPS() }
postInit() postInit()
} }
private fun postInit() { private fun postInit() {
Display.handler = EcoDisplayHandler(this) Display.setHandler(EcoDisplayHandler(this))
this.dataHandler = if (this.configYml.getBool("mysql.enabled"))
MySQLDataHandler(this) else YamlDataHandler(this)
} }
override fun handleEnable() { override fun handleEnable() {
@@ -113,6 +155,14 @@ abstract class EcoSpigotPlugin : EcoPlugin(
this.configYml.getInt("display-frame-ttl").toLong(), this.configYml.getInt("display-frame-ttl").toLong(),
this.configYml.getInt("display-frame-ttl").toLong() this.configYml.getInt("display-frame-ttl").toLong()
) )
this.scheduler.runTimer(
{
(Eco.getHandler().playerProfileHandler as EcoPlayerProfileHandler)
.autosave(this.configYml.getBool("autosave.async"))
},
this.configYml.getInt("autosave.ticks").toLong(),
this.configYml.getInt("autosave.ticks").toLong()
)
} }
override fun handleAfterLoad() { override fun handleAfterLoad() {
@@ -123,6 +173,8 @@ abstract class EcoSpigotPlugin : EcoPlugin(
override fun loadIntegrationLoaders(): List<IntegrationLoader> { override fun loadIntegrationLoaders(): List<IntegrationLoader> {
return listOf( return listOf(
// AntiGrief // AntiGrief
IntegrationLoader("SuperiorSkyblock2") { AntigriefManager.register(AntigriefSuperiorSkyblock2()) },
IntegrationLoader("BentoBox") { AntigriefManager.register(AntigriefBentoBox()) },
IntegrationLoader("WorldGuard") { AntigriefManager.register(AntigriefWorldGuard()) }, IntegrationLoader("WorldGuard") { AntigriefManager.register(AntigriefWorldGuard()) },
IntegrationLoader("GriefPrevention") { AntigriefManager.register(AntigriefGriefPrevention()) }, IntegrationLoader("GriefPrevention") { AntigriefManager.register(AntigriefGriefPrevention()) },
IntegrationLoader("FactionsUUID") { AntigriefManager.register(AntigriefFactionsUUID()) }, IntegrationLoader("FactionsUUID") { AntigriefManager.register(AntigriefFactionsUUID()) },
@@ -157,9 +209,30 @@ abstract class EcoSpigotPlugin : EcoPlugin(
// Shop // Shop
IntegrationLoader("ShopGUIPlus") { ShopManager.register(ShopShopGuiPlus()) }, IntegrationLoader("ShopGUIPlus") { ShopManager.register(ShopShopGuiPlus()) },
// Hologram
IntegrationLoader("HolographicDisplays") { HologramManager.register(HologramHolographicDisplays(this)) },
IntegrationLoader("CMI") { HologramManager.register(HologramCMI()) },
IntegrationLoader("GHolo") { HologramManager.register(HologramGHolo()) },
// AFK
IntegrationLoader("Essentials") { AFKManager.register(AFKIntegrationEssentials()) },
IntegrationLoader("CMI") { AFKManager.register(AFKIntegrationCMI()) },
// Economy
IntegrationLoader("Vault") {
val rsp = Bukkit.getServer().servicesManager.getRegistration(Economy::class.java)
if (rsp != null) {
EconomyManager.register(EconomyVault(rsp.provider))
}
},
// Misc // Misc
IntegrationLoader("mcMMO") { McmmoManager.register(McmmoIntegrationImpl()) }, IntegrationLoader("mcMMO") { McmmoManager.register(McmmoIntegrationImpl()) },
IntegrationLoader("Multiverse-Inventories") { this.eventManager.registerListener(MultiverseInventoriesIntegration(this)) } IntegrationLoader("Multiverse-Inventories") {
this.eventManager.registerListener(
MultiverseInventoriesIntegration(this)
)
}
) )
} }
@@ -183,7 +256,9 @@ abstract class EcoSpigotPlugin : EcoPlugin(
PlayerJumpListeners(), PlayerJumpListeners(),
GUIListener(this), GUIListener(this),
ArrowDataListener(this), ArrowDataListener(this),
ArmorChangeEventListeners(this) ArmorChangeEventListeners(this),
DataListener(),
PlayerBlockListener(this)
) )
} }
} }

View File

@@ -0,0 +1,21 @@
package com.willfp.eco.spigot.data
import com.willfp.eco.core.Eco
import com.willfp.eco.util.PlayerUtils
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.player.PlayerQuitEvent
class DataListener : Listener {
@EventHandler
fun onLeave(event: PlayerQuitEvent) {
PlayerUtils.updateSavedDisplayName(event.player)
Eco.getHandler().playerProfileHandler.savePlayer(event.player.uniqueId)
}
@EventHandler
fun onJoin(event: PlayerJoinEvent) {
PlayerUtils.updateSavedDisplayName(event.player)
}
}

View File

@@ -0,0 +1,48 @@
package com.willfp.eco.spigot.data
import com.willfp.eco.core.data.keys.KeyRegistry
import com.willfp.eco.core.data.keys.PersistentDataKey
import com.willfp.eco.core.data.keys.PersistentDataKeyType
import com.willfp.eco.spigot.EcoSpigotPlugin
import org.bukkit.NamespacedKey
class EcoKeyRegistry(
private val plugin: EcoSpigotPlugin
) : KeyRegistry {
private val registry = mutableMapOf<NamespacedKey, PersistentDataKey<*>>()
override fun registerKey(key: PersistentDataKey<*>) {
if (this.registry.containsKey(key.key)) {
this.registry.remove(key.key)
}
validateKey(key)
this.registry[key.key] = key
plugin.dataHandler.updateKeys()
}
override fun getRegisteredKeys(): MutableSet<PersistentDataKey<*>> {
return registry.values.toMutableSet()
}
private fun <T> validateKey(key: PersistentDataKey<T>) {
when (key.type) {
PersistentDataKeyType.INT -> if (key.defaultValue !is Int) {
throw IllegalArgumentException("Invalid Data Type! Should be Int")
}
PersistentDataKeyType.DOUBLE -> if (key.defaultValue !is Double) {
throw IllegalArgumentException("Invalid Data Type! Should be Double")
}
PersistentDataKeyType.BOOLEAN -> if (key.defaultValue !is Boolean) {
throw IllegalArgumentException("Invalid Data Type! Should be Boolean")
}
PersistentDataKeyType.STRING -> if (key.defaultValue !is String) {
throw IllegalArgumentException("Invalid Data Type! Should be String")
}
else -> throw NullPointerException("Null value found!")
}
}
}

View File

@@ -0,0 +1,83 @@
package com.willfp.eco.spigot.data
import com.willfp.eco.core.Eco
import com.willfp.eco.core.data.PlayerProfile
import com.willfp.eco.core.data.PlayerProfileHandler
import com.willfp.eco.core.data.keys.PersistentDataKey
import com.willfp.eco.internal.data.EcoPlayerProfile
import com.willfp.eco.spigot.EcoSpigotPlugin
import org.bukkit.Bukkit
import java.util.*
class EcoPlayerProfileHandler(
private val plugin: EcoSpigotPlugin
) : PlayerProfileHandler {
private val loaded = mutableMapOf<UUID, PlayerProfile>()
private val handler = plugin.dataHandler
override fun load(uuid: UUID): PlayerProfile {
val found = loaded[uuid]
if (found != null) {
return found
}
val data = mutableMapOf<PersistentDataKey<*>, Any>()
for (key in Eco.getHandler().keyRegistry.registeredKeys) {
data[key] = handler.read(uuid, key.key) ?: key.defaultValue
}
val profile = EcoPlayerProfile(data)
loaded[uuid] = profile
return profile
}
override fun savePlayer(uuid: UUID) {
writeToHandler(uuid)
saveToHandler()
}
private fun writeToHandler(uuid: UUID) {
val profile = load(uuid)
for (key in Eco.getHandler().keyRegistry.registeredKeys) {
handler.write(uuid, key.key, profile.read(key) ?: key.defaultValue)
}
}
private fun saveToHandler() {
handler.save()
}
override fun saveAll(async: Boolean) {
val saver = {
for ((uuid, _) in loaded) {
writeToHandler(uuid)
}
saveToHandler()
}
if (async) {
plugin.scheduler.runAsync(saver)
} else {
saver.invoke()
}
}
fun autosave(async: Boolean) {
if (Bukkit.getOnlinePlayers().isEmpty()) {
return
}
if (plugin.configYml.getBool("autosave.log")) {
plugin.logger.info("Auto-Saving player data!")
}
saveAll(async)
if (plugin.configYml.getBool("autosave.log")) {
plugin.logger.info("Saved player data!")
}
}
}

View File

@@ -0,0 +1,53 @@
package com.willfp.eco.spigot.data
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.util.NamespacedKeyUtils
import org.bukkit.block.Block
import org.bukkit.event.EventHandler
import org.bukkit.event.EventPriority
import org.bukkit.event.Listener
import org.bukkit.event.block.BlockBreakEvent
import org.bukkit.event.block.BlockMultiPlaceEvent
import org.bukkit.event.block.BlockPlaceEvent
import org.bukkit.persistence.PersistentDataType
class PlayerBlockListener(
private val plugin: EcoPlugin
) : Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
fun onPlace(event: BlockPlaceEvent) {
val block = event.blockPlaced
writeKey(block)
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
fun onPlace(event: BlockMultiPlaceEvent) {
val block = event.blockPlaced
writeKey(block)
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
fun onBreak(event: BlockBreakEvent) {
val block = event.block
this.plugin.scheduler.run {
removeKey(block)
}
}
private fun writeKey(block: Block) {
val loc = block.location.hashCode().toString(16)
block.chunk.persistentDataContainer.set(
plugin.namespacedKeyFactory.create(loc.lowercase()),
PersistentDataType.INTEGER,
1
)
}
private fun removeKey(block: Block) {
val loc = block.location.hashCode().toString(16)
block.chunk.persistentDataContainer.remove(plugin.namespacedKeyFactory.create(loc.lowercase()))
}
}

View File

@@ -0,0 +1,13 @@
package com.willfp.eco.spigot.data.storage
import org.bukkit.NamespacedKey
import java.util.*
interface DataHandler {
fun save()
fun <T> write(uuid: UUID, key: NamespacedKey, value: T)
fun <T> read(uuid: UUID, key: NamespacedKey): T?
fun updateKeys()
}

View File

@@ -0,0 +1,123 @@
package com.willfp.eco.spigot.data.storage
import com.willfp.eco.core.Eco
import com.willfp.eco.core.data.keys.PersistentDataKey
import com.willfp.eco.core.data.keys.PersistentDataKeyType
import com.willfp.eco.spigot.EcoSpigotPlugin
import org.bukkit.NamespacedKey
import org.jetbrains.exposed.dao.id.UUIDTable
import org.jetbrains.exposed.sql.BooleanColumnType
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.DoubleColumnType
import org.jetbrains.exposed.sql.IntegerColumnType
import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.VarCharColumnType
import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import org.jetbrains.exposed.sql.update
import java.util.UUID
@Suppress("UNCHECKED_CAST")
class MySQLDataHandler(
plugin: EcoSpigotPlugin
) : DataHandler {
private val columns = mutableMapOf<String, Column<*>>()
init {
Database.connect(
"jdbc:mysql://" +
"${plugin.configYml.getString("mysql.host")}:" +
"${plugin.configYml.getString("mysql.port")}/" +
plugin.configYml.getString("mysql.database"),
driver = "com.mysql.cj.jdbc.Driver",
user = plugin.configYml.getString("mysql.user"),
password = plugin.configYml.getString("mysql.password")
)
transaction {
SchemaUtils.create(Players)
}
}
override fun updateKeys() {
transaction {
for (key in Eco.getHandler().keyRegistry.registeredKeys) {
registerColumn(key, Players)
}
SchemaUtils.createMissingTablesAndColumns(Players)
}
}
override fun save() {
// Do nothing
}
override fun <T> write(uuid: UUID, key: NamespacedKey, value: T) {
transaction {
getPlayer(uuid)
val column: Column<T> = getColumn(key.toString()) as Column<T>
Players.update({ Players.id eq uuid }) {
it[column] = value
}
}
}
override fun <T> read(uuid: UUID, key: NamespacedKey): T? {
var value: T? = null
transaction {
val player = getPlayer(uuid)
value = player[getColumn(key.toString())] as T?
}
return value
}
object Players : UUIDTable("eco_players") {
}
private fun <T> registerColumn(key: PersistentDataKey<T>, table: UUIDTable) {
table.apply {
if (this.columns.stream().anyMatch { it.name == key.key.toString() }) {
return@apply
}
when (key.type) {
PersistentDataKeyType.INT -> registerColumn<Int>(key.key.toString(), IntegerColumnType())
.default(key.defaultValue as Int)
PersistentDataKeyType.DOUBLE -> registerColumn<Double>(key.key.toString(), DoubleColumnType())
.default(key.defaultValue as Double)
PersistentDataKeyType.BOOLEAN -> registerColumn<Boolean>(key.key.toString(), BooleanColumnType())
.default(key.defaultValue as Boolean)
PersistentDataKeyType.STRING -> registerColumn<String>(key.key.toString(), VarCharColumnType(512))
.default(key.defaultValue as String)
else -> throw NullPointerException("Null value found!")
}
}
}
private fun getColumn(name: String): Column<*> {
val cached = columns[name]
if (cached != null) {
return cached
}
columns[name] = Players.columns.stream().filter { it.name == name }.findFirst().get()
return getColumn(name)
}
private fun getPlayer(uuid: UUID): ResultRow {
Players.select { Players.id eq uuid }.firstOrNull() ?: run {
Players.insert {
it[id] = uuid
}
}
return Players.select { Players.id eq uuid }.first()
}
}

View File

@@ -0,0 +1,37 @@
package com.willfp.eco.spigot.data.storage
import com.willfp.eco.core.config.yaml.YamlBaseConfig
import com.willfp.eco.spigot.EcoSpigotPlugin
import org.bukkit.NamespacedKey
import java.util.*
@Suppress("UNCHECKED_CAST")
class YamlDataHandler(
plugin: EcoSpigotPlugin
) : DataHandler {
private val dataYml = DataYml(plugin)
override fun save() {
dataYml.save()
}
override fun updateKeys() {
// Do nothing
}
override fun <T> write(uuid: UUID, key: NamespacedKey, value: T) {
dataYml.set("player.$uuid.$key", value)
}
override fun <T> read(uuid: UUID, key: NamespacedKey): T? {
return dataYml.get("player.$uuid.$key") as T?
}
class DataYml(
plugin: EcoSpigotPlugin
) : YamlBaseConfig(
"data",
false,
plugin
)
}

View File

@@ -1,8 +1,10 @@
package com.willfp.eco.spigot.display package com.willfp.eco.spigot.display
import com.comphenix.protocol.PacketType import com.comphenix.protocol.PacketType
import com.comphenix.protocol.ProtocolLibrary
import com.comphenix.protocol.events.PacketContainer import com.comphenix.protocol.events.PacketContainer
import com.comphenix.protocol.events.PacketEvent import com.comphenix.protocol.events.PacketEvent
import com.google.common.util.concurrent.ThreadFactoryBuilder
import com.willfp.eco.core.AbstractPacketAdapter import com.willfp.eco.core.AbstractPacketAdapter
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
@@ -10,53 +12,137 @@ import com.willfp.eco.core.fast.FastItemStack
import com.willfp.eco.spigot.display.frame.DisplayFrame import com.willfp.eco.spigot.display.frame.DisplayFrame
import com.willfp.eco.spigot.display.frame.HashedItem import com.willfp.eco.spigot.display.frame.HashedItem
import com.willfp.eco.spigot.display.frame.lastDisplayFrame import com.willfp.eco.spigot.display.frame.lastDisplayFrame
import com.willfp.eco.util.ServerUtils
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack import org.bukkit.inventory.ItemStack
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
class PacketWindowItems(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, PacketType.Play.Server.WINDOW_ITEMS, false) { class PacketWindowItems(plugin: EcoPlugin) : AbstractPacketAdapter(plugin, PacketType.Play.Server.WINDOW_ITEMS, false) {
private val ignorePacketList = ConcurrentHashMap.newKeySet<String>()
private val playerRates = ConcurrentHashMap<String, Int>()
private val threadFactory = ThreadFactoryBuilder().setNameFormat("eco-display-thread-%d").build()
private val executor = Executors.newCachedThreadPool(threadFactory)
private val scheduledExecutor = Executors.newSingleThreadScheduledExecutor(threadFactory)
override fun onSend( override fun onSend(
packet: PacketContainer, packet: PacketContainer,
player: Player, player: Player,
event: PacketEvent event: PacketEvent
) { ) {
if (ignorePacketList.contains(player.name)) {
ignorePacketList.remove(player.name)
return
}
val windowId = packet.integers.read(0) val windowId = packet.integers.read(0)
if (windowId != 0) { if (windowId != 0) {
player.lastDisplayFrame = DisplayFrame.EMPTY player.lastDisplayFrame = DisplayFrame.EMPTY
} }
packet.itemListModifier.modify(0) { itemStacks: MutableList<ItemStack>? -> val itemStacks = packet.itemListModifier.read(0) ?: return
if (itemStacks == null) {
return@modify null handleRateLimit(player)
if (usingAsync(player)) {
executor.execute {
try {
modifyWindowItems(itemStacks, windowId, player)
} catch (e: Exception) {
if (this.getPlugin().configYml.getBool("async-display.log-errors")) {
this.getPlugin().logger.warning("Error happened in async processing! Disable async display (/plugins/eco/config.yml) if this is a frequent issue")
}
}
val newPacket = packet.deepClone()
newPacket.itemListModifier.write(0, itemStacks)
ignorePacketList.add(player.name)
ProtocolLibrary.getProtocolManager().sendServerPacket(player, newPacket)
} }
} else {
if (this.getPlugin().configYml.getBool("use-display-frame") && windowId == 0) { packet.itemListModifier.write(0, modifyWindowItems(itemStacks, windowId, player))
val frameMap = mutableMapOf<Byte, HashedItem>()
for (index in itemStacks.indices) {
frameMap[index.toByte()] =
HashedItem(FastItemStack.wrap(itemStacks[index]).hashCode(), itemStacks[index])
}
val newFrame = DisplayFrame(frameMap)
val lastFrame = player.lastDisplayFrame
player.lastDisplayFrame = newFrame
val changes = lastFrame.getChangedSlots(newFrame)
for (index in changes) {
Display.display(itemStacks[index.toInt()], player)
}
for (index in (itemStacks.indices subtract changes)) {
itemStacks[index.toInt()] = lastFrame.getItem(index.toByte()) ?: itemStacks[index.toInt()]
}
} else {
itemStacks.forEach { Display.display(it, player) }
}
itemStacks
} }
} }
private fun handleRateLimit(player: Player) {
fun modifyRateValueBy(player: Player, amount: Int) {
val name = player.name
val current = playerRates[name] ?: 0
val new = current + amount
if (new <= 0) {
playerRates.remove(name)
} else {
playerRates[name] = new
}
}
modifyRateValueBy(player, 1)
scheduledExecutor.schedule(
{ modifyRateValueBy(player, -1) },
this.getPlugin().configYml.getInt("async-display.ratelimit.timeframe").toLong(),
TimeUnit.SECONDS
)
}
private fun usingAsync(player: Player): Boolean {
if (this.getPlugin().configYml.getBool("async-display.enabled")) {
return true
}
if (
this.getPlugin().configYml.getBool("async-display.emergency.enabled")
&& ServerUtils.getTps() <= this.getPlugin().configYml.getDouble("async-display.emergency.cutoff")
) {
return true
}
if (
this.getPlugin().configYml.getBool("async-display.ratelimit.enabled")
&& (playerRates[player.name] ?: 0) >= this.getPlugin().configYml.getInt("async-display.ratelimit.cutoff")
) {
return true
}
return false
}
private fun modifyWindowItems(
itemStacks: MutableList<ItemStack>,
windowId: Int,
player: Player
): MutableList<ItemStack> {
if (this.getPlugin().configYml.getBool("use-display-frame") && windowId == 0) {
val frameMap = mutableMapOf<Byte, HashedItem>()
for (index in itemStacks.indices) {
frameMap[index.toByte()] =
HashedItem(FastItemStack.wrap(itemStacks[index]).hashCode(), itemStacks[index])
}
val newFrame = DisplayFrame(frameMap)
val lastFrame = player.lastDisplayFrame
player.lastDisplayFrame = newFrame
val changes = lastFrame.getChangedSlots(newFrame)
for (index in changes) {
Display.display(itemStacks[index.toInt()], player)
}
for (index in (itemStacks.indices subtract changes.toSet())) {
itemStacks[index.toInt()] = lastFrame.getItem(index.toByte()) ?: itemStacks[index.toInt()]
}
} else {
itemStacks.forEach { Display.display(it, player) }
}
return itemStacks
}
} }

View File

@@ -0,0 +1,15 @@
package com.willfp.eco.spigot.integrations.afk
import com.Zrips.CMI.CMI
import com.willfp.eco.core.integrations.afk.AFKWrapper
import org.bukkit.entity.Player
class AFKIntegrationCMI : AFKWrapper {
override fun isAfk(player: Player): Boolean {
return CMI.getInstance().playerManager.getUser(player)?.isAfk ?: false
}
override fun getPluginName(): String {
return "CMI"
}
}

View File

@@ -0,0 +1,18 @@
package com.willfp.eco.spigot.integrations.afk
import com.earth2me.essentials.Essentials
import com.willfp.eco.core.integrations.afk.AFKWrapper
import org.bukkit.entity.Player
import org.bukkit.plugin.java.JavaPlugin
class AFKIntegrationEssentials : AFKWrapper {
private val ess = JavaPlugin.getPlugin(Essentials::class.java)
override fun isAfk(player: Player): Boolean {
return ess.getUser(player) != null && ess.getUser(player).isAfk
}
override fun getPluginName(): String {
return "Essentials"
}
}

View File

@@ -0,0 +1,75 @@
package com.willfp.eco.spigot.integrations.antigrief
import com.willfp.eco.core.integrations.antigrief.AntigriefWrapper
import org.bukkit.Location
import org.bukkit.World
import org.bukkit.block.Block
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Monster
import org.bukkit.entity.Player
import world.bentobox.bentobox.BentoBox
import world.bentobox.bentobox.api.user.User
import world.bentobox.bentobox.lists.Flags
class AntigriefBentoBox : AntigriefWrapper {
override fun canBreakBlock(
player: Player,
block: Block
): Boolean {
val island = BentoBox.getInstance().islandsManager.getIslandAt(block.location).orElse(null) ?: return true
return island.isAllowed(User.getInstance(player), Flags.BREAK_BLOCKS)
}
override fun canCreateExplosion(
player: Player,
location: Location
): Boolean {
val island = BentoBox.getInstance().islandsManager.getIslandAt(location).orElse(null) ?: return true
return island.isAllowed(User.getInstance(player), Flags.TNT_DAMAGE)
}
override fun canPlaceBlock(
player: Player,
block: Block
): Boolean {
val island = BentoBox.getInstance().islandsManager.getIslandAt(block.location).orElse(null) ?: return true
return island.isAllowed(User.getInstance(player), Flags.PLACE_BLOCKS)
}
override fun canInjure(
player: Player,
victim: LivingEntity
): Boolean {
val island = BentoBox.getInstance().islandsManager.getIslandAt(victim.location).orElse(null) ?: return true
return when (victim) {
is Player -> {
island.isAllowed(
User.getInstance(player), when (victim.world.environment) {
World.Environment.NORMAL -> Flags.PVP_OVERWORLD
World.Environment.NETHER -> Flags.PVP_NETHER
World.Environment.THE_END -> Flags.PVP_END
else -> Flags.PVP_OVERWORLD
}
)
}
is Monster -> island.isAllowed(User.getInstance(player), Flags.HURT_MONSTERS)
else -> island.isAllowed(User.getInstance(player), Flags.HURT_ANIMALS)
}
}
override fun getPluginName(): String {
return "BentoBox"
}
override fun equals(other: Any?): Boolean {
if (other !is AntigriefWrapper) {
return false
}
return other.pluginName == this.pluginName
}
override fun hashCode(): Int {
return this.pluginName.hashCode()
}
}

View File

@@ -0,0 +1,49 @@
package com.willfp.eco.spigot.integrations.antigrief
import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI
import com.bgsoftware.superiorskyblock.api.enums.HitActionResult
import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege
import com.willfp.eco.core.integrations.antigrief.AntigriefWrapper
import org.bukkit.Location
import org.bukkit.block.Block
import org.bukkit.entity.Animals
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Monster
import org.bukkit.entity.Player
class AntigriefSuperiorSkyblock2 : AntigriefWrapper {
override fun getPluginName(): String {
return "SuperiorSkyblock2"
}
override fun canBreakBlock(player: Player, block: Block): Boolean {
if (SuperiorSkyblockAPI.getPlayer(player).hasBypassModeEnabled()) return true
return SuperiorSkyblockAPI.getPlayer(player).hasPermission(IslandPrivilege.getByName("Break"))
|| SuperiorSkyblockAPI.getPlayer(player).hasPermission(IslandPrivilege.getByName("BREAK"))
}
override fun canCreateExplosion(player: Player, location: Location): Boolean {
if (SuperiorSkyblockAPI.getPlayer(player).hasBypassModeEnabled()) return true
return SuperiorSkyblockAPI.getIslandAt(location)?.isMember(SuperiorSkyblockAPI.getPlayer(player)) ?: true
}
override fun canPlaceBlock(player: Player, block: Block): Boolean {
if (SuperiorSkyblockAPI.getPlayer(player).hasBypassModeEnabled()) return true
return SuperiorSkyblockAPI.getPlayer(player).hasPermission(IslandPrivilege.getByName("Place"))
|| SuperiorSkyblockAPI.getPlayer(player).hasPermission(IslandPrivilege.getByName("PLACE"))
}
override fun canInjure(player: Player, victim: LivingEntity): Boolean {
if (SuperiorSkyblockAPI.getPlayer(player).hasBypassModeEnabled()) return true
return when (victim) {
is Player -> SuperiorSkyblockAPI.getPlayer(player).canHit(SuperiorSkyblockAPI.getPlayer(victim)).equals(HitActionResult.SUCCESS)
is Animals -> {
return SuperiorSkyblockAPI.getPlayer(player).hasPermission(IslandPrivilege.getByName("ANIMAL_DAMAGE"))
}
is Monster -> {
return SuperiorSkyblockAPI.getPlayer(player).hasPermission(IslandPrivilege.getByName("MONSTER_DAMAGE"))
}
else -> true
}
}
}

View File

@@ -0,0 +1,29 @@
package com.willfp.eco.spigot.integrations.economy
import com.willfp.eco.core.integrations.economy.EconomyWrapper
import net.milkbowl.vault.economy.Economy
import org.bukkit.OfflinePlayer
class EconomyVault(
private val vault: Economy
): EconomyWrapper {
override fun hasAmount(player: OfflinePlayer, amount: Double): Boolean {
return vault.has(player, amount)
}
override fun giveMoney(player: OfflinePlayer, amount: Double): Boolean {
return vault.depositPlayer(player, amount).transactionSuccess()
}
override fun removeMoney(player: OfflinePlayer, amount: Double): Boolean {
return vault.withdrawPlayer(player, amount).transactionSuccess()
}
override fun getBalance(player: OfflinePlayer): Double {
return vault.getBalance(player)
}
override fun getPluginName(): String {
return "Vault"
}
}

View File

@@ -0,0 +1,40 @@
package com.willfp.eco.spigot.integrations.hologram
import com.Zrips.CMI.CMI
import com.Zrips.CMI.Modules.Holograms.CMIHologram
import com.willfp.eco.core.integrations.hologram.Hologram
import com.willfp.eco.core.integrations.hologram.HologramWrapper
import net.Zrips.CMILib.Container.CMILocation
import org.bukkit.Location
import java.util.UUID
@Suppress("DEPRECATION")
class HologramCMI : HologramWrapper {
override fun createHologram(location: Location, contents: MutableList<String>): Hologram {
val cmiHolo = CMIHologram(UUID.randomUUID().toString(), CMILocation(location))
CMI.getInstance().hologramManager.addHologram(cmiHolo)
val holo = HologramImplCMI(cmiHolo)
holo.setContents(contents)
cmiHolo.enable()
return holo
}
override fun getPluginName(): String {
return "CMI"
}
class HologramImplCMI(
private val handle: CMIHologram
) : Hologram {
override fun remove() {
CMI.getInstance().hologramManager.removeHolo(handle)
}
override fun setContents(contents: MutableList<String>) {
handle.lines = contents
}
}
}

View File

@@ -0,0 +1,38 @@
package com.willfp.eco.spigot.integrations.hologram
import com.willfp.eco.core.integrations.hologram.Hologram
import com.willfp.eco.core.integrations.hologram.HologramWrapper
import me.gholo.api.GHoloAPI
import org.bukkit.Location
import java.util.*
@Suppress("DEPRECATION")
class HologramGHolo : HologramWrapper {
companion object {
private val api = GHoloAPI()
}
override fun createHologram(location: Location, contents: MutableList<String>): Hologram {
val id = UUID.randomUUID().toString()
api.insertHolo(id, location, contents)
return HologramImplGHolo(id)
}
override fun getPluginName(): String {
return "GHolo"
}
class HologramImplGHolo(
private val id: String
) : Hologram {
override fun remove() {
api.removeHolo(id)
}
override fun setContents(contents: MutableList<String>) {
api.getHolo(id)?.content = contents
}
}
}

View File

@@ -0,0 +1,41 @@
package com.willfp.eco.spigot.integrations.hologram
import com.gmail.filoghost.holographicdisplays.api.HologramsAPI
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.integrations.hologram.Hologram
import com.willfp.eco.core.integrations.hologram.HologramWrapper
import org.bukkit.Location
class HologramHolographicDisplays(
private val plugin: EcoPlugin
) : HologramWrapper {
override fun createHologram(location: Location, contents: MutableList<String>): Hologram {
val hologram = HologramImplHolographicDisplays(
HologramsAPI.createHologram(plugin, location)
)
hologram.setContents(contents)
return hologram
}
override fun getPluginName(): String {
return "HolographicDisplays"
}
class HologramImplHolographicDisplays(
private val handle: com.gmail.filoghost.holographicdisplays.api.Hologram
) : Hologram {
override fun remove() {
handle.delete()
}
override fun setContents(contents: MutableList<String>) {
handle.clearLines()
for (line in contents) {
handle.appendTextLine(line)
}
}
}
}

View File

@@ -27,6 +27,10 @@ class McmmoIntegrationImpl : McmmoWrapper {
} else event is FakeEvent } else event is FakeEvent
} }
override fun getPluginName(): String {
return "mcMMO"
}
init { init {
if (!ClassUtils.exists("com.gmail.nossr50.events.fake.FakeEvent")) { if (!ClassUtils.exists("com.gmail.nossr50.events.fake.FakeEvent")) {
disabled = true disabled = true

View File

@@ -3,6 +3,19 @@
# by Auxilor # by Auxilor
# #
mysql:
enabled: false # Set to false, data.yml will be used instead.
host: localhost
port: 3306
database: database
user: username
password: passy
autosave:
ticks: 20000 # The amount of ticks between autosaves
log: false # If auto-save messages should be sent to console
async: false # If saves should be performed asynchronously. May cause bugs without MySQL
# Options to fix villager bugs left behind from old (buggy) versions. # Options to fix villager bugs left behind from old (buggy) versions.
villager-display-fix: false villager-display-fix: false
@@ -17,7 +30,7 @@ use-fast-collated-drops: true
enable-bstats: true enable-bstats: true
# Some plugins use their own item display systems (eg Triton) # Some plugins use their own item display systems (eg Triton)
# And must be ran after eco. Don't enable this unless you run a conflicting plugin # And must be run after eco. Don't enable this unless you run a conflicting plugin
# and have been told to enable it. # and have been told to enable it.
use-lower-protocollib-priority: false use-lower-protocollib-priority: false
@@ -28,4 +41,38 @@ use-display-frame: true
# Time to live for a display frame. In other words, this is how frequent (in ticks) # Time to live for a display frame. In other words, this is how frequent (in ticks)
# that display frames will be cleared / deleted. # that display frames will be cleared / deleted.
display-frame-ttl: 17 display-frame-ttl: 17
# Window items packets have the option to be run asynchronously. This may cause
# some bugs and is considered experimental, however it has been tested without
# any apparent issues. Enable this if performance is absolutely crucial or if you
# are experiencing severe display lag.
async-display:
# If async display should always be used.
enabled: false
# Log errors that occur in async processing.
log-errors: true
# If the server is running under heavy load (below a certain TPS value), enable
# async display automatically. This can prevent some server crashes under load.
emergency:
# If emergency async should be used.
enabled: true
# Below this TPS value, emergency async display will be used.
cutoff: 18
# If players with a large amount of display packets should have their processing
# done asynchronously. This will help if a player is trying to crash the server
# by overloading the display system.
ratelimit:
# If rate limit async display should be used.
enabled: true
# The amount of window items packets per timeframe needed to enable async display
# for a specified player.
cutoff: 4
# The length of the timeframe in seconds.
# Cutoff 5, Timeframe 1 means that if there are more than 5 window items packets
# being sent per second for a player, then that player should have their packets
# handled asynchronously.
timeframe: 1

View File

@@ -0,0 +1 @@
# For internal storage use only, do not modify.

View File

@@ -2,7 +2,7 @@ name: eco
version: ${projectVersion} version: ${projectVersion}
main: com.willfp.eco.spigot.EcoHandler main: com.willfp.eco.spigot.EcoHandler
api-version: 1.16 api-version: 1.16
authors: [Auxilor] authors: [ Auxilor ]
website: willfp.com website: willfp.com
load: STARTUP load: STARTUP
depend: depend:
@@ -27,11 +27,23 @@ softdepend:
- HeadDatabase - HeadDatabase
- Multiverse-Inventories - Multiverse-Inventories
- Alice - Alice
- HolographicDisplays
- GHolo
- CMI
- Essentials
- Vault
- BentoBox
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'
- 'org.jetbrains.kotlin:kotlin-stdlib:1.5.31' - 'org.jetbrains.kotlin:kotlin-stdlib:1.5.31'
- 'net.kyori:adventure-platform-bukkit:4.0.0' - 'net.kyori:adventure-platform-bukkit:4.0.0'
- 'net.kyori:adventure-api:4.9.1' - 'net.kyori:adventure-api:4.9.2'
- 'net.kyori:adventure-text-serializer-gson:4.9.2' - 'net.kyori:adventure-text-serializer-gson:4.9.2'
- 'net.kyori:adventure-text-serializer-legacy:4.8.1' - 'net.kyori:adventure-text-serializer-legacy:4.9.2'
- 'org.jetbrains.kotlin:kotlin-stdlib:1.5.21'
- 'org.jetbrains.exposed:exposed-core:0.35.1'
- 'org.jetbrains.exposed:exposed-dao:0.35.1'
- 'org.jetbrains.exposed:exposed-jdbc:0.35.1'
- 'mysql:mysql-connector-java:8.0.25'
- 'com.google.guava:guava:31.0.1-jre'

View File

@@ -0,0 +1,7 @@
package com.willfp.eco.proxy
import com.willfp.eco.core.proxy.AbstractProxy
interface TPSProxy : AbstractProxy {
fun getTPS(): Double
}

View File

@@ -1,2 +1,2 @@
version = 6.11.2 version = 6.13.0
plugin-name = eco plugin-name = eco

BIN
lib/CMIAPI8.7.8.2.jar Normal file

Binary file not shown.

BIN
lib/CMILib1.0.4.1.jar Normal file

Binary file not shown.

BIN
lib/GHolo.jar Normal file

Binary file not shown.