Mirror von
https://github.com/TheSilentPro/HeadDB.git
synchronisiert 2024-12-26 19:02:39 +01:00
lots of improvements and bugfixes.
Dieser Commit ist enthalten in:
Ursprung
7ef5e30694
Commit
e4691102ae
22
pom.xml
22
pom.xml
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>tsp.headdb</groupId>
|
<groupId>tsp.headdb</groupId>
|
||||||
<artifactId>HeadDB</artifactId>
|
<artifactId>HeadDB</artifactId>
|
||||||
<version>5.0.0-rc.7</version>
|
<version>5.0.0-rc.8</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>HeadDB</name>
|
<name>HeadDB</name>
|
||||||
@ -55,13 +55,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>spigot-api</artifactId>
|
||||||
<version>1.20.1-R0.1-SNAPSHOT</version>
|
<version>1.20.2-R0.1-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.mojang</groupId>
|
<groupId>com.mojang</groupId>
|
||||||
<artifactId>authlib</artifactId>
|
<artifactId>authlib</artifactId>
|
||||||
<version>1.5.21</version>
|
<version>4.0.43</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -75,20 +75,26 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.TheSilentPro</groupId>
|
<groupId>com.github.TheSilentPro</groupId>
|
||||||
<artifactId>NexusLib</artifactId>
|
<artifactId>NexusLib</artifactId>
|
||||||
<version>c01a0a0a7d</version>
|
<version>9d8b16b770</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.TheSilentPro</groupId>
|
<groupId>com.github.TheSilentPro</groupId>
|
||||||
<artifactId>Warehouse</artifactId>
|
<artifactId>Warehouse</artifactId>
|
||||||
<version>882b42fc75</version>
|
<version>b228e4f8b1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.wesjd</groupId>
|
<groupId>net.wesjd</groupId>
|
||||||
<artifactId>anvilgui</artifactId>
|
<artifactId>anvilgui</artifactId>
|
||||||
<version>1.7.0-SNAPSHOT</version>
|
<version>1.9.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.TheSilentPro</groupId>
|
||||||
|
<artifactId>HelperLite</artifactId>
|
||||||
|
<version>775582f23b</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Soft Dependencies -->
|
<!-- Soft Dependencies -->
|
||||||
|
<!--suppress VulnerableLibrariesLocal -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.MilkBowl</groupId>
|
<groupId>com.github.MilkBowl</groupId>
|
||||||
<artifactId>VaultAPI</artifactId>
|
<artifactId>VaultAPI</artifactId>
|
||||||
@ -98,7 +104,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>me.clip</groupId>
|
<groupId>me.clip</groupId>
|
||||||
<artifactId>placeholderapi</artifactId>
|
<artifactId>placeholderapi</artifactId>
|
||||||
<version>2.11.1</version>
|
<version>2.11.5</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@ -183,7 +189,7 @@
|
|||||||
<additionalDependency>
|
<additionalDependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>spigot-api</artifactId>
|
||||||
<version>1.20.1-R0.1-SNAPSHOT</version>
|
<version>1.20.2-R0.1-SNAPSHOT</version>
|
||||||
</additionalDependency>
|
</additionalDependency>
|
||||||
</additionalDependencies>
|
</additionalDependencies>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
@ -7,17 +7,25 @@ import tsp.headdb.core.economy.VaultProvider;
|
|||||||
import tsp.headdb.core.storage.Storage;
|
import tsp.headdb.core.storage.Storage;
|
||||||
import tsp.headdb.core.task.UpdateTask;
|
import tsp.headdb.core.task.UpdateTask;
|
||||||
import tsp.headdb.core.util.HeadDBLogger;
|
import tsp.headdb.core.util.HeadDBLogger;
|
||||||
|
import tsp.helperlite.HelperLite;
|
||||||
|
import tsp.helperlite.Schedulers;
|
||||||
|
import tsp.helperlite.scheduler.promise.Promise;
|
||||||
|
import tsp.helperlite.scheduler.task.Task;
|
||||||
import tsp.nexuslib.NexusPlugin;
|
import tsp.nexuslib.NexusPlugin;
|
||||||
import tsp.nexuslib.inventory.PaneListener;
|
import tsp.nexuslib.inventory.PaneListener;
|
||||||
import tsp.nexuslib.localization.TranslatableLocalization;
|
import tsp.nexuslib.localization.TranslatableLocalization;
|
||||||
import tsp.nexuslib.util.PluginUtils;
|
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class HeadDB extends NexusPlugin {
|
public class HeadDB extends NexusPlugin {
|
||||||
|
|
||||||
@ -27,22 +35,27 @@ public class HeadDB extends NexusPlugin {
|
|||||||
private Storage storage;
|
private Storage storage;
|
||||||
private BasicEconomyProvider economyProvider;
|
private BasicEconomyProvider economyProvider;
|
||||||
private CommandManager commandManager;
|
private CommandManager commandManager;
|
||||||
|
private Task updateTask;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart(NexusPlugin nexusPlugin) {
|
public void onStart(NexusPlugin nexusPlugin) {
|
||||||
instance = this;
|
instance = this;
|
||||||
|
HelperLite.init(this);
|
||||||
|
|
||||||
instance.saveDefaultConfig();
|
instance.saveDefaultConfig();
|
||||||
instance.logger = new HeadDBLogger(getConfig().getBoolean("debug"));
|
instance.logger = new HeadDBLogger(getConfig().getBoolean("debug"));
|
||||||
instance.logger.info("Loading HeadDB - " + instance.getDescription().getVersion());
|
instance.logger.info("Loading HeadDB - " + instance.getDescription().getVersion());
|
||||||
|
|
||||||
new UpdateTask(getConfig().getLong("refresh", 86400L)).schedule(this);
|
|
||||||
instance.logger.info("Loaded " + loadLocalization() + " languages!");
|
instance.logger.info("Loaded " + loadLocalization() + " languages!");
|
||||||
|
|
||||||
instance.initStorage();
|
instance.initStorage();
|
||||||
instance.initEconomy();
|
instance.initEconomy();
|
||||||
|
|
||||||
|
startUpdateTask();
|
||||||
|
|
||||||
new PaneListener(this);
|
new PaneListener(this);
|
||||||
|
|
||||||
|
// TODO: Commands helperlite
|
||||||
instance.commandManager = new CommandManager();
|
instance.commandManager = new CommandManager();
|
||||||
loadCommands();
|
loadCommands();
|
||||||
|
|
||||||
@ -66,8 +79,38 @@ public class HeadDB extends NexusPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateTask.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startUpdateTask() {
|
||||||
|
updateTask = Schedulers.builder()
|
||||||
|
.async()
|
||||||
|
.every(getConfig().getLong("refresh", 86400L), TimeUnit.SECONDS)
|
||||||
|
.run(new UpdateTask());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureLatestVersion() {
|
||||||
|
Promise.start().thenApplyAsync(a -> {
|
||||||
|
try {
|
||||||
|
URLConnection connection = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + 84967).openConnection();
|
||||||
|
connection.setConnectTimeout(5000);
|
||||||
|
connection.setRequestProperty("User-Agent", this.getName() + "-VersionChecker");
|
||||||
|
|
||||||
|
return new BufferedReader(new InputStreamReader(connection.getInputStream())).readLine().equals(this.getDescription().getVersion());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}).thenAcceptAsync(latest -> {
|
||||||
|
if (latest) {
|
||||||
|
instance.logger.warning("There is a new update available for HeadDB on spigot!");
|
||||||
|
instance.logger.warning("Download: https://www.spigotmc.org/resources/84967");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loaders
|
||||||
|
|
||||||
private void initMetrics() {
|
private void initMetrics() {
|
||||||
Metrics metrics = new Metrics(this, 9152);
|
Metrics metrics = new Metrics(this, 9152);
|
||||||
|
|
||||||
@ -80,19 +123,8 @@ public class HeadDB extends NexusPlugin {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureLatestVersion() {
|
|
||||||
PluginUtils.isLatestVersion(this, 84967, latest -> {
|
|
||||||
if (Boolean.FALSE.equals(latest)) {
|
|
||||||
instance.logger.warning("There is a new update available for HeadDB on spigot!");
|
|
||||||
instance.logger.warning("Download: https://www.spigotmc.org/resources/84967");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loaders
|
|
||||||
|
|
||||||
private void initStorage() {
|
private void initStorage() {
|
||||||
storage = new Storage(getConfig().getInt("storage.threads"));
|
storage = new Storage();
|
||||||
storage.getPlayerStorage().init();
|
storage.getPlayerStorage().init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +188,10 @@ public class HeadDB extends NexusPlugin {
|
|||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
|
|
||||||
|
public Optional<Task> getUpdateTask() {
|
||||||
|
return Optional.ofNullable(updateTask);
|
||||||
|
}
|
||||||
|
|
||||||
public Storage getStorage() {
|
public Storage getStorage() {
|
||||||
return storage;
|
return storage;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import org.bukkit.configuration.file.YamlConfiguration;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import tsp.headdb.core.storage.HeadDBThreadFactory;
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@ -132,8 +133,7 @@ class Metrics {
|
|||||||
/** The version of the Metrics class. */
|
/** The version of the Metrics class. */
|
||||||
public static final String METRICS_VERSION = "3.0.0";
|
public static final String METRICS_VERSION = "3.0.0";
|
||||||
|
|
||||||
private static final ScheduledExecutorService scheduler =
|
private static final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(HeadDBThreadFactory.FACTORY);
|
||||||
Executors.newScheduledThreadPool(1, task -> new Thread(task, "bStats-Metrics"));
|
|
||||||
|
|
||||||
private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s";
|
private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s";
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import tsp.headdb.implementation.head.Head;
|
|||||||
import tsp.headdb.implementation.head.HeadDatabase;
|
import tsp.headdb.implementation.head.HeadDatabase;
|
||||||
import tsp.headdb.implementation.head.LocalHead;
|
import tsp.headdb.implementation.head.LocalHead;
|
||||||
import tsp.headdb.implementation.requester.HeadProvider;
|
import tsp.headdb.implementation.requester.HeadProvider;
|
||||||
|
import tsp.helperlite.scheduler.promise.Promise;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -163,14 +164,16 @@ public final class HeadAPI {
|
|||||||
* @return {@link Set<Head> Favorite Heads}
|
* @return {@link Set<Head> Favorite Heads}
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public static List<Head> getFavoriteHeads(UUID player) {
|
public static Promise<List<Head>> getFavoriteHeads(UUID player) {
|
||||||
List<Head> result = new ArrayList<>();
|
return Promise.supplyingAsync(() -> {
|
||||||
Optional<PlayerData> data = HeadDB.getInstance().getStorage().getPlayerStorage().get(player);
|
List<Head> result = new ArrayList<>();
|
||||||
data.ifPresent(playerData -> playerData.favorites()
|
Optional<PlayerData> data = HeadDB.getInstance().getStorage().getPlayerStorage().get(player);
|
||||||
.forEach(texture -> getHeadByTexture(texture)
|
data.ifPresent(playerData -> playerData.favorites()
|
||||||
.ifPresent(result::add))
|
.forEach(texture -> getHeadByTexture(texture)
|
||||||
);
|
.ifPresent(result::add))
|
||||||
return result;
|
);
|
||||||
|
return result;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package tsp.headdb.core.command;
|
package tsp.headdb.core.command;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import net.wesjd.anvilgui.AnvilGUI;
|
import net.wesjd.anvilgui.AnvilGUI;
|
||||||
import net.wesjd.anvilgui.AnvilGUI.Builder;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
@ -24,10 +22,7 @@ import tsp.nexuslib.util.StringUtils;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class CommandMain extends HeadDBCommand implements CommandExecutor, TabCompleter {
|
public class CommandMain extends HeadDBCommand implements CommandExecutor, TabCompleter {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package tsp.headdb.core.command;
|
package tsp.headdb.core.command;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import tsp.headdb.HeadDB;
|
import tsp.headdb.HeadDB;
|
||||||
import tsp.headdb.core.api.HeadAPI;
|
import tsp.headdb.core.api.HeadAPI;
|
||||||
|
import tsp.headdb.implementation.head.HeadResult;
|
||||||
|
import tsp.helperlite.scheduler.promise.Promise;
|
||||||
|
|
||||||
public class CommandUpdate extends SubCommand {
|
public class CommandUpdate extends SubCommand {
|
||||||
|
|
||||||
@ -14,10 +15,14 @@ public class CommandUpdate extends SubCommand {
|
|||||||
@Override
|
@Override
|
||||||
public void handle(CommandSender sender, String[] args) {
|
public void handle(CommandSender sender, String[] args) {
|
||||||
getLocalization().sendMessage(sender, "updateDatabase");
|
getLocalization().sendMessage(sender, "updateDatabase");
|
||||||
HeadAPI.getDatabase().update((time, result) -> {
|
try (Promise<HeadResult> promise = HeadAPI.getDatabase().update()) {
|
||||||
HeadDB.getInstance().getLog().debug("Database Updated! Heads: " + result.values().size() + " | Took: " + time + "ms");
|
promise.thenAcceptSync(result -> {
|
||||||
Bukkit.getScheduler().runTask(HeadDB.getInstance(), () -> getLocalization().sendMessage(sender, "updateDatabaseDone", msg -> msg.replace("%size%", String.valueOf(result.values().size()))));
|
HeadDB.getInstance().getLog().debug("Database Updated! Heads: " + result.heads().values().size() + " | Took: " + result.elapsed() + "ms");
|
||||||
});
|
getLocalization().sendMessage(sender, "updateDatabaseDone", msg -> msg.replace("%size%", String.valueOf(result.heads().values().size())));
|
||||||
|
});
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
package tsp.headdb.core.economy;
|
package tsp.headdb.core.economy;
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import tsp.helperlite.scheduler.promise.Promise;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
public interface BasicEconomyProvider {
|
public interface BasicEconomyProvider {
|
||||||
|
|
||||||
CompletableFuture<Boolean> canPurchase(Player player, BigDecimal cost);
|
Promise<Boolean> canPurchase(Player player, BigDecimal cost);
|
||||||
|
|
||||||
CompletableFuture<Boolean> withdraw(Player player, BigDecimal amount);
|
Promise<Boolean> withdraw(Player player, BigDecimal amount);
|
||||||
|
|
||||||
default CompletableFuture<Boolean> purchase(Player player, BigDecimal amount) {
|
default Promise<Boolean> purchase(Player player, BigDecimal amount) {
|
||||||
return canPurchase(player, amount).thenCompose(result -> result ? withdraw(player, amount) : CompletableFuture.completedFuture(false));
|
return canPurchase(player, amount).thenComposeAsync(result -> result ? withdraw(player, amount) : Promise.completed(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
@ -5,24 +5,24 @@ import org.bukkit.Bukkit;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||||
import tsp.headdb.HeadDB;
|
import tsp.headdb.HeadDB;
|
||||||
|
import tsp.helperlite.scheduler.promise.Promise;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
public class VaultProvider implements BasicEconomyProvider {
|
public class VaultProvider implements BasicEconomyProvider {
|
||||||
|
|
||||||
private Economy economy;
|
private Economy economy;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Boolean> canPurchase(Player player, BigDecimal cost) {
|
public Promise<Boolean> canPurchase(Player player, BigDecimal cost) {
|
||||||
double effectiveCost = cost.doubleValue();
|
double effectiveCost = cost.doubleValue();
|
||||||
return CompletableFuture.supplyAsync(() -> economy.has(player, effectiveCost >= 0 ? effectiveCost : 0));
|
return Promise.supplyingAsync(() -> economy.has(player, effectiveCost >= 0 ? effectiveCost : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Boolean> withdraw(Player player, BigDecimal amount) {
|
public Promise<Boolean> withdraw(Player player, BigDecimal amount) {
|
||||||
double effectiveCost = amount.doubleValue();
|
double effectiveCost = amount.doubleValue();
|
||||||
return CompletableFuture.supplyAsync(() -> economy.withdrawPlayer(player, effectiveCost >= 0 ? effectiveCost : 0).transactionSuccess());
|
return Promise.supplyingAsync(() -> economy.withdrawPlayer(player, effectiveCost >= 0 ? effectiveCost : 0).transactionSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ public class PlayerStorage extends SerializableFileDataManager<HashSet<PlayerDat
|
|||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
load().whenComplete((data, ex) -> {
|
load().whenComplete((data, ex) -> {
|
||||||
for (PlayerData entry : data) {
|
for (PlayerData entry : data.orElse(new HashSet<>())) {
|
||||||
players.put(entry.uniqueId(), entry);
|
players.put(entry.uniqueId(), entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package tsp.headdb.core.storage;
|
package tsp.headdb.core.storage;
|
||||||
|
|
||||||
import tsp.headdb.HeadDB;
|
import tsp.headdb.HeadDB;
|
||||||
|
import tsp.helperlite.Schedulers;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@ -11,8 +12,8 @@ public class Storage {
|
|||||||
private final Executor executor;
|
private final Executor executor;
|
||||||
private final PlayerStorage playerStorage;
|
private final PlayerStorage playerStorage;
|
||||||
|
|
||||||
public Storage(int threads) {
|
public Storage() {
|
||||||
executor = Executors.newFixedThreadPool(threads, HeadDBThreadFactory.FACTORY);
|
executor = Schedulers.async();
|
||||||
validateDataDirectory();
|
validateDataDirectory();
|
||||||
playerStorage = new PlayerStorage(HeadDB.getInstance(), this);
|
playerStorage = new PlayerStorage(HeadDB.getInstance(), this);
|
||||||
}
|
}
|
||||||
|
@ -4,51 +4,44 @@ import org.bukkit.Bukkit;
|
|||||||
import tsp.headdb.HeadDB;
|
import tsp.headdb.HeadDB;
|
||||||
import tsp.headdb.core.api.HeadAPI;
|
import tsp.headdb.core.api.HeadAPI;
|
||||||
import tsp.headdb.core.api.events.AsyncHeadsFetchedEvent;
|
import tsp.headdb.core.api.events.AsyncHeadsFetchedEvent;
|
||||||
|
import tsp.headdb.implementation.category.Category;
|
||||||
import tsp.headdb.implementation.head.Head;
|
import tsp.headdb.implementation.head.Head;
|
||||||
import tsp.nexuslib.task.Task;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class UpdateTask implements Task {
|
public class UpdateTask implements Runnable {
|
||||||
|
|
||||||
private final long interval;
|
|
||||||
|
|
||||||
public UpdateTask(long interval) {
|
|
||||||
this.interval = interval;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
HeadAPI.getDatabase().update((time, heads) -> {
|
HeadAPI.getDatabase().update().thenAcceptAsync(result -> {
|
||||||
int size = 0;
|
HeadDB instance = HeadDB.getInstance();
|
||||||
for (List<Head> list : heads.values()) {
|
|
||||||
for (Head ignored : list) {
|
|
||||||
size++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String providerName = HeadAPI.getDatabase().getRequester().getProvider().name();
|
String providerName = HeadAPI.getDatabase().getRequester().getProvider().name();
|
||||||
|
|
||||||
HeadDB.getInstance().getLog().debug("Fetched: " + size + " Heads | Provider: " + providerName + " | Time: " + time + "ms (" + TimeUnit.MILLISECONDS.toSeconds(time) + "s)");
|
instance.getLog().debug("Fetched: " + getHeadsCount(result.heads()) + " Heads | Provider: " + providerName + " | Time: " + result.elapsed() + "ms (" + TimeUnit.MILLISECONDS.toSeconds(result.elapsed()) + "s)");
|
||||||
Bukkit.getPluginManager().callEvent(
|
Bukkit.getPluginManager().callEvent(
|
||||||
new AsyncHeadsFetchedEvent(
|
new AsyncHeadsFetchedEvent(
|
||||||
heads,
|
result.heads(),
|
||||||
providerName,
|
providerName,
|
||||||
time));
|
result.elapsed()));
|
||||||
|
|
||||||
|
instance.getStorage().getPlayerStorage().backup();
|
||||||
|
instance.getUpdateTask().ifPresentOrElse(task -> {
|
||||||
|
instance.getLog().debug("UpdateTask completed! Times ran: " + task.getTimesRan());
|
||||||
|
}, () -> instance.getLog().debug("Initial UpdateTask completed!"));
|
||||||
});
|
});
|
||||||
HeadDB.getInstance().getStorage().getPlayerStorage().backup();
|
|
||||||
HeadDB.getInstance().getLog().debug("UpdateTask finished!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private int getHeadsCount(Map<Category, List<Head>> heads) {
|
||||||
public long getRepeatInterval() {
|
int n = 0;
|
||||||
return interval;
|
for (List<Head> list : heads.values()) {
|
||||||
}
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
return n;
|
||||||
public boolean isAsync() {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,63 +1,12 @@
|
|||||||
package tsp.headdb.core.util;
|
package tsp.headdb.core.util;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import tsp.nexuslib.logger.NexusLogger;
|
||||||
import tsp.nexuslib.util.StringUtils;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class HeadDBLogger {
|
public class HeadDBLogger extends NexusLogger {
|
||||||
|
|
||||||
private final boolean debug;
|
|
||||||
|
|
||||||
public HeadDBLogger(boolean debug) {
|
public HeadDBLogger(boolean debug) {
|
||||||
this.debug = debug;
|
super("HeadDB", debug);
|
||||||
}
|
|
||||||
public void info(String message) {
|
|
||||||
this.log(LogLevel.INFO, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void warning(String message) {
|
|
||||||
this.log(LogLevel.WARNING, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void error(String message) {
|
|
||||||
this.log(LogLevel.ERROR, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void debug(String message) {
|
|
||||||
this.log(LogLevel.DEBUG, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void trace(String message) {
|
|
||||||
this.log(LogLevel.TRACE, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void log(LogLevel level, String message) {
|
|
||||||
if ((level == LogLevel.DEBUG || level == LogLevel.TRACE) && !debug) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Bukkit.getConsoleSender().sendMessage(StringUtils.colorize("&cHeadDB &8>> " + level.getColor() + "[" + level.name() + "]: " + message));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDebug() {
|
|
||||||
return this.debug;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum LogLevel {
|
|
||||||
INFO,
|
|
||||||
WARNING,
|
|
||||||
ERROR,
|
|
||||||
DEBUG,
|
|
||||||
TRACE;
|
|
||||||
|
|
||||||
public String getColor() {
|
|
||||||
return switch (this) {
|
|
||||||
case INFO -> "\u001b[32m";
|
|
||||||
case WARNING -> "\u001b[33m";
|
|
||||||
case ERROR -> "\u001b[31m";
|
|
||||||
case DEBUG -> "\u001b[36m";
|
|
||||||
case TRACE -> "\u001b[35m";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,15 +10,22 @@ import org.bukkit.configuration.ConfigurationSection;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.inventory.meta.SkullMeta;
|
||||||
|
import org.bukkit.profile.PlayerProfile;
|
||||||
|
import org.bukkit.profile.PlayerTextures;
|
||||||
import tsp.headdb.HeadDB;
|
import tsp.headdb.HeadDB;
|
||||||
import tsp.headdb.core.api.HeadAPI;
|
import tsp.headdb.core.api.HeadAPI;
|
||||||
import tsp.headdb.core.economy.BasicEconomyProvider;
|
import tsp.headdb.core.economy.BasicEconomyProvider;
|
||||||
import tsp.headdb.core.hook.Hooks;
|
import tsp.headdb.core.hook.Hooks;
|
||||||
import tsp.headdb.implementation.category.Category;
|
import tsp.headdb.implementation.category.Category;
|
||||||
import tsp.headdb.implementation.head.Head;
|
import tsp.headdb.implementation.head.Head;
|
||||||
|
import tsp.helperlite.scheduler.promise.Promise;
|
||||||
|
import tsp.nexuslib.builder.ItemBuilder;
|
||||||
import tsp.nexuslib.inventory.Button;
|
import tsp.nexuslib.inventory.Button;
|
||||||
import tsp.nexuslib.inventory.PagedPane;
|
import tsp.nexuslib.inventory.PagedPane;
|
||||||
import tsp.nexuslib.inventory.Pane;
|
import tsp.nexuslib.inventory.Pane;
|
||||||
|
import tsp.nexuslib.localization.TranslatableLocalization;
|
||||||
|
import tsp.nexuslib.server.ServerVersion;
|
||||||
import tsp.nexuslib.util.StringUtils;
|
import tsp.nexuslib.util.StringUtils;
|
||||||
import tsp.nexuslib.util.Validate;
|
import tsp.nexuslib.util.Validate;
|
||||||
|
|
||||||
@ -27,8 +34,9 @@ import javax.annotation.Nullable;
|
|||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
|
|
||||||
@ -108,31 +116,36 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void openFavoritesMenu(Player player) {
|
public static void openFavoritesMenu(Player player) {
|
||||||
List<Head> heads = HeadAPI.getFavoriteHeads(player.getUniqueId());
|
try (Promise<List<Head>> promise = HeadAPI.getFavoriteHeads(player.getUniqueId())) {
|
||||||
PagedPane main = Utils.createPaged(player, Utils.translateTitle(HeadDB.getInstance().getLocalization().getMessage(player.getUniqueId(), "menu.main.favorites.name").orElse("Favorites"), heads.size(), "Favorites"));
|
promise.thenAcceptSync(heads -> {
|
||||||
for (Head head : heads) {
|
PagedPane main = Utils.createPaged(player, Utils.translateTitle(HeadDB.getInstance().getLocalization().getMessage(player.getUniqueId(), "menu.main.favorites.name").orElse("Favorites"), heads.size(), "Favorites"));
|
||||||
main.addButton(new Button(head.getItem(player.getUniqueId()), fe -> {
|
for (Head head : heads) {
|
||||||
if (!player.hasPermission("headdb.favorites")) {
|
main.addButton(new Button(head.getItem(player.getUniqueId()), fe -> {
|
||||||
HeadDB.getInstance().getLocalization().sendMessage(player, "noAccessFavorites");
|
if (!player.hasPermission("headdb.favorites")) {
|
||||||
return;
|
HeadDB.getInstance().getLocalization().sendMessage(player, "noAccessFavorites");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fe.isLeftClick()) {
|
||||||
|
int amount = 1;
|
||||||
|
if (fe.isShiftClick()) {
|
||||||
|
amount = 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.purchase(player, head, amount);
|
||||||
|
} else if (fe.isRightClick()) {
|
||||||
|
HeadDB.getInstance().getStorage().getPlayerStorage().removeFavorite(player.getUniqueId(), head.getTexture());
|
||||||
|
HeadDB.getInstance().getLocalization().sendMessage(player, "removedFavorite", msg -> msg.replace("%name%", head.getName()));
|
||||||
|
openFavoritesMenu(player);
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fe.isLeftClick()) {
|
main.open(player);
|
||||||
int amount = 1;
|
});
|
||||||
if (fe.isShiftClick()) {
|
} catch (Exception ex) {
|
||||||
amount = 64;
|
ex.printStackTrace();
|
||||||
}
|
|
||||||
|
|
||||||
Utils.purchase(player, head, amount);
|
|
||||||
} else if (fe.isRightClick()) {
|
|
||||||
HeadDB.getInstance().getStorage().getPlayerStorage().removeFavorite(player.getUniqueId(), head.getTexture());
|
|
||||||
HeadDB.getInstance().getLocalization().sendMessage(player, "removedFavorite", msg -> msg.replace("%name%", head.getName()));
|
|
||||||
openFavoritesMenu(player);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main.open(player);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParametersAreNonnullByDefault
|
@ParametersAreNonnullByDefault
|
||||||
@ -166,10 +179,10 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CompletableFuture<Boolean> processPayment(Player player, Head head, int amount) {
|
private static Promise<Boolean> processPayment(Player player, Head head, int amount) {
|
||||||
Optional<BasicEconomyProvider> optional = HeadDB.getInstance().getEconomyProvider();
|
Optional<BasicEconomyProvider> optional = HeadDB.getInstance().getEconomyProvider();
|
||||||
if (optional.isEmpty()) {
|
if (optional.isEmpty()) {
|
||||||
return CompletableFuture.completedFuture(true); // No economy, the head is free
|
return Promise.completed(true); // No economy, the head is free
|
||||||
} else {
|
} else {
|
||||||
BigDecimal cost = BigDecimal.valueOf(HeadDB.getInstance().getConfig().getDouble("economy.cost." + head.getCategory().getName()) * amount);
|
BigDecimal cost = BigDecimal.valueOf(HeadDB.getInstance().getConfig().getDouble("economy.cost." + head.getCategory().getName()) * amount);
|
||||||
HeadDB.getInstance().getLocalization().sendMessage(player.getUniqueId(), "processPayment", msg -> msg
|
HeadDB.getInstance().getLocalization().sendMessage(player.getUniqueId(), "processPayment", msg -> msg
|
||||||
@ -177,8 +190,10 @@ public class Utils {
|
|||||||
.replace("%amount%", String.valueOf(amount))
|
.replace("%amount%", String.valueOf(amount))
|
||||||
.replace("%cost%", HeadDB.getInstance().getDecimalFormat().format(cost))
|
.replace("%cost%", HeadDB.getInstance().getDecimalFormat().format(cost))
|
||||||
);
|
);
|
||||||
return optional.get().purchase(player, cost).thenApply(success -> {
|
|
||||||
Bukkit.getScheduler().runTask(HeadDB.getInstance(), () -> {
|
try (Promise<Boolean> economyPromise = optional.get().purchase(player, cost)) {
|
||||||
|
// TODO: Might not need to be sync.
|
||||||
|
return economyPromise.thenApplySync((success) -> {
|
||||||
if (success) {
|
if (success) {
|
||||||
HeadDB.getInstance().getLocalization().sendMessage(player, "completePayment", msg -> msg
|
HeadDB.getInstance().getLocalization().sendMessage(player, "completePayment", msg -> msg
|
||||||
.replace("%name%", head.getName())
|
.replace("%name%", head.getName())
|
||||||
@ -186,46 +201,38 @@ public class Utils {
|
|||||||
} else {
|
} else {
|
||||||
HeadDB.getInstance().getLocalization().sendMessage(player, "invalidFunds", msg -> msg.replace("%name%", head.getName()));
|
HeadDB.getInstance().getLocalization().sendMessage(player, "invalidFunds", msg -> msg.replace("%name%", head.getName()));
|
||||||
}
|
}
|
||||||
|
return success;
|
||||||
});
|
});
|
||||||
return success;
|
} catch (Exception ex) {
|
||||||
|
HeadDB.getInstance().getLog().severe("Failed to process payment: " + ex.getMessage());
|
||||||
/* Note: Issues caused by sync call to async event but when run async above method fucks up.
|
return Promise.exceptionally(ex);
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(HeadDB.getInstance(), () -> {
|
}
|
||||||
HeadPurchaseEvent event = new HeadPurchaseEvent(player, head, cost, success);
|
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
*/
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void purchase(Player player, Head head, int amount) {
|
public static void purchase(Player player, Head head, int amount) {
|
||||||
processPayment(player, head, amount).whenComplete((success, ex) -> {
|
// Bukkit API - Has to be sync.
|
||||||
if (ex != null) {
|
try (Promise<Boolean> paymentPromise = processPayment(player, head, amount)) {
|
||||||
HeadDB.getInstance().getLog().error("Failed to purchase head '" + head.getName() + "' for player: " + player.getName());
|
paymentPromise.thenAcceptSync((success) -> {
|
||||||
ex.printStackTrace();
|
if (success) {
|
||||||
} else {
|
ItemStack item = head.getItem(player.getUniqueId());
|
||||||
// Bukkit API, therefore task is ran sync.
|
item.setAmount(amount);
|
||||||
Bukkit.getScheduler().runTask(HeadDB.getInstance(), () -> {
|
player.getInventory().addItem(item);
|
||||||
if (success) {
|
HeadDB.getInstance().getConfig().getStringList("commands.purchase").forEach(command -> {
|
||||||
ItemStack item = head.getItem(player.getUniqueId());
|
if (command.isEmpty()) {
|
||||||
item.setAmount(amount);
|
return;
|
||||||
player.getInventory().addItem(item);
|
|
||||||
HeadDB.getInstance().getConfig().getStringList("commands.purchase").forEach(command -> {
|
|
||||||
if (command.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Hooks.PAPI.enabled()) {
|
|
||||||
command = PlaceholderAPI.setPlaceholders(player, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
if (Hooks.PAPI.enabled()) {
|
||||||
|
command = PlaceholderAPI.setPlaceholders(player, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<String> getTexture(ItemStack head) {
|
public static Optional<String> getTexture(ItemStack head) {
|
||||||
@ -252,6 +259,51 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ItemStack asItem(UUID receiver, Head head) {
|
||||||
|
TranslatableLocalization localization = HeadDB.getInstance().getLocalization();
|
||||||
|
ItemStack item = new ItemBuilder(Material.PLAYER_HEAD)
|
||||||
|
.name(localization.getMessage(receiver, "menu.head.name").orElse("&e" + head.getName().toUpperCase(Locale.ROOT)).replace("%name%", head.getName()))
|
||||||
|
.setLore("&cID: " + head.getId(), "&7Tags: &e" + head.getTags())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
|
||||||
|
// if version < 1.20.1 use reflection, else (1.20.2+) use PlayerProfile because spigot bitches otherwise.
|
||||||
|
if (ServerVersion.getVersion().orElse(ServerVersion.v_1_20_1).isOlderThan(ServerVersion.v_1_20_2)) {
|
||||||
|
try {
|
||||||
|
GameProfile profile = new GameProfile(head.getUniqueId(), head.getName());
|
||||||
|
profile.getProperties().put("textures", new Property("textures", head.getTexture()));
|
||||||
|
|
||||||
|
//noinspection DataFlowIssue
|
||||||
|
Field profileField = meta.getClass().getDeclaredField("profile");
|
||||||
|
profileField.setAccessible(true);
|
||||||
|
profileField.set(meta, profile);
|
||||||
|
item.setItemMeta(meta);
|
||||||
|
} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException ex) {
|
||||||
|
//Log.error("Could not set skull owner for " + uuid.toString() + " | Stack Trace:");
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
PlayerProfile profile = Bukkit.createPlayerProfile(head.getUniqueId(), head.getName());
|
||||||
|
PlayerTextures textures = profile.getTextures();
|
||||||
|
String url = new String(Base64.getDecoder().decode(head.getTexture()));
|
||||||
|
textures.setSkin(new URL(url.substring("{\"textures\":{\"SKIN\":{\"url\":\"".length(), url.length() - "\"}}}".length())));
|
||||||
|
profile.setTextures(textures);
|
||||||
|
|
||||||
|
SkullMeta skullMeta = (SkullMeta) meta;
|
||||||
|
if (skullMeta != null) {
|
||||||
|
skullMeta.setOwnerProfile(profile);
|
||||||
|
}
|
||||||
|
item.setItemMeta(skullMeta);
|
||||||
|
} catch (MalformedURLException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
public static int resolveInt(String raw) {
|
public static int resolveInt(String raw) {
|
||||||
try {
|
try {
|
||||||
return Integer.parseInt(raw);
|
return Integer.parseInt(raw);
|
||||||
|
@ -1,19 +1,11 @@
|
|||||||
package tsp.headdb.implementation.head;
|
package tsp.headdb.implementation.head;
|
||||||
|
|
||||||
import com.mojang.authlib.GameProfile;
|
|
||||||
import com.mojang.authlib.properties.Property;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import tsp.headdb.core.util.Utils;
|
||||||
import tsp.headdb.HeadDB;
|
|
||||||
import tsp.headdb.implementation.category.Category;
|
import tsp.headdb.implementation.category.Category;
|
||||||
import tsp.nexuslib.builder.ItemBuilder;
|
|
||||||
import tsp.nexuslib.localization.TranslatableLocalization;
|
|
||||||
import tsp.nexuslib.util.Validate;
|
import tsp.nexuslib.util.Validate;
|
||||||
|
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class Head {
|
public class Head {
|
||||||
@ -47,26 +39,7 @@ public class Head {
|
|||||||
|
|
||||||
public ItemStack getItem(UUID receiver) {
|
public ItemStack getItem(UUID receiver) {
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
TranslatableLocalization localization = HeadDB.getInstance().getLocalization();
|
item = Utils.asItem(receiver, this);
|
||||||
item = new ItemBuilder(Material.PLAYER_HEAD)
|
|
||||||
.name(localization.getMessage(receiver, "menu.head.name").orElse("&e" + name.toUpperCase(Locale.ROOT)).replace("%name%", name))
|
|
||||||
.setLore("&cID: " + id, "&7Tags: &e" + tags)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
ItemMeta meta = item.getItemMeta();
|
|
||||||
GameProfile profile = new GameProfile(uniqueId, name);
|
|
||||||
profile.getProperties().put("textures", new Property("textures", texture));
|
|
||||||
try {
|
|
||||||
//noinspection DataFlowIssue
|
|
||||||
Field profileField = meta.getClass().getDeclaredField("profile");
|
|
||||||
profileField.setAccessible(true);
|
|
||||||
profileField.set(meta, profile);
|
|
||||||
} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException ex) {
|
|
||||||
//Log.error("Could not set skull owner for " + uuid.toString() + " | Stack Trace:");
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
item.setItemMeta(meta);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return item.clone(); // Return clone that changes are not reflected
|
return item.clone(); // Return clone that changes are not reflected
|
||||||
|
@ -1,53 +1,59 @@
|
|||||||
package tsp.headdb.implementation.head;
|
package tsp.headdb.implementation.head;
|
||||||
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.bukkit.scheduler.BukkitScheduler;
|
|
||||||
import tsp.headdb.implementation.category.Category;
|
import tsp.headdb.implementation.category.Category;
|
||||||
import tsp.headdb.implementation.requester.HeadProvider;
|
import tsp.headdb.implementation.requester.HeadProvider;
|
||||||
import tsp.headdb.implementation.requester.Requester;
|
import tsp.headdb.implementation.requester.Requester;
|
||||||
|
import tsp.helperlite.scheduler.promise.Promise;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
|
|
||||||
public class HeadDatabase {
|
public class HeadDatabase {
|
||||||
|
|
||||||
private final JavaPlugin plugin;
|
private final JavaPlugin plugin;
|
||||||
private final BukkitScheduler scheduler;
|
|
||||||
private final Requester requester;
|
private final Requester requester;
|
||||||
private final ConcurrentHashMap<Category, List<Head>> heads;
|
private final ConcurrentHashMap<Category, List<Head>> heads;
|
||||||
private long timestamp;
|
private long timestamp;
|
||||||
|
|
||||||
public HeadDatabase(JavaPlugin plugin, HeadProvider provider) {
|
public HeadDatabase(JavaPlugin plugin, HeadProvider provider) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.scheduler = plugin.getServer().getScheduler();
|
|
||||||
this.requester = new Requester(plugin, provider);
|
this.requester = new Requester(plugin, provider);
|
||||||
this.heads = new ConcurrentHashMap<>();
|
this.heads = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// Fill empty
|
||||||
|
for (Category cat : Category.VALUES) {
|
||||||
|
heads.put(cat, new ArrayList<>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Category, List<Head>> getHeads() {
|
public Map<Category, List<Head>> getHeads() {
|
||||||
return heads;
|
return heads;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getHeadsNoCache(BiConsumer<Long, Map<Category, List<Head>>> heads) {
|
public Promise<HeadResult> getHeadsNoCache() {
|
||||||
getScheduler().runTaskAsynchronously(plugin, () -> {
|
return Promise.supplyingAsync(() -> {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
Map<Category, List<Head>> result = new HashMap<>();
|
Map<Category, List<Head>> result = new HashMap<>();
|
||||||
for (Category category : Category.VALUES) {
|
for (Category category : Category.VALUES) {
|
||||||
requester.fetchAndResolve(category, response -> result.put(category, response));
|
result.put(category, requester.fetchAndResolve(category));
|
||||||
}
|
}
|
||||||
|
|
||||||
heads.accept(System.currentTimeMillis() - start, result);
|
return new HeadResult(System.currentTimeMillis() - start, result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(BiConsumer<Long, Map<Category, List<Head>>> fetched) {
|
public Promise<HeadResult> update() {
|
||||||
getHeadsNoCache((elapsed, result) -> {
|
return Promise.start()
|
||||||
heads.putAll(result);
|
.thenComposeAsync(compose -> getHeadsNoCache())
|
||||||
timestamp = System.currentTimeMillis();
|
.thenApplyAsync(result -> {
|
||||||
fetched.accept(elapsed, result);
|
heads.clear();
|
||||||
|
heads.putAll(result.heads());
|
||||||
|
timestamp = System.currentTimeMillis();
|
||||||
|
return result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,10 +65,6 @@ public class HeadDatabase {
|
|||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BukkitScheduler getScheduler() {
|
|
||||||
return scheduler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Requester getRequester() {
|
public Requester getRequester() {
|
||||||
return requester;
|
return requester;
|
||||||
}
|
}
|
||||||
|
11
src/main/java/tsp/headdb/implementation/head/HeadResult.java
Normale Datei
11
src/main/java/tsp/headdb/implementation/head/HeadResult.java
Normale Datei
@ -0,0 +1,11 @@
|
|||||||
|
package tsp.headdb.implementation.head;
|
||||||
|
|
||||||
|
import tsp.headdb.implementation.category.Category;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author TheSilentPro (Silent)
|
||||||
|
*/
|
||||||
|
public record HeadResult(long elapsed, Map<Category, List<Head>> heads) {}
|
@ -18,8 +18,14 @@ import java.net.URL;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responsible for requesting heads from providers.
|
||||||
|
*
|
||||||
|
* @author TheSilentPro
|
||||||
|
* @see tsp.headdb.core.api.HeadAPI
|
||||||
|
* @see tsp.headdb.implementation.head.HeadDatabase
|
||||||
|
*/
|
||||||
public class Requester {
|
public class Requester {
|
||||||
|
|
||||||
private final JavaPlugin plugin;
|
private final JavaPlugin plugin;
|
||||||
@ -30,51 +36,52 @@ public class Requester {
|
|||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fetchAndResolve(Category category, Consumer<List<Head>> heads) {
|
public List<Head> fetchAndResolve(Category category) {
|
||||||
try {
|
try {
|
||||||
fetch(category, response -> {
|
Response response = fetch(category);
|
||||||
List<Head> result = new ArrayList<>();
|
List<Head> result = new ArrayList<>();
|
||||||
if (response.code() != 200) {
|
if (response.code() != 200) {
|
||||||
heads.accept(result);
|
return result;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
JsonArray main = JsonParser.parseString(response.response()).getAsJsonArray();
|
JsonArray main = JsonParser.parseString(response.response()).getAsJsonArray();
|
||||||
for (JsonElement entry : main) {
|
for (JsonElement entry : main) {
|
||||||
JsonObject obj = entry.getAsJsonObject();
|
JsonObject obj = entry.getAsJsonObject();
|
||||||
int id = obj.get("id").getAsInt();
|
int id = obj.get("id").getAsInt();
|
||||||
|
|
||||||
if (plugin.getConfig().contains("blockedHeads.ids")) {
|
if (plugin.getConfig().contains("blockedHeads.ids")) {
|
||||||
List<Integer> blockedIds = plugin.getConfig().getIntegerList("blockedHeads.ids");
|
List<Integer> blockedIds = plugin.getConfig().getIntegerList("blockedHeads.ids");
|
||||||
if (blockedIds.contains(id)) {
|
if (blockedIds.contains(id)) {
|
||||||
HeadDB.getInstance().getLog().debug("Skipped blocked head: " + obj.get("name").getAsString() + "(" + id + ")");
|
HeadDB.getInstance().getLog().debug("Skipped blocked head: " + obj.get("name").getAsString() + "(" + id + ")");
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result.add(new Head(
|
|
||||||
id,
|
|
||||||
Utils.validateUniqueId(obj.get("uuid").getAsString()).orElse(UUID.randomUUID()),
|
|
||||||
obj.get("name").getAsString(),
|
|
||||||
obj.get("value").getAsString(),
|
|
||||||
obj.get("tags").getAsString(),
|
|
||||||
response.date(),
|
|
||||||
category
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
heads.accept(result);
|
result.add(new Head(
|
||||||
});
|
id,
|
||||||
|
Utils.validateUniqueId(obj.get("uuid").getAsString()).orElse(UUID.randomUUID()),
|
||||||
|
obj.get("name").getAsString(),
|
||||||
|
obj.get("value").getAsString(),
|
||||||
|
obj.get("tags").getAsString(),
|
||||||
|
response.date(),
|
||||||
|
category
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
HeadDB.getInstance().getLog().debug("Failed to load from provider: " + provider.name());
|
HeadDB.getInstance().getLog().debug("Failed to load from provider: " + provider.name());
|
||||||
if (HeadDB.getInstance().getConfig().getBoolean("fallback") && provider != HeadProvider.HEAD_ARCHIVE) { // prevent recursion. Maybe switch to an attempts counter down in the future
|
if (HeadDB.getInstance().getConfig().getBoolean("fallback") && provider != HeadProvider.HEAD_ARCHIVE) { // prevent recursion. Maybe switch to an attempts counter down in the future
|
||||||
provider = HeadProvider.HEAD_ARCHIVE;
|
provider = HeadProvider.HEAD_ARCHIVE;
|
||||||
fetchAndResolve(category, heads);
|
return fetchAndResolve(category);
|
||||||
|
} else {
|
||||||
|
HeadDB.getInstance().getLog().error("Could not fetch heads from any provider!");
|
||||||
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fetch(Category category, Consumer<Response> response) throws IOException {
|
public Response fetch(Category category) throws IOException {
|
||||||
HttpURLConnection connection = (HttpURLConnection) new URL(provider.getFormattedUrl(category)).openConnection();
|
HttpURLConnection connection = (HttpURLConnection) new URL(provider.getFormattedUrl(category)).openConnection();
|
||||||
connection.setConnectTimeout(5000);
|
connection.setConnectTimeout(5000);
|
||||||
connection.setRequestMethod("GET");
|
connection.setRequestMethod("GET");
|
||||||
@ -88,10 +95,9 @@ public class Requester {
|
|||||||
builder.append(line);
|
builder.append(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
response.accept(new Response(builder.toString(), connection.getResponseCode(), connection.getHeaderField("date")));
|
connection.disconnect();
|
||||||
|
return new Response(builder.toString(), connection.getResponseCode(), connection.getHeaderField("date"));
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.disconnect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public HeadProvider getProvider() {
|
public HeadProvider getProvider() {
|
||||||
|
@ -90,10 +90,5 @@ blockedHeads:
|
|||||||
ids:
|
ids:
|
||||||
- -1
|
- -1
|
||||||
|
|
||||||
# Storage Options
|
|
||||||
storage:
|
|
||||||
# Amount of threads in the executor pool used for storage.
|
|
||||||
threads: 2
|
|
||||||
|
|
||||||
# Debug Mode
|
# Debug Mode
|
||||||
debug: false
|
debug: false
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren