Delete old implementation

This commit is contained in:
Eric 2020-03-19 15:05:18 +01:00
parent 68b21191ba
commit d87afd44ab
89 changed files with 0 additions and 19571 deletions

View File

@ -1,181 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.epiceric.shopchest</groupId>
<artifactId>shopchest</artifactId>
<version>1.13-SNAPSHOT</version>
<name>ShopChest</name>
<url>https://www.spigotmc.org/resources/shopchest.11431/</url>
<description>Let your players create their own nice-looking shops to sell their stuff to other players!</description>
<parent>
<groupId>de.epiceric.shopchest</groupId>
<artifactId>shopchest-parent</artifactId>
<version>1.13-SNAPSHOT</version>
</parent>
<repositories>
<repository>
<id>vault-repo</id>
<url>http://nexus.hc.to/content/repositories/pub_releases/</url>
</repository>
<repository>
<id>codemc-repo</id>
<url>https://repo.codemc.org/repository/maven-public/</url>
</repository>
<repository>
<id>sk89q-repo</id>
<url>http://maven.sk89q.com/artifactory/repo/</url>
</repository>
<repository>
<id>athion-repo</id>
<url>http://ci.athion.net/job/PlotSquared-Releases/ws/mvn/</url>
</repository>
<repository>
<id>uskyblock-repo</id>
<url>https://raw.github.com/rlf/uSkyBlock/mvn-repo/</url>
</repository>
<repository>
<id>tastybento-repo</id>
<url>http://dl.bintray.com/tastybento/maven-repo</url>
</repository>
<repository>
<id>jitpack-repo</id>
<url>https://jitpack.io</url>
</repository>
<repository>
<id>nlthijs48-repo</id>
<url>http://maven.wiefferink.me</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>net.milkbowl.vault</groupId>
<artifactId>VaultAPI</artifactId>
<version>1.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>fr.xephi</groupId>
<artifactId>authme</artifactId>
<version>5.4.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.intellectualsites.plotsquared</groupId>
<artifactId>PlotSquared-API</artifactId>
<version>4.226</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.rlf</groupId>
<artifactId>uSkyBlock-API</artifactId>
<version>2.6.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.wasteofplastic</groupId>
<artifactId>askyblock</artifactId>
<version>3.0.6.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.TechFortress</groupId>
<artifactId>GriefPrevention</artifactId>
<version>16.11.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>me.wiefferink</groupId>
<artifactId>areashop</artifactId>
<version>2.6.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.palmergames</groupId>
<artifactId>Towny</artifactId>
<version>0.93.1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/Towny-0.93.1.0.jar</systemPath>
</dependency>
<dependency>
<groupId>pl.gnacik</groupId>
<artifactId>IslandWorld</artifactId>
<version>8.5</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/IslandWorld-8.5.jar</systemPath>
</dependency>
<!-- Shaded dependencies -->
<dependency>
<groupId>de.epiceric.shopchest</groupId>
<artifactId>shopchest-api</artifactId>
<version>1.13-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.codemc.worldguardwrapper</groupId>
<artifactId>worldguardwrapper</artifactId>
<version>1.1.6-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.26</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>org.bstats.bukkit</pattern>
<shadedPattern>de.epiceric.shopchest.dependencies.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>org.codemc.worldguardwrapper</pattern>
<shadedPattern>de.epiceric.shopchest.dependencies.worldguardwrapper</shadedPattern>
</relocation>
<relocation>
<pattern>com.zaxxer.hikari</pattern>
<shadedPattern>de.epiceric.shopchest.dependencies.hikari</shadedPattern>
</relocation>
<relocation>
<pattern>org.slf4j</pattern>
<shadedPattern>de.epiceric.shopchest.dependencies.slf4j</shadedPattern>
</relocation>
</relocations>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,662 +0,0 @@
package de.epiceric.shopchest;
import com.palmergames.bukkit.towny.Towny;
import com.wasteofplastic.askyblock.ASkyBlock;
import de.epiceric.shopchest.command.ShopCommand;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.config.HologramFormat;
import de.epiceric.shopchest.event.ShopInitializedEvent;
import de.epiceric.shopchest.external.PlotSquaredShopFlag;
import de.epiceric.shopchest.external.WorldGuardShopFlag;
import de.epiceric.shopchest.external.listeners.ASkyBlockListener;
import de.epiceric.shopchest.external.listeners.GriefPreventionListener;
import de.epiceric.shopchest.external.listeners.IslandWorldListener;
import de.epiceric.shopchest.external.listeners.PlotSquaredListener;
import de.epiceric.shopchest.external.listeners.TownyListener;
import de.epiceric.shopchest.external.listeners.USkyBlockListener;
import de.epiceric.shopchest.language.LanguageUtils;
import de.epiceric.shopchest.listeners.AreaShopListener;
import de.epiceric.shopchest.listeners.BlockExplodeListener;
import de.epiceric.shopchest.listeners.ChestProtectListener;
import de.epiceric.shopchest.listeners.CreativeModeListener;
import de.epiceric.shopchest.listeners.NotifyPlayerOnJoinListener;
import de.epiceric.shopchest.listeners.ShopInteractListener;
import de.epiceric.shopchest.listeners.ShopItemListener;
import de.epiceric.shopchest.listeners.ShopUpdateListener;
import de.epiceric.shopchest.listeners.WorldGuardListener;
import de.epiceric.shopchest.shop.Shop;
import de.epiceric.shopchest.shop.Shop.ShopType;
import de.epiceric.shopchest.sql.Database;
import de.epiceric.shopchest.sql.MySQL;
import de.epiceric.shopchest.sql.SQLite;
import de.epiceric.shopchest.utils.Callback;
import de.epiceric.shopchest.utils.ClickType;
import de.epiceric.shopchest.utils.Permissions;
import de.epiceric.shopchest.utils.ShopUpdater;
import de.epiceric.shopchest.utils.ShopUtils;
import de.epiceric.shopchest.utils.UpdateChecker;
import de.epiceric.shopchest.utils.UpdateChecker.UpdateCheckerResult;
import de.epiceric.shopchest.utils.Utils;
import fr.xephi.authme.AuthMe;
import me.ryanhamshire.GriefPrevention.GriefPrevention;
import me.wiefferink.areashop.AreaShop;
import net.milkbowl.vault.economy.Economy;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.codemc.worldguardwrapper.WorldGuardWrapper;
import pl.islandworld.IslandWorld;
import us.talabrek.ultimateskyblock.api.uSkyBlockAPI;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ShopChest extends JavaPlugin {
private static ShopChest instance;
private Config config;
private HologramFormat hologramFormat;
private ShopCommand shopCommand;
private Economy econ = null;
private Database database;
private boolean isUpdateNeeded = false;
private String latestVersion = "";
private String downloadLink = "";
private ShopUtils shopUtils;
private FileWriter fw;
private Plugin worldGuard;
private Towny towny;
private AuthMe authMe;
private uSkyBlockAPI uSkyBlock;
private ASkyBlock aSkyBlock;
private IslandWorld islandWorld;
private GriefPrevention griefPrevention;
private AreaShop areaShop;
private ShopUpdater updater;
private ExecutorService shopCreationThreadPool;
/**
* @return An instance of ShopChest
*/
public static ShopChest getInstance() {
return instance;
}
/**
* Sets up the economy of Vault
* @return Whether an economy plugin has been registered
*/
private boolean setupEconomy() {
RegisteredServiceProvider<Economy> rsp = getServer().getServicesManager().getRegistration(Economy.class);
if (rsp == null) {
return false;
}
econ = rsp.getProvider();
return econ != null;
}
@Override
public void onLoad() {
instance = this;
config = new Config(this);
if (Config.enableDebugLog) {
File debugLogFile = new File(getDataFolder(), "debug.txt");
try {
if (!debugLogFile.exists()) {
debugLogFile.createNewFile();
}
new PrintWriter(debugLogFile).close();
fw = new FileWriter(debugLogFile, true);
} catch (IOException e) {
getLogger().info("Failed to instantiate FileWriter");
e.printStackTrace();
}
}
debug("Loading ShopChest version " + getDescription().getVersion());
worldGuard = Bukkit.getServer().getPluginManager().getPlugin("WorldGuard");
if (worldGuard != null) {
WorldGuardShopFlag.register(this);
}
}
@Override
public void onEnable() {
debug("Enabling ShopChest version " + getDescription().getVersion());
if (!getServer().getPluginManager().isPluginEnabled("Vault")) {
debug("Could not find plugin \"Vault\"");
getLogger().severe("Could not find plugin \"Vault\"");
getServer().getPluginManager().disablePlugin(this);
return;
}
if (!setupEconomy()) {
debug("Could not find any Vault economy dependency!");
getLogger().severe("Could not find any Vault economy dependency!");
getServer().getPluginManager().disablePlugin(this);
return;
}
switch (Utils.getServerVersion()) {
case "v1_8_R1":
case "v1_8_R2":
case "v1_8_R3":
case "v1_9_R1":
case "v1_9_R2":
case "v1_10_R1":
case "v1_11_R1":
case "v1_12_R1":
case "v1_13_R1":
case "v1_13_R2":
case "v1_14_R1":
break;
default:
debug("Server version not officially supported: " + Utils.getServerVersion() + "!");
debug("Plugin may still work, but more errors are expected!");
getLogger().warning("Server version not officially supported: " + Utils.getServerVersion() + "!");
getLogger().warning("Plugin may still work, but more errors are expected!");
}
shopUtils = new ShopUtils(this);
saveResource("item_names.txt", true);
LanguageUtils.load();
File hologramFormatFile = new File(getDataFolder(), "hologram-format.yml");
if (!hologramFormatFile.exists()) {
saveResource("hologram-format.yml", false);
}
hologramFormat = new HologramFormat(this);
shopCommand = new ShopCommand(this);
shopCreationThreadPool = new ThreadPoolExecutor(0, 8,
5L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
loadExternalPlugins();
loadMetrics();
initDatabase();
checkForUpdates();
registerListeners();
registerExternalListeners();
initializeShops();
updater = new ShopUpdater(this);
updater.start();
}
@Override
public void onDisable() {
debug("Disabling ShopChest...");
if (shopUtils == null) {
// Plugin has not been fully enabled (probably due to errors),
// so only close file writer.
if (fw != null && Config.enableDebugLog) {
try {
fw.close();
} catch (IOException e) {
getLogger().severe("Failed to close FileWriter");
e.printStackTrace();
}
}
return;
}
ClickType.clear();
if (updater != null) {
debug("Stopping updater");
updater.stop();
}
if (shopCreationThreadPool != null) {
shopCreationThreadPool.shutdown();
}
for (Shop shop : shopUtils.getShopsCopy()) {
shopUtils.removeShop(shop, false);
debug("Removed shop (#" + shop.getID() + ")");
}
if (database != null) {
if (database instanceof SQLite) {
((SQLite) database).vacuum(false);
}
database.disconnect();
}
if (fw != null && Config.enableDebugLog) {
try {
fw.close();
} catch (IOException e) {
getLogger().severe("Failed to close FileWriter");
e.printStackTrace();
}
}
}
private void loadExternalPlugins() {
Plugin townyPlugin = Bukkit.getServer().getPluginManager().getPlugin("Towny");
if (townyPlugin instanceof Towny) {
towny = (Towny) townyPlugin;
}
Plugin authMePlugin = Bukkit.getServer().getPluginManager().getPlugin("AuthMe");
if (authMePlugin instanceof AuthMe) {
authMe = (AuthMe) authMePlugin;
}
Plugin uSkyBlockPlugin = Bukkit.getServer().getPluginManager().getPlugin("uSkyBlock");
if (uSkyBlockPlugin instanceof uSkyBlockAPI) {
uSkyBlock = (uSkyBlockAPI) uSkyBlockPlugin;
}
Plugin aSkyBlockPlugin = Bukkit.getServer().getPluginManager().getPlugin("ASkyBlock");
if (aSkyBlockPlugin instanceof ASkyBlock) {
aSkyBlock = (ASkyBlock) aSkyBlockPlugin;
}
Plugin islandWorldPlugin = Bukkit.getServer().getPluginManager().getPlugin("IslandWorld");
if (islandWorldPlugin instanceof IslandWorld) {
islandWorld = (IslandWorld) islandWorldPlugin;
}
Plugin griefPreventionPlugin = Bukkit.getServer().getPluginManager().getPlugin("GriefPrevention");
if (griefPreventionPlugin instanceof GriefPrevention) {
griefPrevention = (GriefPrevention) griefPreventionPlugin;
}
Plugin areaShopPlugin = Bukkit.getServer().getPluginManager().getPlugin("AreaShop");
if (areaShopPlugin instanceof AreaShop) {
areaShop = (AreaShop) areaShopPlugin;
}
if (hasWorldGuard()) {
WorldGuardWrapper.getInstance().registerEvents(this);
}
if (hasPlotSquared()) {
PlotSquaredShopFlag.register(this);
}
}
private void loadMetrics() {
debug("Initializing Metrics...");
Metrics metrics = new Metrics(this);
metrics.addCustomChart(new Metrics.SimplePie("creative_setting", () -> Config.creativeSelectItem ? "Enabled" : "Disabled"));
metrics.addCustomChart(new Metrics.SimplePie("database_type", () -> Config.databaseType.toString()));
metrics.addCustomChart(new Metrics.AdvancedPie("shop_type", () -> {
int normal = 0;
int admin = 0;
for (Shop shop : shopUtils.getShops()) {
if (shop.getShopType() == ShopType.NORMAL) normal++;
else if (shop.getShopType() == ShopType.ADMIN) admin++;
}
Map<String, Integer> result = new HashMap<>();
result.put("Admin", admin);
result.put("Normal", normal);
return result;
}));
}
private void initDatabase() {
if (Config.databaseType == Database.DatabaseType.SQLite) {
debug("Using database type: SQLite");
getLogger().info("Using SQLite");
database = new SQLite(this);
} else {
debug("Using database type: MySQL");
getLogger().info("Using MySQL");
database = new MySQL(this);
if (Config.databaseMySqlPingInterval > 0) {
Bukkit.getScheduler().runTaskTimer(this, new Runnable() {
@Override
public void run() {
if (database instanceof MySQL) {
((MySQL) database).ping();
}
}
}, Config.databaseMySqlPingInterval * 20L, Config.databaseMySqlPingInterval * 20L);
}
}
}
private void checkForUpdates() {
if (!Config.enableUpdateChecker) {
return;
}
new BukkitRunnable() {
@Override
public void run() {
UpdateChecker uc = new UpdateChecker(ShopChest.this);
UpdateCheckerResult result = uc.check();
switch (result) {
case TRUE:
latestVersion = uc.getVersion();
downloadLink = uc.getLink();
isUpdateNeeded = true;
getLogger().warning(String.format("Version %s is available! You are running version %s.",
latestVersion, getDescription().getVersion()));
for (Player p : getServer().getOnlinePlayers()) {
if (p.hasPermission(Permissions.UPDATE_NOTIFICATION)) {
Utils.sendUpdateMessage(ShopChest.this, p);
}
}
break;
case FALSE:
latestVersion = "";
downloadLink = "";
isUpdateNeeded = false;
break;
case ERROR:
latestVersion = "";
downloadLink = "";
isUpdateNeeded = false;
getLogger().severe("An error occurred while checking for updates.");
break;
}
}
}.runTaskAsynchronously(this);
}
private void registerListeners() {
debug("Registering listeners...");
getServer().getPluginManager().registerEvents(new ShopUpdateListener(this), this);
getServer().getPluginManager().registerEvents(new ShopItemListener(this), this);
getServer().getPluginManager().registerEvents(new ShopInteractListener(this), this);
getServer().getPluginManager().registerEvents(new NotifyPlayerOnJoinListener(this), this);
getServer().getPluginManager().registerEvents(new ChestProtectListener(this), this);
getServer().getPluginManager().registerEvents(new CreativeModeListener(this), this);
if (!Utils.getServerVersion().equals("v1_8_R1")) {
getServer().getPluginManager().registerEvents(new BlockExplodeListener(this), this);
}
if (hasWorldGuard()) {
getServer().getPluginManager().registerEvents(new WorldGuardListener(this), this);
if (hasAreaShop()) {
getServer().getPluginManager().registerEvents(new AreaShopListener(this), this);
}
}
}
private void registerExternalListeners() {
if (hasASkyBlock())
getServer().getPluginManager().registerEvents(new ASkyBlockListener(this), this);
if (hasGriefPrevention())
getServer().getPluginManager().registerEvents(new GriefPreventionListener(this), this);
if (hasIslandWorld())
getServer().getPluginManager().registerEvents(new IslandWorldListener(this), this);
if (hasPlotSquared())
getServer().getPluginManager().registerEvents(new PlotSquaredListener(this), this);
if (hasTowny())
getServer().getPluginManager().registerEvents(new TownyListener(this), this);
if (hasUSkyBlock())
getServer().getPluginManager().registerEvents(new USkyBlockListener(this), this);
if (hasWorldGuard())
getServer().getPluginManager().registerEvents(new de.epiceric.shopchest.external.listeners.WorldGuardListener(this), this);
}
/**
* Initializes the shops
*/
private void initializeShops() {
debug("Initializing Shops...");
shopUtils.reloadShops(false, true, new Callback<Integer>(this) {
@Override
public void onResult(Integer result) {
Bukkit.getServer().getPluginManager().callEvent(new ShopInitializedEvent(result));
getLogger().info("Initialized " + result + " Shops");
debug("Initialized " + result + " Shops");
}
@Override
public void onError(Throwable throwable) {
// Database connection probably failed => disable plugin to prevent more errors
getLogger().severe("No database access. Disabling ShopChest");
if (throwable != null) getLogger().severe(throwable.getMessage());
getServer().getPluginManager().disablePlugin(ShopChest.this);
}
});
}
/**
* Print a message to the <i>/plugins/ShopChest/debug.txt</i> file
* @param message Message to print
*/
public void debug(String message) {
if (Config.enableDebugLog && fw != null) {
try {
Calendar c = Calendar.getInstance();
String timestamp = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(c.getTime());
fw.write(String.format("[%s] %s\r\n", timestamp, message));
fw.flush();
} catch (IOException e) {
getLogger().severe("Failed to print debug message.");
e.printStackTrace();
}
}
}
/**
* Print a {@link Throwable}'s stacktrace to the <i>/plugins/ShopChest/debug.txt</i> file
* @param throwable {@link Throwable} whose stacktrace will be printed
*/
public void debug(Throwable throwable) {
if (Config.enableDebugLog && fw != null) {
PrintWriter pw = new PrintWriter(fw);
throwable.printStackTrace(pw);
pw.flush();
}
}
/**
* @return A thread pool for executing shop creation tasks
*/
public ExecutorService getShopCreationThreadPool() {
return shopCreationThreadPool;
}
public HologramFormat getHologramFormat() {
return hologramFormat;
}
public ShopCommand getShopCommand() {
return shopCommand;
}
/**
* @return The {@link ShopUpdater} that schedules hologram and item updates
*/
public ShopUpdater getUpdater() {
return updater;
}
/**
* @return Whether the plugin 'AreaShop' is enabled
*/
public boolean hasAreaShop() {
return areaShop != null && areaShop.isEnabled();
}
/**
* @return Whether the plugin 'GriefPrevention' is enabled
*/
public boolean hasGriefPrevention() {
return griefPrevention != null && griefPrevention.isEnabled();
}
/**
* @return An instance of {@link GriefPrevention} or {@code null} if GriefPrevention is not enabled
*/
public GriefPrevention getGriefPrevention() {
return griefPrevention;
}
/**
* @return Whether the plugin 'IslandWorld' is enabled
*/
public boolean hasIslandWorld() {
return islandWorld != null && islandWorld.isEnabled();
}
/**
* @return Whether the plugin 'ASkyBlock' is enabled
*/
public boolean hasASkyBlock() {
return aSkyBlock != null && aSkyBlock.isEnabled();
}
/**
* @return Whether the plugin 'uSkyBlock' is enabled
*/
public boolean hasUSkyBlock() {
return uSkyBlock != null && uSkyBlock.isEnabled();
}
/**
* @return An instance of {@link uSkyBlockAPI} or {@code null} if uSkyBlock is not enabled
*/
public uSkyBlockAPI getUSkyBlock() {
return uSkyBlock;
}
/**
* @return Whether the plugin 'PlotSquared' is enabled
*/
public boolean hasPlotSquared() {
if (Utils.getMajorVersion() < 13) {
// Supported PlotSquared versions don't support versions below 1.13
return false;
}
Plugin p = getServer().getPluginManager().getPlugin("PlotSquared");
return p != null && p.isEnabled();
}
/**
* @return Whether the plugin 'AuthMe' is enabled
*/
public boolean hasAuthMe() {
return authMe != null && authMe.isEnabled();
}
/**
* @return Whether the plugin 'Towny' is enabled
*/
public boolean hasTowny() {
return towny != null && towny.isEnabled();
}
/**
* @return Whether the plugin 'WorldGuard' is enabled
*/
public boolean hasWorldGuard() {
return worldGuard != null && worldGuard.isEnabled();
}
/**
* @return ShopChest's {@link ShopUtils} containing some important methods
*/
public ShopUtils getShopUtils() {
return shopUtils;
}
/**
* @return Registered Economy of Vault
*/
public Economy getEconomy() {
return econ;
}
/**
* @return ShopChest's shop database
*/
public Database getShopDatabase() {
return database;
}
/**
* @return Whether an update is needed (will return false if not checked)
*/
public boolean isUpdateNeeded() {
return isUpdateNeeded;
}
/**
* Set whether an update is needed
* @param isUpdateNeeded Whether an update should be needed
*/
public void setUpdateNeeded(boolean isUpdateNeeded) {
this.isUpdateNeeded = isUpdateNeeded;
}
/**
* @return The latest version of ShopChest (will return null if not checked or if no update is available)
*/
public String getLatestVersion() {
return latestVersion;
}
/**
* Set the latest version
* @param latestVersion Version to set as latest version
*/
public void setLatestVersion(String latestVersion) {
this.latestVersion = latestVersion;
}
/**
* @return The download link of the latest version (will return null if not checked or if no update is available)
*/
public String getDownloadLink() {
return downloadLink;
}
/**
* Set the download Link of the latest version (will return null if not checked or if no update is available)
* @param downloadLink Link to set as Download Link
*/
public void setDownloadLink(String downloadLink) {
this.downloadLink = downloadLink;
}
/**
* @return The {@link Config} of ShopChest
*/
public Config getShopChestConfig() {
return config;
}
}

View File

@ -1,311 +0,0 @@
package de.epiceric.shopchest.command;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.config.Placeholder;
import de.epiceric.shopchest.language.LanguageUtils;
import de.epiceric.shopchest.language.Message;
import de.epiceric.shopchest.language.Replacement;
import de.epiceric.shopchest.utils.Permissions;
import de.epiceric.shopchest.utils.ClickType.SelectClickType;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
public class ShopCommand {
private static boolean commandCreated = false;
private ShopChest plugin;
private String name;
private PluginCommand pluginCommand;
private ShopCommandExecutor executor;
private List<ShopSubCommand> subCommands = new ArrayList<>();
public ShopCommand(final ShopChest plugin) {
if (commandCreated) {
IllegalStateException e = new IllegalStateException("Command has already been registered");
plugin.debug(e);
throw e;
}
this.plugin = plugin;
this.name = Config.mainCommandName;
this.pluginCommand = createPluginCommand();
this.executor = new ShopCommandExecutor(plugin);
ShopTabCompleter tabCompleter = new ShopTabCompleter(plugin);
final Replacement cmdReplacement = new Replacement(Placeholder.COMMAND, name);
addSubCommand(new ShopSubCommand("create", true, executor, tabCompleter) {
@Override
public String getHelpMessage(CommandSender sender) {
boolean receiveCreateMessage = sender.hasPermission(Permissions.CREATE);
if (!receiveCreateMessage) {
for (PermissionAttachmentInfo permInfo : sender.getEffectivePermissions()) {
String perm = permInfo.getPermission();
if (perm.startsWith(Permissions.CREATE) && sender.hasPermission(perm)) {
receiveCreateMessage = true;
break;
}
}
}
if (sender.hasPermission(Permissions.CREATE_ADMIN)) {
return LanguageUtils.getMessage(Message.COMMAND_DESC_CREATE_ADMIN, cmdReplacement);
} else if (receiveCreateMessage) {
return LanguageUtils.getMessage(Message.COMMAND_DESC_CREATE, cmdReplacement);
}
return "";
}
});
addSubCommand(new ShopSubCommand("remove", true, executor, tabCompleter) {
@Override
public String getHelpMessage(CommandSender sender) {
return LanguageUtils.getMessage(Message.COMMAND_DESC_REMOVE, cmdReplacement);
}
});
addSubCommand(new ShopSubCommand("info", true, executor, tabCompleter) {
@Override
public String getHelpMessage(CommandSender sender) {
return LanguageUtils.getMessage(Message.COMMAND_DESC_INFO, cmdReplacement);
}
});
addSubCommand(new ShopSubCommand("limits", true, executor, tabCompleter) {
@Override
public String getHelpMessage(CommandSender sender) {
return LanguageUtils.getMessage(Message.COMMAND_DESC_LIMITS, cmdReplacement);
}
});
addSubCommand(new ShopSubCommand("open", true, executor, tabCompleter) {
@Override
public String getHelpMessage(CommandSender sender) {
return LanguageUtils.getMessage(Message.COMMAND_DESC_OPEN, cmdReplacement);
}
});
addSubCommand(new ShopSubCommand("removeall", false, executor, tabCompleter) {
@Override
public String getHelpMessage(CommandSender sender) {
if (sender.hasPermission(Permissions.REMOVE_OTHER)) {
return LanguageUtils.getMessage(Message.COMMAND_DESC_REMOVEALL, cmdReplacement);
} else {
return "";
}
}
});
addSubCommand(new ShopSubCommand("reload", false, executor, tabCompleter) {
@Override
public String getHelpMessage(CommandSender sender) {
if (sender.hasPermission(Permissions.RELOAD)) {
return LanguageUtils.getMessage(Message.COMMAND_DESC_RELOAD, cmdReplacement);
} else {
return "";
}
}
});
addSubCommand(new ShopSubCommand("update", false, executor, tabCompleter) {
@Override
public String getHelpMessage(CommandSender sender) {
if (sender.hasPermission(Permissions.UPDATE)) {
return LanguageUtils.getMessage(Message.COMMAND_DESC_UPDATE, cmdReplacement);
} else {
return "";
}
}
});
addSubCommand(new ShopSubCommand("config", false, executor, tabCompleter) {
@Override
public String getHelpMessage(CommandSender sender) {
if (sender.hasPermission(Permissions.CONFIG)) {
return LanguageUtils.getMessage(Message.COMMAND_DESC_CONFIG, cmdReplacement);
} else {
return "";
}
}
});
register();
commandCreated = true;
}
public PluginCommand getCommand() {
return pluginCommand;
}
/**
* Call the second part of the create method after the player
* has selected an item from the creative inventory.
*/
public void createShopAfterSelected(Player player, SelectClickType clickType) {
executor.create2(player, clickType);
}
private PluginCommand createPluginCommand() {
plugin.debug("Creating plugin command");
try {
Constructor<PluginCommand> c = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class);
c.setAccessible(true);
PluginCommand cmd = c.newInstance(name, plugin);
cmd.setDescription("Manage players' shops or this plugin.");
cmd.setUsage("/" + name);
cmd.setExecutor(new ShopBaseCommandExecutor());
cmd.setTabCompleter(new ShopBaseTabCompleter());
return cmd;
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
plugin.getLogger().severe("Failed to create command");
plugin.debug("Failed to create plugin command");
plugin.debug(e);
}
return null;
}
public void addSubCommand(ShopSubCommand subCommand) {
plugin.debug("Adding sub command \"" + subCommand.getName() + "\"");
this.subCommands.add(subCommand);
}
public List<ShopSubCommand> getSubCommands() {
return new ArrayList<>(subCommands);
}
private void register() {
if (pluginCommand == null) return;
plugin.debug("Registering command " + name);
try {
Field f = Bukkit.getPluginManager().getClass().getDeclaredField("commandMap");
f.setAccessible(true);
Object commandMapObject = f.get(Bukkit.getPluginManager());
if (commandMapObject instanceof CommandMap) {
CommandMap commandMap = (CommandMap) commandMapObject;
commandMap.register(plugin.getName(), pluginCommand);
}
} catch (NoSuchFieldException | IllegalAccessException e) {
plugin.getLogger().severe("Failed to register command");
plugin.debug("Failed to register plugin command");
plugin.debug(e);
}
}
/**
* Sends the basic help message
*
* @param sender {@link CommandSender} who will receive the message
*/
private void sendBasicHelpMessage(CommandSender sender) {
plugin.debug("Sending basic help message to " + sender.getName());
sender.sendMessage(" ");
String header = LanguageUtils.getMessage(Message.COMMAND_DESC_HEADER,
new Replacement(Placeholder.COMMAND, Config.mainCommandName));
if (!header.trim().isEmpty()) sender.sendMessage(header);
for (ShopSubCommand subCommand : subCommands) {
String msg = subCommand.getHelpMessage(sender);
if (msg == null || msg.isEmpty()) {
continue;
}
sender.sendMessage(msg);
}
String footer = LanguageUtils.getMessage(Message.COMMAND_DESC_FOOTER,
new Replacement(Placeholder.COMMAND,Config.mainCommandName));
if (!footer.trim().isEmpty()) sender.sendMessage(footer);
sender.sendMessage(" ");
}
private class ShopBaseCommandExecutor implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length > 0) {
for (ShopSubCommand subCommand : subCommands) {
if (subCommand.getName().equalsIgnoreCase(args[0])) {
if (!(sender instanceof Player) && subCommand.isPlayerCommand()) {
sender.sendMessage(ChatColor.RED + "Only players can use this command.");
return true;
}
if (!subCommand.execute(sender, command, label, args)) {
sendBasicHelpMessage(sender);
}
return true;
}
}
sendBasicHelpMessage(sender);
} else {
sendBasicHelpMessage(sender);
}
return true;
}
}
private class ShopBaseTabCompleter implements TabCompleter {
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
List<String> subCommandNames = new ArrayList<>();
List<String> tabCompletions = new ArrayList<>();
for (ShopSubCommand subCommand : subCommands) {
subCommandNames.add(subCommand.getName());
}
if (args.length == 1) {
if (!args[0].isEmpty()) {
for (String s : subCommandNames) {
if (s.startsWith(args[0])) {
tabCompletions.add(s);
}
}
return tabCompletions;
} else {
return subCommandNames;
}
} else if (args.length > 1) {
for (ShopSubCommand subCmd : subCommands) {
if (subCmd.getName().equalsIgnoreCase(args[0])) {
return subCmd.getTabCompletions(sender, command, label, args);
}
}
}
return new ArrayList<>();
}
}
}

View File

@ -1,538 +0,0 @@
package de.epiceric.shopchest.command;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.config.Placeholder;
import de.epiceric.shopchest.event.ShopPreCreateEvent;
import de.epiceric.shopchest.event.ShopPreInfoEvent;
import de.epiceric.shopchest.event.ShopPreOpenEvent;
import de.epiceric.shopchest.event.ShopPreRemoveEvent;
import de.epiceric.shopchest.event.ShopReloadEvent;
import de.epiceric.shopchest.event.ShopRemoveAllEvent;
import de.epiceric.shopchest.language.LanguageUtils;
import de.epiceric.shopchest.language.Message;
import de.epiceric.shopchest.language.Replacement;
import de.epiceric.shopchest.shop.Shop;
import de.epiceric.shopchest.shop.ShopProduct;
import de.epiceric.shopchest.shop.Shop.ShopType;
import de.epiceric.shopchest.utils.Callback;
import de.epiceric.shopchest.utils.ClickType;
import de.epiceric.shopchest.utils.ItemUtils;
import de.epiceric.shopchest.utils.Permissions;
import de.epiceric.shopchest.utils.ShopUtils;
import de.epiceric.shopchest.utils.UpdateChecker;
import de.epiceric.shopchest.utils.Utils;
import de.epiceric.shopchest.utils.ClickType.CreateClickType;
import de.epiceric.shopchest.utils.ClickType.SelectClickType;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
class ShopCommandExecutor implements CommandExecutor {
private ShopChest plugin;
private ShopUtils shopUtils;
ShopCommandExecutor(ShopChest plugin) {
this.plugin = plugin;
this.shopUtils = plugin.getShopUtils();
}
@Override
public boolean onCommand(CommandSender sender, Command command, String s, String[] args) {
List<ShopSubCommand> subCommands = plugin.getShopCommand().getSubCommands();
if (args.length > 0) {
String _subCommand = args[0];
ShopSubCommand subCommand = null;
for (ShopSubCommand shopSubCommand : subCommands) {
if (shopSubCommand.getName().equalsIgnoreCase(_subCommand)) {
subCommand = shopSubCommand;
break;
}
}
if (subCommand == null) {
return false;
}
if (subCommand.getName().equalsIgnoreCase("reload")) {
if (sender.hasPermission(Permissions.RELOAD)) {
reload(sender);
} else {
sender.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_RELOAD));
}
} else if (subCommand.getName().equalsIgnoreCase("update")) {
if (sender.hasPermission(Permissions.UPDATE)) {
checkUpdates(sender);
} else {
sender.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_UPDATE));
}
} else if (subCommand.getName().equalsIgnoreCase("config")) {
if (sender.hasPermission(Permissions.CONFIG)) {
return args.length >= 4 && changeConfig(sender, args);
} else {
sender.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_CONFIG));
}
} else if (subCommand.getName().equalsIgnoreCase("removeall")) {
if (sender.hasPermission(Permissions.REMOVE_OTHER)) {
if (args.length >= 2) {
removeAll(sender, args);
} else {
return false;
}
} else {
sender.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_REMOVE_OTHERS));
}
} else {
if (sender instanceof Player) {
Player p = (Player) sender;
if (subCommand.getName().equalsIgnoreCase("create")) {
if (args.length == 4) {
create(args, Shop.ShopType.NORMAL, p);
} else if (args.length == 5) {
if (args[4].equalsIgnoreCase("normal")) {
create(args, Shop.ShopType.NORMAL, p);
} else if (args[4].equalsIgnoreCase("admin")) {
if (p.hasPermission(Permissions.CREATE_ADMIN)) {
create(args, Shop.ShopType.ADMIN, p);
} else {
p.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_CREATE_ADMIN));
}
} else {
return false;
}
} else {
return false;
}
} else if (subCommand.getName().equalsIgnoreCase("remove")) {
remove(p);
} else if (subCommand.getName().equalsIgnoreCase("info")) {
info(p);
} else if (subCommand.getName().equalsIgnoreCase("limits")) {
plugin.debug(p.getName() + " is viewing his shop limits: " + shopUtils.getShopAmount(p) + "/" + shopUtils.getShopLimit(p));
int limit = shopUtils.getShopLimit(p);
p.sendMessage(LanguageUtils.getMessage(Message.OCCUPIED_SHOP_SLOTS,
new Replacement(Placeholder.LIMIT, (limit < 0 ? "" : String.valueOf(limit))),
new Replacement(Placeholder.AMOUNT, String.valueOf(shopUtils.getShopAmount(p)))));
} else if (subCommand.getName().equalsIgnoreCase("open")) {
open(p);
} else {
return false;
}
}
}
return true;
}
return false;
}
/**
* A given player checks for updates
* @param sender The command executor
*/
private void checkUpdates(CommandSender sender) {
plugin.debug(sender.getName() + " is checking for updates");
sender.sendMessage(LanguageUtils.getMessage(Message.UPDATE_CHECKING));
UpdateChecker uc = new UpdateChecker(plugin);
UpdateChecker.UpdateCheckerResult result = uc.check();
if (result == UpdateChecker.UpdateCheckerResult.TRUE) {
plugin.setLatestVersion(uc.getVersion());
plugin.setDownloadLink(uc.getLink());
plugin.setUpdateNeeded(true);
if (sender instanceof Player) {
Utils.sendUpdateMessage(plugin, (Player) sender);
} else {
sender.sendMessage(LanguageUtils.getMessage(Message.UPDATE_AVAILABLE, new Replacement(Placeholder.VERSION, uc.getVersion())));
}
} else if (result == UpdateChecker.UpdateCheckerResult.FALSE) {
plugin.setLatestVersion("");
plugin.setDownloadLink("");
plugin.setUpdateNeeded(false);
sender.sendMessage(LanguageUtils.getMessage(Message.UPDATE_NO_UPDATE));
} else {
plugin.setLatestVersion("");
plugin.setDownloadLink("");
plugin.setUpdateNeeded(false);
sender.sendMessage(LanguageUtils.getMessage(Message.UPDATE_ERROR));
}
}
/**
* A given player reloads the shops
* @param sender The command executor
*/
private void reload(final CommandSender sender) {
plugin.debug(sender.getName() + " is reloading the shops");
ShopReloadEvent event = new ShopReloadEvent(sender);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()){
plugin.debug("Reload event cancelled");
return;
}
shopUtils.reloadShops(true, true, new Callback<Integer>(plugin) {
@Override
public void onResult(Integer result) {
sender.sendMessage(LanguageUtils.getMessage(Message.RELOADED_SHOPS,
new Replacement(Placeholder.AMOUNT, String.valueOf(result))));
plugin.debug(sender.getName() + " has reloaded " + result + " shops");
}
@Override
public void onError(Throwable throwable) {
// Database connection probably failed => disable plugin to prevent more errors
sender.sendMessage(LanguageUtils.getMessage(Message.ERROR_OCCURRED,
new Replacement(Placeholder.ERROR, "No database access: Disabling ShopChest")));
plugin.getLogger().severe("No database access: Disabling ShopChest");
if (throwable != null) plugin.getLogger().severe(throwable.getMessage());
plugin.getServer().getPluginManager().disablePlugin(plugin);
}
});
}
/**
* A given player creates a shop
* @param args Arguments of the entered command
* @param shopType The {@link Shop.ShopType}, the shop will have
* @param p The command executor
*/
private void create(String[] args, Shop.ShopType shopType, final Player p) {
plugin.debug(p.getName() + " wants to create a shop");
int amount;
double buyPrice, sellPrice;
// Check if amount and prices are valid
try {
amount = Integer.parseInt(args[1]);
buyPrice = Double.parseDouble(args[2]);
sellPrice = Double.parseDouble(args[3]);
} catch (NumberFormatException e) {
p.sendMessage(LanguageUtils.getMessage(Message.AMOUNT_PRICE_NOT_NUMBER));
plugin.debug(p.getName() + " has entered an invalid amount and/or prices");
return;
}
if (!Utils.hasPermissionToCreateShop(p, Utils.getPreferredItemInHand(p), buyPrice > 0, sellPrice > 0)) {
p.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_CREATE));
plugin.debug(p.getName() + " is not permitted to create the shop");
return;
}
// Check for limits
int limit = shopUtils.getShopLimit(p);
if (limit != -1) {
if (shopUtils.getShopAmount(p) >= limit) {
if (shopType != Shop.ShopType.ADMIN) {
p.sendMessage(LanguageUtils.getMessage(Message.SHOP_LIMIT_REACHED, new Replacement(Placeholder.LIMIT, String.valueOf(limit))));
plugin.debug(p.getName() + " has reached the limit");
return;
}
}
}
if (amount <= 0) {
p.sendMessage(LanguageUtils.getMessage(Message.AMOUNT_IS_ZERO));
plugin.debug(p.getName() + " has entered an invalid amount");
return;
}
if (!Config.allowDecimalsInPrice && (buyPrice != (int) buyPrice || sellPrice != (int) sellPrice)) {
p.sendMessage(LanguageUtils.getMessage(Message.PRICES_CONTAIN_DECIMALS));
plugin.debug(p.getName() + " has entered an invalid price");
return;
}
boolean buyEnabled = buyPrice > 0;
boolean sellEnabled = sellPrice > 0;
if (!buyEnabled && !sellEnabled) {
p.sendMessage(LanguageUtils.getMessage(Message.BUY_SELL_DISABLED));
plugin.debug(p.getName() + " has disabled buying and selling");
return;
}
ItemStack inHand = Utils.getPreferredItemInHand(p);
// Check if item in hand
if (inHand == null) {
plugin.debug(p.getName() + " does not have an item in his hand");
if (!Config.creativeSelectItem) {
p.sendMessage(LanguageUtils.getMessage(Message.NO_ITEM_IN_HAND));
return;
}
if (!(ClickType.getPlayerClickType(p) instanceof SelectClickType)) {
// Don't set previous game mode to creative if player already has select click type
ClickType.setPlayerClickType(p, new SelectClickType(p.getGameMode(), amount, buyPrice, sellPrice, shopType));
p.setGameMode(GameMode.CREATIVE);
}
p.sendMessage(LanguageUtils.getMessage(Message.SELECT_ITEM));
} else {
SelectClickType ct = new SelectClickType(null, amount, buyPrice, sellPrice, shopType);
ct.setItem(inHand);
create2(p, ct);
}
}
/**
* <b>SHALL ONLY BE CALLED VIA {@link ShopCommand#createShopAfterSelected()}</b>
*/
protected void create2(Player p, SelectClickType selectClickType) {
ItemStack itemStack = selectClickType.getItem();
int amount = selectClickType.getAmount();
double buyPrice = selectClickType.getBuyPrice();
double sellPrice = selectClickType.getSellPrice();
boolean buyEnabled = buyPrice > 0;
boolean sellEnabled = sellPrice > 0;
ShopType shopType = selectClickType.getShopType();
// Check if item on blacklist
for (String item :Config.blacklist) {
ItemStack is = ItemUtils.getItemStack(item);
if (is == null) {
plugin.getLogger().warning("Invalid item found in blacklist: " + item);
plugin.debug("Invalid item in blacklist: " + item);
continue;
}
if (is.getType().equals(itemStack.getType()) && is.getDurability() == itemStack.getDurability()) {
p.sendMessage(LanguageUtils.getMessage(Message.CANNOT_SELL_ITEM));
plugin.debug(p.getName() + "'s item is on the blacklist");
return;
}
}
// Check if prices lower than minimum price
for (String key :Config.minimumPrices) {
ItemStack is = ItemUtils.getItemStack(key);
double minPrice = plugin.getConfig().getDouble("minimum-prices." + key);
if (is == null) {
plugin.getLogger().warning("Invalid item found in minimum-prices: " + key);
plugin.debug("Invalid item in minimum-prices: " + key);
continue;
}
if (is.getType().equals(itemStack.getType()) && is.getDurability() == itemStack.getDurability()) {
if (buyEnabled) {
if ((buyPrice < amount * minPrice) && (buyPrice > 0)) {
p.sendMessage(LanguageUtils.getMessage(Message.BUY_PRICE_TOO_LOW, new Replacement(Placeholder.MIN_PRICE, String.valueOf(amount * minPrice))));
plugin.debug(p.getName() + "'s buy price is lower than the minimum");
return;
}
}
if (sellEnabled) {
if ((sellPrice < amount * minPrice) && (sellPrice > 0)) {
p.sendMessage(LanguageUtils.getMessage(Message.SELL_PRICE_TOO_LOW, new Replacement(Placeholder.MIN_PRICE, String.valueOf(amount * minPrice))));
plugin.debug(p.getName() + "'s sell price is lower than the minimum");
return;
}
}
}
}
// Check if prices higher than maximum price
for (String key :Config.maximumPrices) {
ItemStack is = ItemUtils.getItemStack(key);
double maxPrice = plugin.getConfig().getDouble("maximum-prices." + key);
if (is == null) {
plugin.getLogger().warning("Invalid item found in maximum-prices: " + key);
plugin.debug("Invalid item in maximum-prices: " + key);
continue;
}
if (is.getType().equals(itemStack.getType()) && is.getDurability() == itemStack.getDurability()) {
if (buyEnabled) {
if ((buyPrice > amount * maxPrice) && (buyPrice > 0)) {
p.sendMessage(LanguageUtils.getMessage(Message.BUY_PRICE_TOO_HIGH, new Replacement(Placeholder.MAX_PRICE, String.valueOf(amount * maxPrice))));
plugin.debug(p.getName() + "'s buy price is higher than the maximum");
return;
}
}
if (sellEnabled) {
if ((sellPrice > amount * maxPrice) && (sellPrice > 0)) {
p.sendMessage(LanguageUtils.getMessage(Message.SELL_PRICE_TOO_HIGH, new Replacement(Placeholder.MAX_PRICE, String.valueOf(amount * maxPrice))));
plugin.debug(p.getName() + "'s sell price is higher than the maximum");
return;
}
}
}
}
if (sellEnabled && buyEnabled) {
if (Config.buyGreaterOrEqualSell) {
if (buyPrice < sellPrice) {
p.sendMessage(LanguageUtils.getMessage(Message.BUY_PRICE_TOO_LOW, new Replacement(Placeholder.MIN_PRICE, String.valueOf(sellPrice))));
plugin.debug(p.getName() + "'s buy price is lower than the sell price");
return;
}
}
}
if (Enchantment.DURABILITY.canEnchantItem(itemStack)) {
if (itemStack.getDurability() > 0 && !Config.allowBrokenItems) {
p.sendMessage(LanguageUtils.getMessage(Message.CANNOT_SELL_BROKEN_ITEM));
plugin.debug(p.getName() + "'s item is broken");
return;
}
}
double creationPrice = (shopType == Shop.ShopType.NORMAL) ?Config.shopCreationPriceNormal :Config.shopCreationPriceAdmin;
if (creationPrice > 0) {
if (plugin.getEconomy().getBalance(p, p.getWorld().getName()) < creationPrice) {
p.sendMessage(LanguageUtils.getMessage(Message.SHOP_CREATE_NOT_ENOUGH_MONEY, new Replacement(Placeholder.CREATION_PRICE, String.valueOf(creationPrice))));
plugin.debug(p.getName() + " can not pay the creation price");
return;
}
}
ShopProduct product = new ShopProduct(itemStack, amount);
ShopPreCreateEvent event = new ShopPreCreateEvent(p, new Shop(plugin, p, product, null, buyPrice, sellPrice, shopType));
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
ClickType.setPlayerClickType(p, new CreateClickType(product, buyPrice, sellPrice, shopType));
plugin.debug(p.getName() + " can now click a chest");
p.sendMessage(LanguageUtils.getMessage(Message.CLICK_CHEST_CREATE));
} else {
plugin.debug("Shop pre create event cancelled");
}
}
/**
* A given player removes a shop
* @param p The command executor
*/
private void remove(final Player p) {
plugin.debug(p.getName() + " wants to remove a shop");
ShopPreRemoveEvent event = new ShopPreRemoveEvent(p);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
plugin.debug("Shop pre remove event cancelled");
return;
}
plugin.debug(p.getName() + " can now click a chest");
p.sendMessage(LanguageUtils.getMessage(Message.CLICK_CHEST_REMOVE));
ClickType.setPlayerClickType(p, new ClickType(ClickType.EnumClickType.REMOVE));
}
/**
* A given player retrieves information about a shop
* @param p The command executor
*/
private void info(final Player p) {
plugin.debug(p.getName() + " wants to retrieve information");
ShopPreInfoEvent event = new ShopPreInfoEvent(p);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
plugin.debug("Shop pre info event cancelled");
return;
}
plugin.debug(p.getName() + " can now click a chest");
p.sendMessage(LanguageUtils.getMessage(Message.CLICK_CHEST_INFO));
ClickType.setPlayerClickType(p, new ClickType(ClickType.EnumClickType.INFO));
}
/**
* A given player opens a shop
* @param p The command executor
*/
private void open(final Player p) {
plugin.debug(p.getName() + " wants to open a shop");
ShopPreOpenEvent event = new ShopPreOpenEvent(p);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
plugin.debug("Shop pre open event cancelled");
return;
}
plugin.debug(p.getName() + " can now click a chest");
p.sendMessage(LanguageUtils.getMessage(Message.CLICK_CHEST_OPEN));
ClickType.setPlayerClickType(p, new ClickType(ClickType.EnumClickType.OPEN));
}
private boolean changeConfig(CommandSender sender, String[] args) {
plugin.debug(sender.getName() + " is changing the configuration");
String property = args[2];
String value = args[3];
if (args[1].equalsIgnoreCase("set")) {
plugin.getShopChestConfig().set(property, value);
sender.sendMessage(LanguageUtils.getMessage(Message.CHANGED_CONFIG_SET, new Replacement(Placeholder.PROPERTY, property), new Replacement(Placeholder.VALUE, value)));
} else if (args[1].equalsIgnoreCase("add")) {
plugin.getShopChestConfig().add(property, value);
sender.sendMessage(LanguageUtils.getMessage(Message.CHANGED_CONFIG_ADDED, new Replacement(Placeholder.PROPERTY, property), new Replacement(Placeholder.VALUE, value)));
} else if (args[1].equalsIgnoreCase("remove")) {
plugin.getShopChestConfig().remove(property, value);
sender.sendMessage(LanguageUtils.getMessage(Message.CHANGED_CONFIG_REMOVED, new Replacement(Placeholder.PROPERTY, property), new Replacement(Placeholder.VALUE, value)));
} else {
return false;
}
return true;
}
private void removeAll(CommandSender sender, String[] args) {
OfflinePlayer vendor = Bukkit.getOfflinePlayer(args[1]);
plugin.debug(sender.getName() + " is removing all shops of " + vendor.getName());
List<Shop> shops = new ArrayList<>();
for (Shop shop : shopUtils.getShops()) {
if (shop.getVendor().getUniqueId().equals(vendor.getUniqueId())) {
shops.add(shop);
}
}
ShopRemoveAllEvent event = new ShopRemoveAllEvent(sender, vendor, shops);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()){
plugin.debug("Remove all event cancelled");
return;
}
for (Shop shop : shops) {
shopUtils.removeShop(shop, true);
}
sender.sendMessage(LanguageUtils.getMessage(Message.ALL_SHOPS_REMOVED,
new Replacement(Placeholder.AMOUNT, String.valueOf(shops.size())),
new Replacement(Placeholder.VENDOR, vendor.getName())));
}
}

View File

@ -1,68 +0,0 @@
package de.epiceric.shopchest.command;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import java.util.ArrayList;
import java.util.List;
public abstract class ShopSubCommand {
private String name;
private boolean playerCommand;
private CommandExecutor executor;
private TabCompleter tabCompleter;
public ShopSubCommand(String name, boolean playerCommand, CommandExecutor executor, TabCompleter tabCompleter) {
this.name = name;
this.playerCommand = playerCommand;
this.executor = executor;
this.tabCompleter = tabCompleter;
}
public String getName() {
return name;
}
/**
* @return Whether the command can only be used by players, not by the console
*/
public boolean isPlayerCommand() {
return playerCommand;
}
/**
* Execute the sub command
* @param sender Sender of the command
* @param command Command which was executed
* @param args Arguments of the command ({@code args[0]} is the sub command's name)
* @param label Alias of the command which was used
* @param args Passed command arguments
* @return Whether the sender should be sent the help message
*/
public boolean execute(CommandSender sender, Command command, String label, String[] args) {
return executor.onCommand(sender, command, label, args);
}
/**
* @param sender Sender of the command
* @param command Command which was executed
* @param label Alias of the command which was used
* @param args Arguments of the command ({@code args[0]} is the sub command's name)
* @return A list of tab completions for the sub command (may be an empty list)
*/
public List<String> getTabCompletions(CommandSender sender, Command command, String label, String[] args) {
if (tabCompleter == null) {
return new ArrayList<>();
}
return tabCompleter.onTabComplete(sender, command, label, args);
}
/**
* @param sender Sender to receive the help message
* @return The help message for the command.
*/
public abstract String getHelpMessage(CommandSender sender);
}

View File

@ -1,110 +0,0 @@
package de.epiceric.shopchest.command;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
class ShopTabCompleter implements TabCompleter {
private ShopChest plugin;
ShopTabCompleter(ShopChest plugin) {
this.plugin = plugin;
}
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
if (command.getName().equalsIgnoreCase(Config.mainCommandName)) {
List<String> createSubCommands = Arrays.asList("admin", "normal");
List<String> configSubCommands = Arrays.asList("add", "remove", "set");
List<String> areaShopRemoveEvents = Arrays.asList("DELETE", "RESELL", "SELL", "UNRENT");
List<String> townyShopPlots = Arrays.asList("ARENA", "COMMERCIAL", "EMBASSY", "FARM", "INN", "JAIL", "RESIDENTIAL", "SPLEEF", "WILDS");
Set<String> configValues = plugin.getConfig().getKeys(true);
ArrayList<String> returnCompletions = new ArrayList<>();
if (args.length == 2) {
if (args[0].equals("config")) {
if (!args[1].equals("")) {
for (String s : configSubCommands) {
if (s.startsWith(args[1])) {
returnCompletions.add(s);
}
}
return returnCompletions;
} else {
return configSubCommands;
}
}
} else if (args.length == 3) {
if (args[0].equals("config")) {
if (!args[2].equals("")) {
for (String s : configValues) {
if (s.startsWith(args[2])) {
returnCompletions.add(s);
}
}
return returnCompletions;
} else {
return new ArrayList<>(configValues);
}
}
} else if (args.length == 4) {
if (args[0].equals("config")) {
if (args[2].equals("towny-shop-plots")) {
if (!args[3].equals("")) {
for (String s : townyShopPlots) {
if (s.startsWith(args[3])) {
returnCompletions.add(s);
}
}
return returnCompletions;
} else {
return townyShopPlots;
}
} else if (args[2].equals("areashop-remove-shops")) {
if (!args[3].equals("")) {
for (String s : areaShopRemoveEvents) {
if (s.startsWith(args[3])) {
returnCompletions.add(s);
}
}
return returnCompletions;
} else {
return areaShopRemoveEvents;
}
}
}
} else if (args.length == 5) {
if (args[0].equals("create")) {
if (!args[4].equals("")) {
for (String s : createSubCommands) {
if (s.startsWith(args[4])) {
returnCompletions.add(s);
}
}
return returnCompletions;
} else {
return createSubCommands;
}
}
}
}
return new ArrayList<>();
}
}

View File

@ -1,602 +0,0 @@
package de.epiceric.shopchest.config;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.language.LanguageUtils;
import de.epiceric.shopchest.sql.Database;
import de.epiceric.shopchest.utils.ItemUtils;
import de.epiceric.shopchest.utils.Utils;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.inventory.ItemStack;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Config {
/**
* The item with which a player can click a shop to retrieve information
**/
public static ItemStack shopInfoItem;
/**
* The default value for the custom WorldGuard flag 'create-shop'
**/
public static boolean wgAllowCreateShopDefault;
/**
* The default value for the custom WorldGuard flag 'use-admin-shop'
**/
public static boolean wgAllowUseAdminShopDefault;
/**
* The default value for the custom WorldGuard flag 'use-shop'
**/
public static boolean wgAllowUseShopDefault;
/**
* The types of town plots residents are allowed to create shops in
**/
public static List<String> townyShopPlotsResidents;
/**
* The types of town plots the mayor is allowed to create shops in
**/
public static List<String> townyShopPlotsMayor;
/**
* The types of town plots the king is allowed to create shops in
**/
public static List<String> townyShopPlotsKing;
/**
* The events of AreaShop when shops in that region should be removed
**/
public static List<String> areashopRemoveShopEvents;
/**
* The hostname used in ShopChest's MySQL database
**/
public static String databaseMySqlHost;
/**
* The port used for ShopChest's MySQL database
**/
public static int databaseMySqlPort;
/**
* The database used for ShopChest's MySQL database
**/
public static String databaseMySqlDatabase;
/**
* The username used in ShopChest's MySQL database
**/
public static String databaseMySqlUsername;
/**
* The password used in ShopChest's MySQL database
**/
public static String databaseMySqlPassword;
/**
* The prefix to be used for database tables
*/
public static String databaseTablePrefix;
/**
* The database type used for ShopChest
**/
public static Database.DatabaseType databaseType;
/**
* The interval in seconds, a ping is sent to the MySQL server
**/
public static int databaseMySqlPingInterval;
/**
* <p>The minimum prices for certain items</p>
* This returns a key set, which contains e.g "STONE", "STONE:1", of the <i>minimum-prices</i> section in ShopChest's config.
* To actually retrieve the minimum price for an item, you have to get the double {@code minimum-prices.<key>}.
**/
public static Set<String> minimumPrices;
/**
* <p>The maximum prices for certain items</p>
* This returns a key set, which contains e.g "STONE", "STONE:1", of the {@code maximum-prices} section in ShopChest's config.
* To actually retrieve the maximum price for an item, you have to get the double {@code maximum-prices.<key>}.
**/
public static Set<String> maximumPrices;
/**
* <p>List containing items, of which players can't create a shop</p>
* If this list contains an item (e.g "STONE", "STONE:1"), it's in the blacklist.
**/
public static List<String> blacklist;
/**
* Whether prices may contain decimals
**/
public static boolean allowDecimalsInPrice;
/**
* Whether the buy price of a shop must be greater than or equal the sell price
**/
public static boolean buyGreaterOrEqualSell;
/**
* Whether buys and sells must be confirmed
**/
public static boolean confirmShopping;
/**
* Whether the shop creation price should be refunded at removal.
*/
public static boolean refundShopCreation;
/**
* <p>Whether the update checker should run on start and notify players on join.</p>
* The command is not affected by this setting and will continue to check for updates.
**/
public static boolean enableUpdateChecker;
/**
* Whether the debug log file should be created
**/
public static boolean enableDebugLog;
/**
* Whether buys and sells should be logged in the database
**/
public static boolean enableEconomyLog;
/**
* Whether WorldGuard integration should be enabled
**/
public static boolean enableWorldGuardIntegration;
/**
* <p>Sets the time limit for cleaning up the economy log in days</p>
*
* If this equals to {@code 0}, the economy log will not be cleaned.
**/
public static int cleanupEconomyLogDays;
/**
* Whether Towny integration should be enabled
**/
public static boolean enableTownyIntegration;
/**
* Whether AuthMe integration should be enabled
**/
public static boolean enableAuthMeIntegration;
/**
* Whether PlotSquared integration should be enabled
**/
public static boolean enablePlotsquaredIntegration;
/**
* Whether uSkyBlock integration should be enabled
**/
public static boolean enableUSkyblockIntegration;
/**
* Whether ASkyBlock integration should be enabled
**/
public static boolean enableASkyblockIntegration;
/**
* Whether IslandWorld integration should be enabled
**/
public static boolean enableIslandWorldIntegration;
/**
* Whether GriefPrevention integration should be enabled
**/
public static boolean enableGriefPreventionIntegration;
/**
* Whether AreaShop integration should be enabled
**/
public static boolean enableAreaShopIntegration;
/**
* Whether the vendor of the shop should get messages about buys and sells
**/
public static boolean enableVendorMessages;
/**
* Whether the extension of a potion or tipped arrow (if available) should be appended to the item name.
**/
public static boolean appendPotionLevelToItemName;
/**
* Whether players are allowed to sell/buy broken items
**/
public static boolean allowBrokenItems;
/**
* Whether only the shop a player is pointing at should be shown
**/
public static boolean onlyShowShopsInSight;
/**
* <p>Whether shops should automatically be removed from the database if an error occurred while loading</p>
* (e.g. when no chest is found at a shop's location)
*/
public static boolean removeShopOnError;
/**
* Whether the item amount should be calculated to fit the available money or inventory space
**/
public static boolean autoCalculateItemAmount;
/**
* Whether players should be able to select an item from the creative inventory
*/
public static boolean creativeSelectItem;
/**
* <p>Whether the mouse buttons are inverted</p>
* <b>Default:</b><br>
* Right-Click: Buy<br>
* Left-Click: Sell
**/
public static boolean invertMouseButtons;
/**
* Whether the hologram's location should be fixed at the bottom
**/
public static boolean hologramFixedBottom;
/**
* Amount every hologram should be lifted
**/
public static double hologramLift;
/**
* The maximum distance between a player and a shop to see the hologram
**/
public static double maximalDistance;
/**
* The maximum distance between a player and a shop to see the shop item
**/
public static double maximalItemDistance;
/**
* The price a player has to pay in order to create a normal shop
**/
public static double shopCreationPriceNormal;
/**
* The price a player has to pay in order to create an admin shop
**/
public static double shopCreationPriceAdmin;
/**
* The default shop limit for players whose limit is not set via a permission
**/
public static int defaultLimit;
/**
* The main command of ShopChest <i>(default: shop)</i>
**/
public static String mainCommandName;
/**
* The language file to use (e.g <i>en_US</i>, <i>de_DE</i>)
**/
public static String languageFile;
/**
* The language configuration of the currently selected language file
*/
public static LanguageConfiguration langConfig;
private ShopChest plugin;
public Config(ShopChest plugin) {
this.plugin = plugin;
plugin.saveDefaultConfig();
reload(true, true, true);
}
/**
* <p>Set a configuration value</p>
* <i>Config is automatically reloaded</i>
*
* @param property Property to change
* @param value Value to set
*/
public void set(String property, String value) {
boolean langChange = (property.equalsIgnoreCase("language-file"));
try {
int intValue = Integer.parseInt(value);
plugin.getConfig().set(property, intValue);
plugin.saveConfig();
reload(false, langChange, false);
return;
} catch (NumberFormatException e) { /* Value not an integer */ }
try {
double doubleValue = Double.parseDouble(value);
plugin.getConfig().set(property, doubleValue);
plugin.saveConfig();
reload(false, langChange, false);
return;
} catch (NumberFormatException e) { /* Value not a double */ }
if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
boolean boolValue = Boolean.parseBoolean(value);
plugin.getConfig().set(property, boolValue);
} else {
plugin.getConfig().set(property, value);
}
plugin.saveConfig();
reload(false, langChange, false);
}
/**
* Add a value to a list in the config.yml.
* If the list does not exist, a new list with the given value will be created
*
* @param property Location of the list
* @param value Value to add
*/
public void add(String property, String value) {
List list = (plugin.getConfig().getList(property) == null) ? new ArrayList<>() : plugin.getConfig().getList(property);
try {
int intValue = Integer.parseInt(value);
list.add(intValue);
plugin.saveConfig();
reload(false, false, false);
return;
} catch (NumberFormatException e) { /* Value not an integer */ }
try {
double doubleValue = Double.parseDouble(value);
list.add(doubleValue);
plugin.saveConfig();
reload(false, false, false);
return;
} catch (NumberFormatException e) { /* Value not a double */ }
if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
boolean boolValue = Boolean.parseBoolean(value);
list.add(boolValue);
} else {
list.add(value);
}
plugin.saveConfig();
reload(false, false, false);
}
public void remove(String property, String value) {
List list = (plugin.getConfig().getList(property) == null) ? new ArrayList<>() : plugin.getConfig().getList(property);
try {
int intValue = Integer.parseInt(value);
list.remove(intValue);
plugin.saveConfig();
reload(false, false, false);
return;
} catch (NumberFormatException e) { /* Value not an integer */ }
try {
double doubleValue = Double.parseDouble(value);
list.remove(doubleValue);
plugin.saveConfig();
reload(false, false, false);
return;
} catch (NumberFormatException e) { /* Value not a double */ }
if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
boolean boolValue = Boolean.parseBoolean(value);
list.remove(boolValue);
} else {
list.remove(value);
}
plugin.saveConfig();
reload(false, false, false);
}
/**
* Reload the configuration values from config.yml
* @param firstLoad Whether the config values have not been loaded before
* @param langReload Whether the language configuration should be reloaded
* @param showMessages Whether console (error) messages should be shown
*/
public void reload(boolean firstLoad, boolean langReload, boolean showMessages) {
plugin.reloadConfig();
shopInfoItem = ItemUtils.getItemStack(plugin.getConfig().getString("shop-info-item"));
wgAllowCreateShopDefault = plugin.getConfig().getBoolean("worldguard-default-flag-values.create-shop");
wgAllowUseAdminShopDefault = plugin.getConfig().getBoolean("worldguard-default-flag-values.use-admin-shop");
wgAllowUseShopDefault = plugin.getConfig().getBoolean("worldguard-default-flag-values.use-shop");
townyShopPlotsResidents = plugin.getConfig().getStringList("towny-shop-plots.residents");
townyShopPlotsMayor = plugin.getConfig().getStringList("towny-shop-plots.mayor");
townyShopPlotsKing = plugin.getConfig().getStringList("towny-shop-plots.king");
areashopRemoveShopEvents = plugin.getConfig().getStringList("areashop-remove-shops");
databaseMySqlPingInterval = plugin.getConfig().getInt("database.mysql.ping-interval");
databaseMySqlHost = plugin.getConfig().getString("database.mysql.hostname");
databaseMySqlPort = plugin.getConfig().getInt("database.mysql.port");
databaseMySqlDatabase = plugin.getConfig().getString("database.mysql.database");
databaseMySqlUsername = plugin.getConfig().getString("database.mysql.username");
databaseMySqlPassword = plugin.getConfig().getString("database.mysql.password");
databaseTablePrefix = plugin.getConfig().getString("database.table-prefix");
databaseType = Database.DatabaseType.valueOf(plugin.getConfig().getString("database.type"));
minimumPrices = (plugin.getConfig().getConfigurationSection("minimum-prices") == null) ? new HashSet<String>() : plugin.getConfig().getConfigurationSection("minimum-prices").getKeys(true);
maximumPrices = (plugin.getConfig().getConfigurationSection("maximum-prices") == null) ? new HashSet<String>() : plugin.getConfig().getConfigurationSection("maximum-prices").getKeys(true);
allowDecimalsInPrice = plugin.getConfig().getBoolean("allow-decimals-in-price");
allowBrokenItems = plugin.getConfig().getBoolean("allow-broken-items");
autoCalculateItemAmount = (allowDecimalsInPrice && plugin.getConfig().getBoolean("auto-calculate-item-amount"));
creativeSelectItem = plugin.getConfig().getBoolean("creative-select-item");
blacklist = (plugin.getConfig().getStringList("blacklist") == null) ? new ArrayList<String>() : plugin.getConfig().getStringList("blacklist");
buyGreaterOrEqualSell = plugin.getConfig().getBoolean("buy-greater-or-equal-sell");
confirmShopping = plugin.getConfig().getBoolean("confirm-shopping");
refundShopCreation = plugin.getConfig().getBoolean("refund-shop-creation");
enableUpdateChecker = plugin.getConfig().getBoolean("enable-update-checker");
enableDebugLog = plugin.getConfig().getBoolean("enable-debug-log");
enableEconomyLog = plugin.getConfig().getBoolean("enable-economy-log");
cleanupEconomyLogDays = plugin.getConfig().getInt("cleanup-economy-log-days");
enableWorldGuardIntegration = plugin.getConfig().getBoolean("enable-worldguard-integration");
enableTownyIntegration = plugin.getConfig().getBoolean("enable-towny-integration");
enableAuthMeIntegration = plugin.getConfig().getBoolean("enable-authme-integration");
enablePlotsquaredIntegration = plugin.getConfig().getBoolean("enable-plotsquared-integration");
enableUSkyblockIntegration = plugin.getConfig().getBoolean("enable-uskyblock-integration");
enableASkyblockIntegration = plugin.getConfig().getBoolean("enable-askyblock-integration");
enableIslandWorldIntegration = plugin.getConfig().getBoolean("enable-islandworld-integration");
enableGriefPreventionIntegration = plugin.getConfig().getBoolean("enable-griefprevention-integration");
enableAreaShopIntegration = plugin.getConfig().getBoolean("enable-areashop-integration");
enableVendorMessages = plugin.getConfig().getBoolean("enable-vendor-messages");
onlyShowShopsInSight = plugin.getConfig().getBoolean("only-show-shops-in-sight");
appendPotionLevelToItemName = plugin.getConfig().getBoolean("append-potion-level-to-item-name");
removeShopOnError = plugin.getConfig().getBoolean("remove-shop-on-error");
invertMouseButtons = plugin.getConfig().getBoolean("invert-mouse-buttons");
hologramFixedBottom = plugin.getConfig().getBoolean("hologram-fixed-bottom");
hologramLift = plugin.getConfig().getDouble("hologram-lift");
maximalDistance = plugin.getConfig().getDouble("maximal-distance");
maximalItemDistance = plugin.getConfig().getDouble("maximal-item-distance");
shopCreationPriceNormal = plugin.getConfig().getDouble("shop-creation-price.normal");
shopCreationPriceAdmin = plugin.getConfig().getDouble("shop-creation-price.admin");
defaultLimit = plugin.getConfig().getInt("shop-limits.default");
mainCommandName = plugin.getConfig().getString("main-command-name");
languageFile = plugin.getConfig().getString("language-file");
if (firstLoad || langReload) loadLanguageConfig(showMessages);
if (!firstLoad && langReload) LanguageUtils.load();
}
/**
* @return ShopChest's {@link LanguageConfiguration}
*/
public LanguageConfiguration getLanguageConfig() {
return langConfig;
}
private Reader getTextResource(String file, boolean showMessages) {
try {
return (Reader) plugin.getClass().getDeclaredMethod("getTextResource", String.class).invoke(plugin, file);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
if (showMessages) plugin.getLogger().severe("Failed to get file from jar: " + file);
plugin.debug("Failed to get file from jar: " + file);
plugin.debug(e);
}
return null;
}
private void loadLanguageConfig(boolean showMessages) {
langConfig = new LanguageConfiguration(plugin, showMessages);
File langFolder = new File(plugin.getDataFolder(), "lang");
String legacy = Utils.getMajorVersion() < 13 ? "-legacy" : "";
if (!(new File(langFolder, "en_US" + legacy + ".lang")).exists())
plugin.saveResource("lang/en_US" + legacy + ".lang", false);
if (!(new File(langFolder, "de_DE" + legacy + ".lang")).exists())
plugin.saveResource("lang/de_DE" + legacy + ".lang", false);
File langConfigFile = new File(langFolder, languageFile + legacy + ".lang");
File langDefaultFile = new File(langFolder, "en_US" + legacy + ".lang");
if (!langConfigFile.exists()) {
if (!langDefaultFile.exists()) {
try {
Reader r = getTextResource("lang/" + langConfigFile.getName(), showMessages);
if (r == null) {
r = getTextResource("lang/en_US" + legacy + ".lang", showMessages);
if (showMessages) plugin.getLogger().info("Using locale \"en_US" + legacy + "\" (Streamed from jar file)");
} else {
if (showMessages)
plugin.getLogger().info("Using locale \"" + langConfigFile.getName().substring(0, langConfigFile.getName().length() - 5) + "\" (Streamed from jar file)");
}
if (r == null) {
if (showMessages) plugin.getLogger().warning("Using default language values");
plugin.debug("Using default language values (#1)");
}
BufferedReader br = new BufferedReader(r);
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append("\n");
line = br.readLine();
}
langConfig.loadFromString(sb.toString());
} catch (IOException | InvalidConfigurationException e) {
if (showMessages) {
plugin.getLogger().warning("Using default language values");
}
plugin.debug("Using default language values (#2)");
plugin.debug(e);
}
} else {
try {
langConfig.load(langDefaultFile);
if (showMessages) plugin.getLogger().info("Using locale \"en_US" + legacy + "\"");
} catch (IOException | InvalidConfigurationException e) {
if (showMessages) {
plugin.getLogger().warning("Using default language values");
}
plugin.debug("Using default language values (#3)");
plugin.debug(e);
}
}
} else {
try {
if (showMessages)
plugin.getLogger().info("Using locale \"" + langConfigFile.getName().substring(0, langConfigFile.getName().length() - 5) + "\"");
langConfig.load(langConfigFile);
} catch (IOException | InvalidConfigurationException e) {
if (showMessages) {
plugin.getLogger().warning("Using default language values");
}
plugin.debug("Using default language values (#4)");
plugin.debug(e);
}
}
}
}

View File

@ -1,243 +0,0 @@
package de.epiceric.shopchest.config;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.utils.Operator;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HologramFormat {
public enum Requirement {
VENDOR, AMOUNT, ITEM_TYPE, ITEM_NAME, HAS_ENCHANTMENT, BUY_PRICE,
SELL_PRICE, HAS_POTION_EFFECT, IS_MUSIC_DISC, IS_POTION_EXTENDED, IS_BANNER_PATTERN,
IS_WRITTEN_BOOK, ADMIN_SHOP, NORMAL_SHOP, IN_STOCK, MAX_STACK, CHEST_SPACE, DURABILITY
}
// no "-" sign since no variable can be negative
// e.g.: 100.0 >= 50.0
private static final Pattern SIMPLE_NUMERIC_CONDITION = Pattern.compile("^(\\d+(?:\\.\\d+)?) ([<>][=]?|[=!]=) (\\d+(?:\\.\\d+)?)$");
// e.g.: "STONE" == "DIAMOND_SWORD"
private static final Pattern SIMPLE_STRING_CONDITION = Pattern.compile("^\"([^\"]*)\" ([=!]=) \"([^\"]*)\"$");
private ScriptEngineManager manager = new ScriptEngineManager();
private ScriptEngine engine = manager.getEngineByName("JavaScript");
private ShopChest plugin;
private File configFile;
private YamlConfiguration config;
public HologramFormat(ShopChest plugin) {
this.configFile = new File(plugin.getDataFolder(), "hologram-format.yml");
this.config = YamlConfiguration.loadConfiguration(configFile);
this.plugin = plugin;
}
/**
* Get the format for the given line of the hologram
* @param line Line of the hologram
* @param reqMap Values of the requirements that might be needed by the format (contains {@code null} if not comparable)
* @param plaMap Values of the placeholders that might be needed by the format
* @return The format of the first working option, or an empty String if no option is working
* because of not fulfilled requirements
*/
public String getFormat(int line, Map<Requirement, Object> reqMap, Map<Placeholder, Object> plaMap) {
ConfigurationSection options = config.getConfigurationSection("lines." + line + ".options");
optionLoop:
for (String key : options.getKeys(false)) {
ConfigurationSection option = options.getConfigurationSection(key);
List<String> requirements = option.getStringList("requirements");
String format = option.getString("format");
for (String sReq : requirements) {
for (Requirement req : reqMap.keySet()) {
if (sReq.contains(req.toString())) {
if (!evalRequirement(sReq, reqMap)) {
continue optionLoop;
}
}
}
}
return evalPlaceholder(format, plaMap);
}
return "";
}
public void reload() {
config = YamlConfiguration.loadConfiguration(configFile);
}
/**
* @return Whether the hologram text has to change dynamically without reloading
*/
public boolean isDynamic() {
int count = getLineCount();
for (int i = 0; i < count; i++) {
ConfigurationSection options = config.getConfigurationSection("lines." + i + ".options");
for (String key : options.getKeys(false)) {
ConfigurationSection option = options.getConfigurationSection(key);
String format = option.getString("format");
if (format.contains(Placeholder.STOCK.toString()) || format.contains(Placeholder.CHEST_SPACE.toString())) {
return true;
}
for (String req : option.getStringList("requirements")) {
if (req.contains(Requirement.IN_STOCK.toString()) || req.contains(Requirement.CHEST_SPACE.toString())) {
return true;
}
}
}
}
return false;
}
/**
* @return Amount of lines in a hologram
*/
public int getLineCount() {
return config.getConfigurationSection("lines").getKeys(false).size();
}
/**
* @return Configuration of the "hologram-format.yml" file
*/
public YamlConfiguration getConfig() {
return config;
}
/**
* Parse and evaluate a condition
* @param condition Condition to evaluate
* @param values Values of the requirements
* @return Result of the condition
*/
public boolean evalRequirement(String condition, Map<Requirement, Object> values) {
String cond = condition;
for (HologramFormat.Requirement req : HologramFormat.Requirement.values()) {
if (cond.contains(req.toString()) && values.containsKey(req)) {
Object val = values.get(req);
String sVal = String.valueOf(val);
if (val instanceof String && !(sVal.startsWith("\"") && sVal.endsWith("\""))) {
sVal = String.format("\"%s\"", sVal);
}
cond = cond.replace(req.toString(), sVal);
}
}
if (cond.equals("true")) {
// e.g.: ADMIN_SHOP
return true;
} else if (cond.equals("false")) {
return false;
} else {
char firstChar = cond.charAt(0);
// numeric cond: first char must be a digit (no variable can be negative)
if (firstChar >= '0' && firstChar <= '9') {
Matcher matcher = SIMPLE_NUMERIC_CONDITION.matcher(cond);
if (matcher.find()) {
Double a, b;
Operator operator;
try {
a = Double.valueOf(matcher.group(1));
operator = Operator.from(matcher.group(2));
b = Double.valueOf(matcher.group(3));
return operator.compare(a, b);
} catch (IllegalArgumentException ignored) {
// should not happen, since regex checked that there is valid number and valid operator
}
}
}
// string cond: first char must be a: "
if (firstChar == '"') {
Matcher matcher = SIMPLE_STRING_CONDITION.matcher(cond);
if (matcher.find()) {
String a, b;
Operator operator;
try {
a = matcher.group(1);
operator = Operator.from(matcher.group(2));
b = matcher.group(3);
return operator.compare(a, b);
} catch (IllegalArgumentException | UnsupportedOperationException ignored) {
// should not happen, since regex checked that there is valid operator
}
}
}
// complex comparison
try {
return (boolean) engine.eval(cond);
} catch (ScriptException e) {
plugin.debug("Failed to eval condition: " + condition);
plugin.debug(e);
return false;
}
}
}
/**
* Parse and evaluate a condition
* @param string Message or hologram format whose containing scripts to execute
* @param values Values of the placeholders
* @return Result of the condition
*/
public String evalPlaceholder(String string, Map<Placeholder, Object> values) {
try {
Matcher matcher = Pattern.compile("\\{([^}]+)}").matcher(string);
String newString = string;
while (matcher.find()) {
String withBrackets = matcher.group();
String script = withBrackets.substring(1, withBrackets.length() - 1);
for (Placeholder placeholder : values.keySet()) {
if (script.contains(placeholder.toString())) {
Object val = values.get(placeholder);
String sVal = String.valueOf(val);
if (val instanceof String && !(sVal.startsWith("\"") && sVal.endsWith("\""))) {
sVal = String.format("\"%s\"", sVal);
}
script = script.replace(placeholder.toString(), sVal);
}
}
String result = String.valueOf(engine.eval(script));
newString = newString.replace(withBrackets, result);
}
return newString;
} catch (ScriptException e) {
plugin.debug("Failed to eval placeholder script in string: " + string);
plugin.debug(e);
}
return string;
}
}

View File

@ -1,126 +0,0 @@
package de.epiceric.shopchest.config;
import de.epiceric.shopchest.ShopChest;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
public class LanguageConfiguration extends FileConfiguration {
private ArrayList<String> lines = new ArrayList<>();
private HashMap<String, String> values = new HashMap<>();
private ShopChest plugin;
private boolean showMessages;
private File file;
public LanguageConfiguration(ShopChest plugin, boolean showMessages) {
this.plugin = plugin;
this.showMessages = showMessages;
}
@Override
public String saveToString() {
StringBuilder sb = new StringBuilder("");
for (String line : lines) {
sb.append(line);
sb.append("\n");
}
return sb.toString();
}
@Override
public String getString(String path, String def) {
for (String key : values.keySet()) {
if (key.equals(path)) {
return values.get(key);
}
}
values.put(path, def);
if (file != null) {
// Append missing entry to loaded language file
try (FileWriter writer = new FileWriter(file, true)) {
writer.write(path + "=" + def + "\n");
if (showMessages)
plugin.getLogger().info("Missing translation for \"" + path + "\" has been added as \"" + def + "\" to the selected language file.");
} catch (IOException e) {
plugin.debug("Failed to add language entry");
plugin.debug(e);
if (showMessages)
plugin.getLogger().severe("Failed to add missing translation for \"" + path + "\" to the selected langauge file.");
}
}
return def;
}
@Override
public void load(File file) throws IOException, InvalidConfigurationException {
this.file = file;
FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append("\n");
line = br.readLine();
}
fis.close();
isr.close();
br.close();
loadFromString(sb.toString());
}
@Override
public void loadFromString(String s) throws InvalidConfigurationException {
String[] lines = s.split("\n");
for (String line : lines) {
if (!line.isEmpty()) {
this.lines.add(line);
if (!line.startsWith("#")) {
if (line.contains("=")) {
if (line.split("=").length >= 2) {
String key = line.split("=")[0];
StringBuilder sbValue = new StringBuilder();
for (int i = 1; i < line.split("=").length; i++) {
if (i > 1) {
sbValue.append("=");
}
sbValue.append(line.split("=")[i]);
}
String value = sbValue.toString();
values.put(key, value);
} else if (line.split("=").length == 1) {
String key = line.split("=")[0];
values.put(key, "");
}
}
}
}
}
}
@Override
protected String buildHeader() {
return null;
}
}

View File

@ -1,43 +0,0 @@
package de.epiceric.shopchest.config;
public enum Placeholder {
VENDOR("%VENDOR%"),
AMOUNT("%AMOUNT%"),
ITEM_NAME("%ITEMNAME%"),
CREATION_PRICE("%CREATION-PRICE%"),
ERROR("%ERROR%"),
ENCHANTMENT("%ENCHANTMENT%"),
MIN_PRICE("%MIN-PRICE%"),
MAX_PRICE("%MAX-PRICE%"),
VERSION("%VERSION%"),
BUY_PRICE("%BUY-PRICE%"),
SELL_PRICE("%SELL-PRICE%"),
LIMIT("%LIMIT%"),
PLAYER("%PLAYER%"),
POTION_EFFECT("%POTION-EFFECT%"),
MUSIC_TITLE("%MUSIC-TITLE%"),
BANNER_PATTERN_NAME("%BANNER-PATTERN-NAME%"),
PROPERTY("%PROPERTY%"),
VALUE("%VALUE%"),
EXTENDED("%EXTENDED%"),
REVENUE("%REVENUE%"),
GENERATION("%GENERATION%"),
STOCK("%STOCK%"),
CHEST_SPACE("%CHEST-SPACE%"),
MAX_STACK("%MAX-STACK%"),
COMMAND("%COMMAND%"),
DURABILITY("%DURABILITY%");
private String name;
Placeholder(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}

View File

@ -1,58 +0,0 @@
package de.epiceric.shopchest.event;
import de.epiceric.shopchest.shop.Shop;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
/**
* Called when a player buys or sells something from or to a shop
*/
public class ShopBuySellEvent extends ShopEvent implements Cancellable {
private Type type;
private int newAmount;
private double newPrice;
private boolean cancelled;
public ShopBuySellEvent(Player player, Shop shop, Type type, int newAmount, double newPrice) {
super(player, shop);
this.type = type;
this.newAmount = newAmount;
this.newPrice = newPrice;
}
/**
* @return Whether the player buys or sells something
*/
public Type getType() {
return type;
}
/**
* @return The amount which might be modified because of automatic item amount calculation
*/
public int getNewAmount() {
return newAmount;
}
/**
* @return The price which might be modified because of automatic item amount calculation
*/
public double getNewPrice() {
return newPrice;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
public enum Type {
BUY,
SELL;
}
}

View File

@ -1,35 +0,0 @@
package de.epiceric.shopchest.event;
import de.epiceric.shopchest.shop.Shop;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
/**
* Called when a player creates a shop (clicks on a chest)
*/
public class ShopCreateEvent extends ShopEvent implements Cancellable {
private double creationPrice;
private boolean cancelled;
public ShopCreateEvent(Player player, Shop shop, double creationPrice) {
super(player, shop);
this.creationPrice = creationPrice;
}
/**
* @return The price the player has to pay in order to create the shop (only if the event is not cancelled)
*/
public double getCreationPrice() {
return creationPrice;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@ -1,42 +0,0 @@
package de.epiceric.shopchest.event;
import de.epiceric.shopchest.shop.Shop;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public abstract class ShopEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private Shop shop;
private Player player;
public ShopEvent(Player player, Shop shop) {
this.player = player;
this.shop = shop;
}
/**
* @return Shop which is involved in this event
*/
public Shop getShop() {
return shop;
}
/**
* @return Player who is involved in this event
*/
public Player getPlayer() {
return player;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}

View File

@ -1,37 +0,0 @@
package de.epiceric.shopchest.event;
import de.epiceric.shopchest.shop.Shop;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
/**
* Called when a player extends a shop (making a chest a double chest)
*/
public class ShopExtendEvent extends ShopEvent implements Cancellable {
private boolean cancelled;
private Location newChestLocation;
public ShopExtendEvent(Player player, Shop shop, Location newChest) {
super(player, shop);
this.newChestLocation = newChest;
}
/**
* @return Location of the placed chest
*/
public Location getNewChestLocation() {
return newChestLocation;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@ -1,26 +0,0 @@
package de.epiceric.shopchest.event;
import de.epiceric.shopchest.shop.Shop;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
/**
* Called when a player retrieves information about a shop (clicks on a chest)
*/
public class ShopInfoEvent extends ShopEvent implements Cancellable {
private boolean cancelled;
public ShopInfoEvent(Player player, Shop shop) {
super(player, shop);
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@ -1,27 +0,0 @@
package de.epiceric.shopchest.event;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class ShopInitializedEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private int amount;
public ShopInitializedEvent(int amount) {
this.amount = amount;
}
public int getAmount() {
return amount;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}

View File

@ -1,26 +0,0 @@
package de.epiceric.shopchest.event;
import de.epiceric.shopchest.shop.Shop;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
/**
* Called when a player opens a shop (clicks on a chest)
*/
public class ShopOpenEvent extends ShopEvent implements Cancellable {
private boolean cancelled;
public ShopOpenEvent(Player player, Shop shop) {
super(player, shop);
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@ -1,26 +0,0 @@
package de.epiceric.shopchest.event;
import de.epiceric.shopchest.shop.Shop;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
/**
* Called when a player wants to create a shop (enters the command)
*/
public class ShopPreCreateEvent extends ShopEvent implements Cancellable {
private boolean cancelled;
public ShopPreCreateEvent(Player player, Shop shop) {
super(player, shop);
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@ -1,46 +0,0 @@
package de.epiceric.shopchest.event;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/**
* Called when a player wants to retrieve information about a shop (enters the command)
*/
public class ShopPreInfoEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private Player player;
private boolean cancelled;
public ShopPreInfoEvent(Player player) {
this.player = player;
}
/**
* @return Player who is involved in this event
*/
public Player getPlayer() {
return player;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}

View File

@ -1,46 +0,0 @@
package de.epiceric.shopchest.event;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/**
* Called when a player wants to open a shop (enters the command)
*/
public class ShopPreOpenEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private Player player;
private boolean cancelled;
public ShopPreOpenEvent(Player player) {
this.player = player;
}
/**
* @return Player who is involved in this event
*/
public Player getPlayer() {
return player;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}

View File

@ -1,46 +0,0 @@
package de.epiceric.shopchest.event;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/**
* Called when a player wants to remove a shop (enters the command)
*/
public class ShopPreRemoveEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private Player player;
private boolean cancelled;
public ShopPreRemoveEvent(Player player) {
this.player = player;
}
/**
* @return Player who is involved in this event
*/
public Player getPlayer() {
return player;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
}

View File

@ -1,46 +0,0 @@
package de.epiceric.shopchest.event;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/**
* Called when a player reloads the shops
*/
public class ShopReloadEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private CommandSender sender;
private boolean cancelled;
public ShopReloadEvent(CommandSender sender) {
this.sender = sender;
}
/**
* @return Sender, who caused the reload ({@link org.bukkit.entity.Player} or {@link org.bukkit.command.ConsoleCommandSender})
*/
public CommandSender getSender() {
return sender;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
@Override
public boolean isCancelled() {
return cancelled;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@ -1,56 +0,0 @@
package de.epiceric.shopchest.event;
import de.epiceric.shopchest.shop.Shop;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import java.util.List;
public class ShopRemoveAllEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private CommandSender sender;
private OfflinePlayer vendor;
private List<Shop> shops;
private boolean cancelled;
public ShopRemoveAllEvent(CommandSender sender, OfflinePlayer vendor, List<Shop> shops) {
this.sender = sender;
this.vendor = vendor;
this.shops = shops;
}
public CommandSender getSender() {
return sender;
}
public OfflinePlayer getVendor() {
return vendor;
}
public List<Shop> getShops() {
return shops;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
@Override
public boolean isCancelled() {
return cancelled;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@ -1,26 +0,0 @@
package de.epiceric.shopchest.event;
import de.epiceric.shopchest.shop.Shop;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
/**
* Called when a player removes a shop (clicks on a chest)
*/
public class ShopRemoveEvent extends ShopEvent implements Cancellable {
private boolean cancelled;
public ShopRemoveEvent(Player player, Shop shop) {
super(player, shop);
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@ -1,9 +0,0 @@
package de.epiceric.shopchest.exceptions;
public class ChestNotFoundException extends Exception {
private static final long serialVersionUID = -6446875473671870708L;
public ChestNotFoundException(String message) {
super(message);
}
}

View File

@ -1,9 +0,0 @@
package de.epiceric.shopchest.exceptions;
public class NotEnoughSpaceException extends Exception {
private static final long serialVersionUID = 3718475607700458355L;
public NotEnoughSpaceException(String message) {
super(message);
}
}

View File

@ -1,9 +0,0 @@
package de.epiceric.shopchest.exceptions;
public class WorldNotFoundException extends Exception {
private static final long serialVersionUID = -555886332156936972L;
public WorldNotFoundException(String worldName) {
super("Could not find world with name \"" + worldName + "\"");
}
}

View File

@ -1,114 +0,0 @@
package de.epiceric.shopchest.external;
import com.github.intellectualsites.plotsquared.plot.flag.Flag;
import com.github.intellectualsites.plotsquared.plot.flag.Flags;
import com.github.intellectualsites.plotsquared.plot.object.Plot;
import org.bukkit.entity.Player;
import de.epiceric.shopchest.ShopChest;
import java.util.Locale;
public class PlotSquaredShopFlag {
private static boolean registered = false;
public enum Group {
OWNERS, MEMBERS, TRUSTED, EVERYONE, NONE
}
public static GroupFlag CREATE_SHOP = new GroupFlag("create-shop");
public static GroupFlag USE_SHOP = new GroupFlag("use-shop");
public static GroupFlag USE_ADMIN_SHOP = new GroupFlag("use-admin-shop");
public static void register(ShopChest plugin) {
if (registered) return;
Flags.registerFlag(CREATE_SHOP);
Flags.registerFlag(USE_SHOP);
Flags.registerFlag(USE_ADMIN_SHOP);
registered = true;
plugin.debug("Registered custom PlotSquared flags");
}
/**
* Check if a flag is allowed for a player on a plot from PlotSquared
* @param plot Plot from PlotSquared
* @param flag Flag to check
* @param p Player to check
* @return Whether the flag is allowed for the player
*/
public static boolean isFlagAllowedOnPlot(Plot plot, GroupFlag flag, Player p) {
if (plot != null && flag != null) {
Group group = plot.getFlag(flag, PlotSquaredShopFlag.Group.NONE);
//ShopChest.getInstance().debug("Flag " + flag.getName() + " is set to " + group);
switch (group) {
case OWNERS:
return plot.getOwners().contains(p.getUniqueId());
case TRUSTED:
return plot.getOwners().contains(p.getUniqueId()) || plot.getTrusted().contains(p.getUniqueId());
case MEMBERS:
return plot.getOwners().contains(p.getUniqueId()) || plot.getTrusted().contains(p.getUniqueId()) || plot.getMembers().contains(p.getUniqueId());
case EVERYONE:
return true;
case NONE:
return false;
}
}
//ShopChest.getInstance().debug("Flag or plot is null, or value of flag is not a group");
return true;
}
public static class GroupFlag extends Flag<Group> {
public GroupFlag(String name) {
super(name);
}
@Override
public String valueToString(Object value) {
return String.valueOf(value);
}
@Override
public Group parseValue(String s) {
String val = s.toLowerCase(Locale.ENGLISH);
switch (val) {
case "owners":
case "owner":
return Group.OWNERS;
case "members":
case "member":
case "helpers":
case "helper":
return Group.MEMBERS;
case "trusted":
return Group.TRUSTED;
case "everyone":
case "all":
return Group.EVERYONE;
case "deny":
case "false":
case "no":
case "0":
case "none":
case "noone":
return Group.NONE;
}
return null;
}
@Override
public String getValueDescription() {
return "Flag value must be a group: 'owner' , 'members', 'trusted', 'everyone' or 'none'";
}
}
}

View File

@ -1,31 +0,0 @@
package de.epiceric.shopchest.external;
import java.util.Optional;
import org.codemc.worldguardwrapper.WorldGuardWrapper;
import org.codemc.worldguardwrapper.flag.IWrappedFlag;
import org.codemc.worldguardwrapper.flag.WrappedState;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
public class WorldGuardShopFlag {
public static void register(final ShopChest plugin) {
WorldGuardWrapper wrapper = WorldGuardWrapper.getInstance();
Optional<IWrappedFlag<WrappedState>> createFlag = wrapper.registerFlag("create-shop",
WrappedState.class, Config.wgAllowCreateShopDefault ? WrappedState.ALLOW : WrappedState.DENY);
Optional<IWrappedFlag<WrappedState>> useFlag = wrapper.registerFlag("use-shop",
WrappedState.class, Config.wgAllowUseShopDefault ? WrappedState.ALLOW : WrappedState.DENY);
Optional<IWrappedFlag<WrappedState>> useAdminFlag = wrapper.registerFlag("use-admin-shop",
WrappedState.class, Config.wgAllowUseAdminShopDefault ? WrappedState.ALLOW : WrappedState.DENY);
plugin.debug("Flag create-shop: " + String.valueOf(createFlag.isPresent()));
plugin.debug("Flag use-shop: " + String.valueOf(useFlag.isPresent()));
plugin.debug("Flag use-admin-shop: " + String.valueOf(useAdminFlag.isPresent()));
}
}

View File

@ -1,62 +0,0 @@
package de.epiceric.shopchest.external.listeners;
import java.util.Set;
import com.wasteofplastic.askyblock.ASkyBlockAPI;
import com.wasteofplastic.askyblock.Island;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.event.ShopCreateEvent;
import de.epiceric.shopchest.event.ShopExtendEvent;
import de.epiceric.shopchest.utils.Utils;
public class ASkyBlockListener implements Listener {
private final ShopChest plugin;
public ASkyBlockListener(ShopChest plugin) {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onCreateShop(ShopCreateEvent e) {
if (!Config.enableASkyblockIntegration)
return;
Set<Location> chestLocations = Utils.getChestLocations(e.getShop());
for (Location loc : chestLocations) {
if (handleForLocation(e.getPlayer(), loc, e))
return;
}
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onExtendShop(ShopExtendEvent e) {
if (!Config.enableASkyblockIntegration)
return;
handleForLocation(e.getPlayer(), e.getNewChestLocation(), e);
}
private boolean handleForLocation(Player player, Location loc, Cancellable e) {
Island island = ASkyBlockAPI.getInstance().getIslandAt(loc);
if (island == null)
return false;
if (!player.getUniqueId().equals(island.getOwner()) && !island.getMembers().contains(player.getUniqueId())) {
e.setCancelled(true);
plugin.debug("Cancel Reason: ASkyBlock");
return true;
}
return false;
}
}

View File

@ -1,62 +0,0 @@
package de.epiceric.shopchest.external.listeners;
import java.util.Set;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.event.ShopCreateEvent;
import de.epiceric.shopchest.event.ShopExtendEvent;
import de.epiceric.shopchest.utils.Utils;
import me.ryanhamshire.GriefPrevention.Claim;
import me.ryanhamshire.GriefPrevention.GriefPrevention;
public class GriefPreventionListener implements Listener {
private final ShopChest plugin;
private final GriefPrevention griefPrevention;
public GriefPreventionListener(ShopChest plugin) {
this.plugin = plugin;
this.griefPrevention = plugin.getGriefPrevention();
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onCreateShop(ShopCreateEvent e) {
if (!Config.enableGriefPreventionIntegration)
return;
Set<Location> chestLocations = Utils.getChestLocations(e.getShop());
for (Location loc : chestLocations) {
if (handleForLocation(e.getPlayer(), loc, e))
return;
}
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onExtendShop(ShopExtendEvent e) {
if (!Config.enableASkyblockIntegration)
return;
handleForLocation(e.getPlayer(), e.getNewChestLocation(), e);
}
private boolean handleForLocation(Player player, Location loc, Cancellable e) {
Claim claim = griefPrevention.dataStore.getClaimAt(loc, false, null);
if (claim == null)
return false;
if (claim.allowContainers(player) != null) {
e.setCancelled(true);
plugin.debug("Cancel Reason: GriefPrevention");
return true;
}
return false;
}
}

View File

@ -1,59 +0,0 @@
package de.epiceric.shopchest.external.listeners;
import java.util.Set;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.event.ShopCreateEvent;
import de.epiceric.shopchest.event.ShopExtendEvent;
import de.epiceric.shopchest.utils.Utils;
import pl.islandworld.api.IslandWorldApi;
public class IslandWorldListener implements Listener {
private final ShopChest plugin;
public IslandWorldListener(ShopChest plugin) {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onCreateShop(ShopCreateEvent e) {
if (!Config.enableIslandWorldIntegration || !IslandWorldApi.isInitialized())
return;
Set<Location> chestLocations = Utils.getChestLocations(e.getShop());
for (Location loc : chestLocations) {
if (handleForLocation(e.getPlayer(), loc, e))
return;
}
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onExtendShop(ShopExtendEvent e) {
if (!Config.enableIslandWorldIntegration || !IslandWorldApi.isInitialized())
return;
handleForLocation(e.getPlayer(), e.getNewChestLocation(), e);
}
private boolean handleForLocation(Player player, Location loc, Cancellable e) {
if (!loc.getWorld().getName().equals(IslandWorldApi.getIslandWorld().getName()))
return false;
if (!IslandWorldApi.canBuildOnLocation(player, loc, true)) {
e.setCancelled(true);
plugin.debug("Cancel Reason: IslandWorld");
return true;
}
return false;
}
}

View File

@ -1,80 +0,0 @@
package de.epiceric.shopchest.external.listeners;
import java.util.Set;
import com.github.intellectualsites.plotsquared.plot.object.Location;
import com.github.intellectualsites.plotsquared.plot.object.Plot;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.event.ShopCreateEvent;
import de.epiceric.shopchest.event.ShopExtendEvent;
import de.epiceric.shopchest.external.PlotSquaredShopFlag;
import de.epiceric.shopchest.utils.Utils;
public class PlotSquaredListener implements Listener {
private final ShopChest plugin;
public PlotSquaredListener(ShopChest plugin) {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onCreateShop(ShopCreateEvent e) {
if (!Config.enablePlotsquaredIntegration)
return;
Set<org.bukkit.Location> chestLocations = Utils.getChestLocations(e.getShop());
for (org.bukkit.Location loc : chestLocations) {
if (handleForLocation(e.getPlayer(), loc, e))
return;
}
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onExtendShop(ShopExtendEvent e) {
if (!Config.enablePlotsquaredIntegration)
return;
handleForLocation(e.getPlayer(), e.getNewChestLocation(), e);
}
// TODO: Outsource shop use external permission
// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
// public void onBuySell(ShopBuySellEvent e) {
// if (!Config.enablePlotsquaredIntegration)
// return;
// ShopType shopType = e.getShop().getShopType();
// GroupFlag flag = shopType == ShopType.ADMIN ? PlotSquaredShopFlag.USE_ADMIN_SHOP : PlotSquaredShopFlag.USE_SHOP;
// Set<org.bukkit.Location> chestLocations = Utils.getChestLocations(e.getShop());
// for (org.bukkit.Location loc : chestLocations) {
// Location plotLocation = new Location(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
// Plot plot = plotLocation.getOwnedPlot();
// if (!isFlagAllowed(plot, flag, e.getPlayer())) {
// e.setCancelled(true);
// plugin.debug("Cancel Reason: PlotSquared");
// return;
// }
// }
// }
private boolean handleForLocation(Player player, org.bukkit.Location loc, Cancellable e) {
Location plotLocation = new Location(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
Plot plot = plotLocation.getOwnedPlot();
if (!PlotSquaredShopFlag.isFlagAllowedOnPlot(plot, PlotSquaredShopFlag.CREATE_SHOP, player)) {
e.setCancelled(true);
plugin.debug("Cancel Reason: PlotSquared");
return true;
}
return false;
}
}

View File

@ -1,84 +0,0 @@
package de.epiceric.shopchest.external.listeners;
import java.util.Optional;
import java.util.Set;
import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
import com.palmergames.bukkit.towny.object.Resident;
import com.palmergames.bukkit.towny.object.Town;
import com.palmergames.bukkit.towny.object.TownBlock;
import com.palmergames.bukkit.towny.object.TownyUniverse;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.event.ShopCreateEvent;
import de.epiceric.shopchest.event.ShopExtendEvent;
import de.epiceric.shopchest.utils.Utils;
public class TownyListener implements Listener {
private final ShopChest plugin;
public TownyListener(ShopChest plugin) {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onCreateShop(ShopCreateEvent e) {
if (!Config.enableTownyIntegration)
return;
Set<Location> chestLocations = Utils.getChestLocations(e.getShop());
for (Location loc : chestLocations) {
if (handleForLocation(e.getPlayer(), loc, e))
return;
}
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onExtendShop(ShopExtendEvent e) {
if (!Config.enablePlotsquaredIntegration)
return;
handleForLocation(e.getPlayer(), e.getNewChestLocation(), e);
}
private boolean handleForLocation(Player player, Location loc, Cancellable e) {
TownBlock townBlock = TownyUniverse.getTownBlock(loc);
if (townBlock == null)
return false;
try {
Town town = townBlock.getTown();
Optional<Resident> playerResident = town.getResidents().stream()
.filter(r -> r.getName().equals(player.getName()))
.findFirst();
if (!playerResident.isPresent()) {
e.setCancelled(true);
plugin.debug("Cancel Reason: Towny (no resident)");
return true;
}
Resident resident = playerResident.get();
String plotType = townBlock.getType().name();
boolean cancel = (resident.isMayor() && !Config.townyShopPlotsMayor.contains(plotType))
|| (resident.isKing() && !Config.townyShopPlotsKing.contains(plotType))
|| (!resident.isKing() && !resident.isMayor() && !Config.townyShopPlotsResidents.contains(plotType));
if (cancel) {
e.setCancelled(true);
plugin.debug("Cancel Reason: Towny (no permission)");
return true;
}
} catch (NotRegisteredException ignored) {
}
return false;
}
}

View File

@ -1,61 +0,0 @@
package de.epiceric.shopchest.external.listeners;
import java.util.Set;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.event.ShopCreateEvent;
import de.epiceric.shopchest.event.ShopExtendEvent;
import de.epiceric.shopchest.utils.Utils;
import us.talabrek.ultimateskyblock.api.IslandInfo;
import us.talabrek.ultimateskyblock.api.uSkyBlockAPI;
public class USkyBlockListener implements Listener {
private final ShopChest plugin;
private final uSkyBlockAPI uSkyBlockAPI;
public USkyBlockListener(ShopChest plugin) {
this.plugin = plugin;
this.uSkyBlockAPI = plugin.getUSkyBlock();
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onCreateShop(ShopCreateEvent e) {
if (!Config.enableUSkyblockIntegration)
return;
Set<Location> chestLocations = Utils.getChestLocations(e.getShop());
for (Location loc : chestLocations) {
if (handleForLocation(e.getPlayer(), loc, e))
return;
}
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onExtendShop(ShopExtendEvent e) {
if (!Config.enablePlotsquaredIntegration)
return;
handleForLocation(e.getPlayer(), e.getNewChestLocation(), e);
}
private boolean handleForLocation(Player player, Location loc, Cancellable e) {
IslandInfo islandInfo = uSkyBlockAPI.getIslandInfo(loc);
if (islandInfo == null)
return false;
if (!player.getName().equals(islandInfo.getLeader()) && !islandInfo.getMembers().contains(player.getName())) {
e.setCancelled(true);
plugin.debug("Cancel Reason: uSkyBlock");
return true;
}
return false;
}
}

View File

@ -1,97 +0,0 @@
package de.epiceric.shopchest.external.listeners;
import java.util.Optional;
import java.util.Set;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.codemc.worldguardwrapper.WorldGuardWrapper;
import org.codemc.worldguardwrapper.flag.IWrappedFlag;
import org.codemc.worldguardwrapper.flag.WrappedState;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.event.ShopCreateEvent;
import de.epiceric.shopchest.event.ShopExtendEvent;
import de.epiceric.shopchest.utils.Utils;
public class WorldGuardListener implements Listener {
private final ShopChest plugin;
private final WorldGuardWrapper wgWrapper;
public WorldGuardListener(ShopChest plugin) {
this.plugin = plugin;
this.wgWrapper = WorldGuardWrapper.getInstance();
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onCreateShop(ShopCreateEvent e) {
if (!Config.enableWorldGuardIntegration)
return;
Set<Location> chestLocations = Utils.getChestLocations(e.getShop());
IWrappedFlag<WrappedState> flag = getStateFlag("create-shop");
for (Location loc : chestLocations) {
if (handleForLocation(e.getPlayer(), loc, e, flag))
return;
}
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onExtendShop(ShopExtendEvent e) {
if (!Config.enableWorldGuardIntegration)
return;
handleForLocation(e.getPlayer(), e.getNewChestLocation(), e, getStateFlag("create-shop"));
}
// TODO: Outsource shop use external permission
// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
// public void onBuySell(ShopBuySellEvent e) {
// if (!Config.enableWorldGuardIntegration)
// return;
// Set<Location> chestLocations = Utils.getChestLocations(e.getShop());
// String flagName = e.getShop().getShopType() == ShopType.ADMIN ? "use-admin-shop" : "use-shop";
// IWrappedFlag<WrappedState> flag = getStateFlag(flagName);
// for (Location loc : chestLocations) {
// WrappedState state = wgWrapper.queryFlag(e.getPlayer(), loc, flag).orElse(WrappedState.DENY);
// if (state == WrappedState.DENY) {
// e.setCancelled(true);
// return;
// }
// }
// }
private boolean handleForLocation(Player player, Location loc, Cancellable e, IWrappedFlag<WrappedState> flag) {
if (flag == null) {
// Flag may have not been registered successfully, so ignore them.
return false;
}
WrappedState state = wgWrapper.queryFlag(player, loc, flag).orElse(WrappedState.DENY);
if (state == WrappedState.DENY) {
e.setCancelled(true);
plugin.debug("Cancel Reason: WorldGuard");
return true;
}
return false;
}
private IWrappedFlag<WrappedState> getStateFlag(String flagName) {
Optional<IWrappedFlag<WrappedState>> flagOptional = wgWrapper.getFlag(flagName, WrappedState.class);
if (!flagOptional.isPresent()) {
plugin.getLogger().severe("Failed to get WorldGuard state flag '" + flagName + "'.");
plugin.debug("WorldGuard state flag '" + flagName + "' is not present!");
return null;
}
return flagOptional.get();
}
}

View File

@ -1,29 +0,0 @@
package de.epiceric.shopchest.language;
import org.bukkit.Material;
public class BannerPatternName {
private Material bannerPatternMaterial;
private String localizedName;
public BannerPatternName(Material bannerPatternMaterial, String localizedName) {
this.bannerPatternMaterial = bannerPatternMaterial;
this.localizedName = localizedName;
}
/**
* @return Localized Name of the Banner Pattern
*/
public String getLocalizedName() {
return localizedName;
}
/**
* @return Material of the Banner Pattern
*/
public Material getBannerPatternMaterial() {
return bannerPatternMaterial;
}
}

View File

@ -1,28 +0,0 @@
package de.epiceric.shopchest.language;
import de.epiceric.shopchest.nms.CustomBookMeta;
public class BookGenerationName {
private String localizedName;
private CustomBookMeta.Generation generation;
public BookGenerationName(CustomBookMeta.Generation generation, String localizedName) {
this.generation = generation;
this.localizedName = localizedName;
}
/**
* @return Generation linked to the name
*/
public CustomBookMeta.Generation getGeneration() {
return generation;
}
/**
* @return Name linked to the book generation
*/
public String getLocalizedName() {
return localizedName;
}
}

View File

@ -1,53 +0,0 @@
package de.epiceric.shopchest.language;
import org.bukkit.enchantments.Enchantment;
public class EnchantmentName {
private Enchantment enchantment;
private String localizedName;
public EnchantmentName(Enchantment enchantment, String localizedName) {
this.enchantment = enchantment;
this.localizedName = localizedName;
}
/**
* @return Enchantment linked to the name
*/
public Enchantment getEnchantment() {
return enchantment;
}
/**
* @return Name linked to the enchantment
*/
public String getLocalizedName() {
return localizedName;
}
public static class EnchantmentLevelName {
private int level;
private String localizedName;
public EnchantmentLevelName(int level, String localizedName) {
this.level = level;
this.localizedName = localizedName;
}
/**
* @return Level linked to the name
*/
public int getLevel() {
return level;
}
/**
* @return Name linked to the level
*/
public String getLocalizedName() {
return localizedName;
}
}
}

View File

@ -1,28 +0,0 @@
package de.epiceric.shopchest.language;
import org.bukkit.entity.EntityType;
public class EntityName {
private String localizedName;
private EntityType entityType;
public EntityName(EntityType entityType, String localizedName) {
this.entityType = entityType;
this.localizedName = localizedName;
}
/**
* @return EntityType linked to the name
*/
public EntityType getEntityType() {
return entityType;
}
/**
* @return Name linked to the EntityType
*/
public String getLocalizedName() {
return localizedName;
}
}

View File

@ -1,42 +0,0 @@
package de.epiceric.shopchest.language;
import org.bukkit.Material;
public class ItemName {
private Material material;
private int subId;
private String localizedName;
public ItemName(Material material, String localizedName) {
this(material, 0, localizedName);
}
public ItemName(Material material, int subId, String localizedName) {
this.material = material;
this.subId = subId;
this.localizedName = localizedName;
}
/**
* @return Material linked to the name
*/
public Material getMaterial() {
return material;
}
/**
* @return Sub ID linked to the name
*/
public int getSubId() {
return subId;
}
/**
* @return Name linked to the item
*/
public String getLocalizedName() {
return localizedName;
}
}

View File

@ -1,29 +0,0 @@
package de.epiceric.shopchest.language;
import org.bukkit.ChatColor;
public class LocalizedMessage {
private Message message;
private String localizedString;
public LocalizedMessage(Message message, String localizedString) {
this.message = message;
this.localizedString = ChatColor.translateAlternateColorCodes('&', localizedString);
}
/**
* @return {@link Message} linked to this object
*/
public Message getMessage() {
return message;
}
/**
* @return Localized Message
*/
public String getLocalizedString() {
return localizedString;
}
}

View File

@ -1,99 +0,0 @@
package de.epiceric.shopchest.language;
public enum Message {
SHOP_CREATED,
ADMIN_SHOP_CREATED,
CHEST_ALREADY_SHOP,
CHEST_BLOCKED,
DOUBLE_CHEST_BLOCKED,
SHOP_REMOVED,
SHOP_REMOVED_REFUND,
ALL_SHOPS_REMOVED,
CHEST_NO_SHOP,
SHOP_CREATE_NOT_ENOUGH_MONEY,
SHOP_INFO_VENDOR,
SHOP_INFO_PRODUCT,
SHOP_INFO_STOCK,
SHOP_INFO_CHEST_SPACE,
SHOP_INFO_PRICE,
SHOP_INFO_DISABLED,
SHOP_INFO_NORMAL,
SHOP_INFO_ADMIN,
BUY_SELL_DISABLED,
BUY_SUCCESS,
BUY_SUCCESS_ADMIN,
SELL_SUCCESS,
SELL_SUCCESS_ADMIN,
SOMEONE_BOUGHT,
SOMEONE_SOLD,
REVENUE_WHILE_OFFLINE,
NOT_ENOUGH_INVENTORY_SPACE,
CHEST_NOT_ENOUGH_INVENTORY_SPACE,
NOT_ENOUGH_MONEY,
NOT_ENOUGH_ITEMS,
VENDOR_NOT_ENOUGH_MONEY,
OUT_OF_STOCK,
VENDOR_OUT_OF_STOCK,
ERROR_OCCURRED,
AMOUNT_PRICE_NOT_NUMBER,
AMOUNT_IS_ZERO,
PRICES_CONTAIN_DECIMALS,
NO_ITEM_IN_HAND,
CLICK_CHEST_CREATE,
CLICK_CHEST_REMOVE,
CLICK_CHEST_INFO,
CLICK_CHEST_OPEN,
CLICK_TO_CONFIRM,
OPENED_SHOP,
CANNOT_BREAK_SHOP,
CANNOT_SELL_BROKEN_ITEM,
BUY_PRICE_TOO_LOW,
SELL_PRICE_TOO_LOW,
BUY_PRICE_TOO_HIGH,
SELL_PRICE_TOO_HIGH,
BUYING_DISABLED,
SELLING_DISABLED,
RELOADED_SHOPS,
SHOP_LIMIT_REACHED,
OCCUPIED_SHOP_SLOTS,
CANNOT_SELL_ITEM,
USE_IN_CREATIVE,
SELECT_ITEM,
ITEM_SELECTED,
CREATION_CANCELLED,
UPDATE_AVAILABLE,
UPDATE_CLICK_TO_DOWNLOAD,
UPDATE_NO_UPDATE,
UPDATE_CHECKING,
UPDATE_ERROR,
NO_PERMISSION_CREATE,
NO_PERMISSION_CREATE_ADMIN,
NO_PERMISSION_CREATE_PROTECTED,
NO_PERMISSION_OPEN_OTHERS,
NO_PERMISSION_BUY,
NO_PERMISSION_SELL,
NO_PERMISSION_BUY_HERE,
NO_PERMISSION_SELL_HERE,
NO_PERMISSION_REMOVE_OTHERS,
NO_PERMISSION_REMOVE_ADMIN,
NO_PERMISSION_RELOAD,
NO_PERMISSION_UPDATE,
NO_PERMISSION_CONFIG,
NO_PERMISSION_EXTEND_OTHERS,
NO_PERMISSION_EXTEND_PROTECTED,
COMMAND_DESC_HEADER,
COMMAND_DESC_FOOTER,
COMMAND_DESC_CREATE,
COMMAND_DESC_CREATE_ADMIN,
COMMAND_DESC_REMOVE,
COMMAND_DESC_INFO,
COMMAND_DESC_REMOVEALL,
COMMAND_DESC_RELOAD,
COMMAND_DESC_UPDATE,
COMMAND_DESC_LIMITS,
COMMAND_DESC_OPEN,
COMMAND_DESC_CONFIG,
CHANGED_CONFIG_SET,
CHANGED_CONFIG_REMOVED,
CHANGED_CONFIG_ADDED
}

View File

@ -1,29 +0,0 @@
package de.epiceric.shopchest.language;
import org.bukkit.Material;
public class MusicDiscName {
private Material musicDiscMaterial;
private String localizedName;
public MusicDiscName(Material musicDiscMaterial, String localizedName) {
this.musicDiscMaterial = musicDiscMaterial;
this.localizedName = localizedName;
}
/**
* @return Localized Title of the Music Disc
*/
public String getLocalizedName() {
return localizedName;
}
/**
* @return Material of the Music Disc
*/
public Material getMusicDiscMaterial() {
return musicDiscMaterial;
}
}

View File

@ -1,29 +0,0 @@
package de.epiceric.shopchest.language;
import org.bukkit.potion.PotionEffectType;
public class PotionEffectName {
private PotionEffectType effect;
private String localizedName;
public PotionEffectName(PotionEffectType effect, String localizedName) {
this.effect = effect;
this.localizedName = localizedName;
}
/**
* @return Potion Effect linked to the name
*/
public PotionEffectType getEffect() {
return effect;
}
/**
* @return Localized Name of the potion effect
*/
public String getLocalizedName() {
return localizedName;
}
}

View File

@ -1,45 +0,0 @@
package de.epiceric.shopchest.language;
import org.bukkit.potion.PotionType;
public class PotionName {
private String localizedName;
private PotionItemType potionItemType;
private PotionType potionType;
public PotionName(PotionItemType potionItemType, PotionType potionType, String localizedName) {
this.potionItemType = potionItemType;
this.localizedName = localizedName;
this.potionType = potionType;
}
/**
* @return {@link PotionItemType} linked to the Potion name
*/
public PotionItemType getPotionItemType() {
return potionItemType;
}
/**
* @return Potion Type linked to the Potion name
*/
public PotionType getPotionType() {
return potionType;
}
/**
* @return Localized Name of the Potion
*/
public String getLocalizedName() {
return localizedName;
}
public enum PotionItemType {
POTION,
LINGERING_POTION,
SPLASH_POTION,
TIPPED_ARROW
}
}

View File

@ -1,29 +0,0 @@
package de.epiceric.shopchest.language;
import de.epiceric.shopchest.config.Placeholder;
public class Replacement {
private Placeholder placeholder;
private String replacement;
public Replacement(Placeholder placeholder, Object replacement) {
this.placeholder = placeholder;
this.replacement = String.valueOf(replacement);
}
/**
* @return String which will replace the placeholder
*/
public String getReplacement() {
return replacement;
}
/**
* @return Placeholder that will be replaced
*/
public Placeholder getPlaceholder() {
return placeholder;
}
}

View File

@ -1,68 +0,0 @@
package de.epiceric.shopchest.listeners;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.shop.Shop;
import me.wiefferink.areashop.events.notify.DeletedRegionEvent;
import me.wiefferink.areashop.events.notify.ResoldRegionEvent;
import me.wiefferink.areashop.events.notify.SoldRegionEvent;
import me.wiefferink.areashop.events.notify.UnrentedRegionEvent;
import me.wiefferink.areashop.regions.GeneralRegion;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.codemc.worldguardwrapper.WorldGuardWrapper;
import org.codemc.worldguardwrapper.region.IWrappedRegion;
public class AreaShopListener implements Listener {
private ShopChest plugin;
public AreaShopListener(ShopChest plugin) {
this.plugin = plugin;
}
@EventHandler
public void onRegionDeleted(DeletedRegionEvent e) {
if (Config.enableAreaShopIntegration && Config.areashopRemoveShopEvents.contains("DELETE")) {
removeShopsInRegion(e.getRegion());
}
}
@EventHandler
public void onRegionUnrented(UnrentedRegionEvent e) {
if (Config.enableAreaShopIntegration && Config.areashopRemoveShopEvents.contains("UNRENT")) {
removeShopsInRegion(e.getRegion());
}
}
@EventHandler
public void onRegionResold(ResoldRegionEvent e) {
if (Config.enableAreaShopIntegration && Config.areashopRemoveShopEvents.contains("RESELL")) {
removeShopsInRegion(e.getRegion());
}
}
@EventHandler
public void onRegionSold(SoldRegionEvent e) {
if (Config.enableAreaShopIntegration && Config.areashopRemoveShopEvents.contains("SELL")) {
removeShopsInRegion(e.getRegion());
}
}
private void removeShopsInRegion(GeneralRegion generalRegion) {
if (!plugin.hasWorldGuard()) return;
for (Shop shop : plugin.getShopUtils().getShopsCopy()) {
if (!shop.getLocation().getWorld().getName().equals(generalRegion.getWorldName())) continue;
for (IWrappedRegion r : WorldGuardWrapper.getInstance().getRegions(shop.getLocation())) {
if (generalRegion.getLowerCaseName().equals(r.getId())) {
plugin.getShopUtils().removeShopById(shop.getID(), true);
break;
}
}
}
}
}

View File

@ -1,30 +0,0 @@
package de.epiceric.shopchest.listeners;
import de.epiceric.shopchest.ShopChest;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockExplodeEvent;
import java.util.ArrayList;
public class BlockExplodeListener implements Listener {
private ShopChest plugin;
public BlockExplodeListener(ShopChest plugin) {
this.plugin = plugin;
}
@EventHandler
public void onBlockExplode(BlockExplodeEvent e) {
ArrayList<Block> bl = new ArrayList<>(e.blockList());
for (Block b : bl) {
if (b.getType().equals(Material.CHEST) || b.getType().equals(Material.TRAPPED_CHEST)) {
if (plugin.getShopUtils().isShop(b.getLocation())) e.blockList().remove(b);
}
}
}
}

View File

@ -1,248 +0,0 @@
package de.epiceric.shopchest.listeners;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.config.Placeholder;
import de.epiceric.shopchest.event.ShopExtendEvent;
import de.epiceric.shopchest.language.LanguageUtils;
import de.epiceric.shopchest.language.Message;
import de.epiceric.shopchest.language.Replacement;
import de.epiceric.shopchest.shop.Shop;
import de.epiceric.shopchest.shop.Shop.ShopType;
import de.epiceric.shopchest.utils.Callback;
import de.epiceric.shopchest.utils.ItemUtils;
import de.epiceric.shopchest.utils.Permissions;
import de.epiceric.shopchest.utils.ShopUtils;
import de.epiceric.shopchest.utils.Utils;
import net.milkbowl.vault.economy.EconomyResponse;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Chest;
import org.bukkit.block.DoubleChest;
import org.bukkit.block.data.type.Chest.Type;
import org.bukkit.entity.Player;
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.BlockPlaceEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.inventory.InventoryMoveItemEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.InventoryHolder;
import java.util.ArrayList;
public class ChestProtectListener implements Listener {
private ShopChest plugin;
private ShopUtils shopUtils;
public ChestProtectListener(ShopChest plugin) {
this.plugin = plugin;
this.shopUtils = plugin.getShopUtils();
}
private void remove(final Shop shop, final Block b, final Player p) {
if (shop.getInventoryHolder() instanceof DoubleChest) {
DoubleChest dc = (DoubleChest) shop.getInventoryHolder();
final Chest l = (Chest) dc.getLeftSide();
final Chest r = (Chest) dc.getRightSide();
Location loc = (b.getLocation().equals(l.getLocation()) ? r.getLocation() : l.getLocation());
final Shop newShop = new Shop(shop.getID(), plugin, shop.getVendor(), shop.getProduct(), loc, shop.getBuyPrice(), shop.getSellPrice(), shop.getShopType());
shopUtils.removeShop(shop, true, new Callback<Void>(plugin) {
@Override
public void onResult(Void result) {
newShop.create(true);
shopUtils.addShop(newShop, true);
}
});
} else {
double creationPrice = shop.getShopType() == ShopType.ADMIN ? Config.shopCreationPriceAdmin : Config.shopCreationPriceNormal;
if (creationPrice > 0 && Config.refundShopCreation && p.getUniqueId().equals(shop.getVendor().getUniqueId())) {
EconomyResponse r = plugin.getEconomy().depositPlayer(p, shop.getLocation().getWorld().getName(), creationPrice);
if (!r.transactionSuccess()) {
plugin.debug("Economy transaction failed: " + r.errorMessage);
p.sendMessage(LanguageUtils.getMessage(Message.ERROR_OCCURRED,
new Replacement(Placeholder.ERROR, r.errorMessage)));
p.sendMessage(LanguageUtils.getMessage(Message.SHOP_REMOVED_REFUND,
new Replacement(Placeholder.CREATION_PRICE, 0)));
} else {
p.sendMessage(LanguageUtils.getMessage(Message.SHOP_REMOVED_REFUND,
new Replacement(Placeholder.CREATION_PRICE, creationPrice)));
}
} else {
p.sendMessage(LanguageUtils.getMessage(Message.SHOP_REMOVED));
}
shopUtils.removeShop(shop, true);
plugin.debug(String.format("%s broke %s's shop (#%d)", p.getName(), shop.getVendor().getName(), shop.getID()));
}
}
@EventHandler(ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent e) {
final Block b = e.getBlock();
if (shopUtils.isShop(b.getLocation())) {
final Shop shop = shopUtils.getShop(e.getBlock().getLocation());
Player p = e.getPlayer();
if (p.isSneaking() && Utils.hasAxeInHand(p)) {
plugin.debug(String.format("%s tries to break %s's shop (#%d)", p.getName(), shop.getVendor().getName(), shop.getID()));
if (shop.getShopType() == Shop.ShopType.ADMIN) {
if (p.hasPermission(Permissions.REMOVE_ADMIN)) {
remove(shop, b, p);
return;
}
} else {
if (shop.getVendor().getUniqueId().equals(p.getUniqueId()) || p.hasPermission(Permissions.REMOVE_OTHER)) {
remove(shop, b, p);
return;
}
}
}
if (shop.getItem() != null) {
shop.getItem().resetForPlayer(p);
}
e.setCancelled(true);
e.getPlayer().sendMessage(LanguageUtils.getMessage(Message.CANNOT_BREAK_SHOP));
}
}
@EventHandler(ignoreCancelled = true)
public void onEntityExplode(EntityExplodeEvent e) {
ArrayList<Block> bl = new ArrayList<>(e.blockList());
for (Block b : bl) {
if (b.getType().equals(Material.CHEST) || b.getType().equals(Material.TRAPPED_CHEST)) {
if (shopUtils.isShop(b.getLocation())) e.blockList().remove(b);
}
}
}
@EventHandler(ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent e) {
final Player p = e.getPlayer();
final Block b = e.getBlockPlaced();
if (!b.getType().equals(Material.CHEST) && !b.getType().equals(Material.TRAPPED_CHEST)) {
return;
}
Chest c = (Chest) b.getState();
Block b2;
// Can't use Utils::getChestLocations since inventory holder
// has not been updated yet in this event (for 1.13+)
if (Utils.getMajorVersion() < 13) {
InventoryHolder ih = c.getInventory().getHolder();
if (!(ih instanceof DoubleChest)) {
return;
}
DoubleChest dc = (DoubleChest) ih;
Chest l = (Chest) dc.getLeftSide();
Chest r = (Chest) dc.getRightSide();
if (b.getLocation().equals(l.getLocation())) {
b2 = r.getBlock();
} else {
b2 = l.getBlock();
}
} else {
org.bukkit.block.data.type.Chest data = (org.bukkit.block.data.type.Chest) c.getBlockData();
if (data.getType() == Type.SINGLE) {
return;
}
BlockFace neighborFacing;
switch (data.getFacing()) {
case NORTH:
neighborFacing = data.getType() == Type.LEFT ? BlockFace.EAST : BlockFace.WEST;
break;
case EAST:
neighborFacing = data.getType() == Type.LEFT ? BlockFace.SOUTH : BlockFace.NORTH;
break;
case SOUTH:
neighborFacing = data.getType() == Type.LEFT ? BlockFace.WEST : BlockFace.EAST;
break;
case WEST:
neighborFacing = data.getType() == Type.LEFT ? BlockFace.NORTH : BlockFace.SOUTH;
break;
default:
neighborFacing = null;
}
b2 = b.getRelative(neighborFacing);
}
final Shop shop = shopUtils.getShop(b2.getLocation());
if (shop == null)
return;
plugin.debug(String.format("%s tries to extend %s's shop (#%d)", p.getName(), shop.getVendor().getName(), shop.getID()));
ShopExtendEvent event = new ShopExtendEvent(p, shop, b.getLocation());
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled() && !p.hasPermission(Permissions.EXTEND_PROTECTED)) {
e.setCancelled(true);
p.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_EXTEND_PROTECTED));
return;
}
if (!p.getUniqueId().equals(shop.getVendor().getUniqueId()) && !p.hasPermission(Permissions.EXTEND_OTHER)) {
e.setCancelled(true);
p.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_EXTEND_OTHERS));
return;
}
if (!ItemUtils.isAir(b.getRelative(BlockFace.UP).getType())) {
e.setCancelled(true);
p.sendMessage(LanguageUtils.getMessage(Message.CHEST_BLOCKED));
return;
}
final Shop newShop = new Shop(shop.getID(), plugin, shop.getVendor(), shop.getProduct(), shop.getLocation(), shop.getBuyPrice(), shop.getSellPrice(), shop.getShopType());
shopUtils.removeShop(shop, true, new Callback<Void>(plugin) {
@Override
public void onResult(Void result) {
newShop.create(true);
shopUtils.addShop(newShop, true);
plugin.debug(String.format("%s extended %s's shop (#%d)", p.getName(), shop.getVendor().getName(), shop.getID()));
}
});
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onItemMove(InventoryMoveItemEvent e) {
if ((e.getSource().getType().equals(InventoryType.CHEST)) && (!e.getInitiator().getType().equals(InventoryType.PLAYER))) {
if (e.getSource().getHolder() instanceof DoubleChest) {
DoubleChest dc = (DoubleChest) e.getSource().getHolder();
Chest r = (Chest) dc.getRightSide();
Chest l = (Chest) dc.getLeftSide();
if (shopUtils.isShop(r.getLocation()) || shopUtils.isShop(l.getLocation())) e.setCancelled(true);
} else if (e.getSource().getHolder() instanceof Chest) {
Chest c = (Chest) e.getSource().getHolder();
if (shopUtils.isShop(c.getLocation())) e.setCancelled(true);
}
}
}
}

View File

@ -1,179 +0,0 @@
package de.epiceric.shopchest.listeners;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
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.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryMoveItemEvent;
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Placeholder;
import de.epiceric.shopchest.language.LanguageUtils;
import de.epiceric.shopchest.language.Message;
import de.epiceric.shopchest.language.Replacement;
import de.epiceric.shopchest.utils.ClickType;
import de.epiceric.shopchest.utils.ClickType.SelectClickType;
public class CreativeModeListener implements Listener {
private ShopChest plugin;
public CreativeModeListener(ShopChest plugin) {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onInventoryClick(InventoryClickEvent e) {
HumanEntity entity = e.getWhoClicked();
if (!(entity instanceof Player))
return;
Player p = (Player) entity;
ClickType clickType = ClickType.getPlayerClickType(p);
if (clickType instanceof SelectClickType) {
e.setCancelled(true);
if (e.getCursor() == null || e.getCursor().getType() == Material.AIR)
return;
ClickType.removePlayerClickType(p);
((SelectClickType) clickType).setItem(e.getCursor());
p.closeInventory();
p.sendMessage(LanguageUtils.getMessage(Message.ITEM_SELECTED,
new Replacement(Placeholder.ITEM_NAME, LanguageUtils.getItemName(e.getCursor()))));
plugin.getShopCommand().createShopAfterSelected(p, (SelectClickType) clickType);
}
}
@EventHandler
public void onPlayerCloseInventory(InventoryCloseEvent e) {
HumanEntity entity = e.getPlayer();
if (!(entity instanceof Player))
return;
Player p = (Player) entity;
ClickType clickType = ClickType.getPlayerClickType(p);
if (!(clickType instanceof SelectClickType))
return;
ClickType.removePlayerClickType(p);
p.sendMessage(LanguageUtils.getMessage(Message.CREATION_CANCELLED));
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent e) {
// Reset game mode on quit if SelectClickType is set
Player p = e.getPlayer();
ClickType.removePlayerClickType(p);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onInventoryDrag(InventoryDragEvent e) {
// Cancel any inventory drags if SelectClickType is set
HumanEntity entity = e.getWhoClicked();
if (!(entity instanceof Player))
return;
ClickType clickType = ClickType.getPlayerClickType((Player) entity);
if (clickType instanceof SelectClickType)
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onInventoryMove(InventoryMoveItemEvent e) {
// Cancel any inventory movement if SelectClickType is set
if (e.getSource().getHolder() instanceof Player) {
Player p = (Player) e.getSource().getHolder();
ClickType clickType = ClickType.getPlayerClickType(p);
if (clickType instanceof SelectClickType)
e.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerPickup(PlayerPickupItemEvent e) {
// Cancel any item pickups if SelectClickType is set
ClickType clickType = ClickType.getPlayerClickType(e.getPlayer());
if (clickType instanceof SelectClickType)
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onBlockBreak(BlockBreakEvent e) {
// Cancel any block breaks if SelectClickType is set
ClickType clickType = ClickType.getPlayerClickType(e.getPlayer());
if (clickType instanceof SelectClickType)
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onBlockPlace(BlockPlaceEvent e) {
// Cancel any block places if SelectClickType is set
ClickType clickType = ClickType.getPlayerClickType(e.getPlayer());
if (clickType instanceof SelectClickType)
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onBlockMultiPlace(BlockMultiPlaceEvent e) {
// Cancel any block places if SelectClickType is set
ClickType clickType = ClickType.getPlayerClickType(e.getPlayer());
if (clickType instanceof SelectClickType)
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerInteract(PlayerInteractEvent e) {
// Cancel any interactions if SelectClickType is set
ClickType clickType = ClickType.getPlayerClickType(e.getPlayer());
if (clickType instanceof SelectClickType)
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent e) {
// Cancel any entity interactions if SelectClickType is set
ClickType clickType = ClickType.getPlayerClickType(e.getPlayer());
if (clickType instanceof SelectClickType)
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerDamageEntity(EntityDamageByEntityEvent e) {
// Cancel any entity damaging if SelectClickType is set
Entity entity = e.getDamager();
if (!(entity instanceof Player))
return;
ClickType clickType = ClickType.getPlayerClickType((Player) entity);
if (clickType instanceof SelectClickType)
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerMove(PlayerMoveEvent e) {
// Cancel any player movement if SelectClickType is set
ClickType clickType = ClickType.getPlayerClickType(e.getPlayer());
if (clickType instanceof SelectClickType)
e.setCancelled(true);
}
}

View File

@ -1,63 +0,0 @@
package de.epiceric.shopchest.listeners;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.config.Placeholder;
import de.epiceric.shopchest.language.LanguageUtils;
import de.epiceric.shopchest.language.Message;
import de.epiceric.shopchest.language.Replacement;
import de.epiceric.shopchest.utils.Callback;
import de.epiceric.shopchest.utils.Permissions;
import de.epiceric.shopchest.utils.Utils;
public class NotifyPlayerOnJoinListener implements Listener {
private ShopChest plugin;
public NotifyPlayerOnJoinListener(ShopChest plugin) {
this.plugin = plugin;
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent e) {
final Player p = e.getPlayer();
if (plugin.isUpdateNeeded() && Config.enableUpdateChecker) {
if (p.hasPermission(Permissions.UPDATE_NOTIFICATION)) {
Utils.sendUpdateMessage(plugin, p);
}
}
plugin.getShopDatabase().getLastLogout(p, new Callback<Long>(plugin) {
@Override
public void onResult(Long result) {
if (result < 0) {
// No logout saved, probably first time joining.
return;
}
plugin.getShopDatabase().getRevenue(p, result, new Callback<Double>(plugin) {
@Override
public void onResult(Double result) {
if (result != 0) {
p.sendMessage(LanguageUtils.getMessage(Message.REVENUE_WHILE_OFFLINE,
new Replacement(Placeholder.REVENUE, String.valueOf(result))));
}
}
});
}
});
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent e) {
plugin.getShopDatabase().logLogout(e.getPlayer(), null);
}
}

View File

@ -1,150 +0,0 @@
package de.epiceric.shopchest.listeners;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.shop.Shop;
import de.epiceric.shopchest.utils.ShopUtils;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.*;
import org.bukkit.event.player.PlayerBucketEmptyEvent;
import org.bukkit.event.world.StructureGrowEvent;
public class ShopItemListener implements Listener {
private ShopUtils shopUtils;
public ShopItemListener(ShopChest plugin) {
this.shopUtils = plugin.getShopUtils();
}
@EventHandler(priority = EventPriority.HIGH)
public void onBlockPlace(BlockPlaceEvent e) {
Block b = e.getBlockPlaced();
Block below = b.getRelative(BlockFace.DOWN);
if (shopUtils.isShop(below.getLocation())) {
Shop shop = shopUtils.getShop(below.getLocation());
if (shop.getItem() != null) {
shop.getItem().resetForPlayer(e.getPlayer());
}
e.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onMultiBlockPlace(BlockMultiPlaceEvent e) {
for (BlockState blockState : e.getReplacedBlockStates()) {
Block below = blockState.getBlock().getRelative(BlockFace.DOWN);
if (shopUtils.isShop(below.getLocation())) {
Shop shop = shopUtils.getShop(below.getLocation());
if (shop.getItem() != null) {
shop.getItem().resetForPlayer(e.getPlayer());
}
e.setCancelled(true);
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onPistonExtend(BlockPistonExtendEvent e) {
// If the piston would only move itself
Block airAfterPiston = e.getBlock().getRelative(e.getDirection());
Block belowAir = airAfterPiston.getRelative(BlockFace.DOWN);
if (shopUtils.isShop(belowAir.getLocation())) {
e.setCancelled(true);
return;
}
for (Block b : e.getBlocks()) {
Block newBlock = b.getRelative(e.getDirection());
Block belowNewBlock = newBlock.getRelative(BlockFace.DOWN);
if (shopUtils.isShop(belowNewBlock.getLocation())) e.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onPistonRetract(BlockPistonRetractEvent e) {
for (Block b : e.getBlocks()) {
Block newBlock = b.getRelative(e.getDirection());
Block belowNewBlock = newBlock.getRelative(BlockFace.DOWN);
if (shopUtils.isShop(belowNewBlock.getLocation())) {
e.setCancelled(true);
for (Player p : Bukkit.getOnlinePlayers()) {
Shop shop = shopUtils.getShop(belowNewBlock.getLocation());
if (shop.getItem() != null) {
shop.getItem().resetForPlayer(p);
}
}
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onLiquidFlow(BlockFromToEvent e) {
Block b = e.getToBlock();
Block below = b.getRelative(BlockFace.DOWN);
if (shopUtils.isShop(below.getLocation())) e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGH)
public void onBucketEmpty(PlayerBucketEmptyEvent e) {
Block clicked = e.getBlockClicked();
Block underWater = clicked.getRelative(BlockFace.DOWN).getRelative(e.getBlockFace());
if (shopUtils.isShop(clicked.getLocation())) {
if (e.getBucket() == Material.LAVA_BUCKET) {
Shop shop = shopUtils.getShop(clicked.getLocation());
if (shop.getItem() != null) {
shop.getItem().resetForPlayer(e.getPlayer());
}
}
} else if (shopUtils.isShop(underWater.getLocation())) {
if (e.getBucket() == Material.LAVA_BUCKET) {
Shop shop = shopUtils.getShop(underWater.getLocation());
if (shop.getItem() != null) {
shop.getItem().resetForPlayer(e.getPlayer());
}
}
} else {
return;
}
e.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGH)
public void onStructureGrow(StructureGrowEvent e) {
for (BlockState state : e.getBlocks()) {
Block newBlock = state.getBlock();
if (shopUtils.isShop(newBlock.getLocation()) || shopUtils.isShop(newBlock.getRelative(BlockFace.DOWN).getLocation())) {
e.setCancelled(true);
}
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onBlockGrow(BlockGrowEvent e) {
Block newBlock = e.getNewState().getBlock();
if (shopUtils.isShop(newBlock.getLocation()) || shopUtils.isShop(newBlock.getRelative(BlockFace.DOWN).getLocation())) {
e.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.HIGH)
public void onBlockSpread(BlockSpreadEvent e) {
Block newBlock = e.getNewState().getBlock();
if (shopUtils.isShop(newBlock.getLocation()) || shopUtils.isShop(newBlock.getRelative(BlockFace.DOWN).getLocation())) {
e.setCancelled(true);
}
}
}

View File

@ -1,105 +0,0 @@
package de.epiceric.shopchest.listeners;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.shop.Shop;
import de.epiceric.shopchest.utils.Callback;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.scheduler.BukkitRunnable;
public class ShopUpdateListener implements Listener {
private ShopChest plugin;
public ShopUpdateListener(ShopChest plugin) {
this.plugin = plugin;
}
@EventHandler
public void onPlayerLeave(PlayerQuitEvent e) {
// If done without delay, Bukkit#getOnlinePlayers() would still
// contain the player even though he left, so the shop updater
// would show the shop again.
new BukkitRunnable(){
@Override
public void run() {
for (Shop shop : plugin.getShopUtils().getShops()) {
if (shop.hasItem()) {
shop.getItem().resetVisible(e.getPlayer());
}
if (shop.hasHologram()) {
shop.getHologram().resetVisible(e.getPlayer());
}
}
plugin.getShopUtils().resetPlayerLocation(e.getPlayer());
}
}.runTaskLater(plugin, 1L);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerTeleport(PlayerTeleportEvent e) {
Location from = e.getFrom();
Location to = e.getTo();
final Player p = e.getPlayer();
// Wait till the chunk should have loaded on the client
if (!from.getWorld().getName().equals(to.getWorld().getName())
|| from.getChunk().getX() != to.getChunk().getX()
|| from.getChunk().getZ() != to.getChunk().getZ()) {
new BukkitRunnable() {
@Override
public void run() {
plugin.getUpdater().queue(() -> {
if (p.isOnline()) {
for (Shop shop : plugin.getShopUtils().getShops()) {
if (shop.hasItem()) {
shop.getItem().hidePlayer(p);
}
if (shop.hasHologram()) {
shop.getHologram().hidePlayer(p);
}
}
plugin.getShopUtils().resetPlayerLocation(p);
}
});
plugin.getUpdater().updateShops(p);
}
}.runTaskLater(plugin, 15L);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerMove(PlayerMoveEvent e) {
plugin.getUpdater().updateShops(e.getPlayer());
}
@EventHandler
public void onWorldLoad(WorldLoadEvent e) {
final String worldName = e.getWorld().getName();
plugin.getShopUtils().reloadShops(false, false, new Callback<Integer>(plugin) {
@Override
public void onResult(Integer result) {
plugin.getLogger().info(String.format("Reloaded %d shops because a new world '%s' was loaded", result, worldName));
plugin.debug(String.format("Reloaded %d shops because a new world '%s' was loaded", result, worldName));
}
@Override
public void onError(Throwable throwable) {
// Database connection probably failed => disable plugin to prevent more errors
plugin.getLogger().severe("No database access. Disabling ShopChest");
if (throwable != null) plugin.getLogger().severe(throwable.getMessage());
plugin.getServer().getPluginManager().disablePlugin(plugin);
}
});
}
}

View File

@ -1,89 +0,0 @@
package de.epiceric.shopchest.listeners;
import java.util.Optional;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Chest;
import org.bukkit.entity.Player;
import org.bukkit.event.Event.Result;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.codemc.worldguardwrapper.WorldGuardWrapper;
import org.codemc.worldguardwrapper.event.WrappedUseBlockEvent;
import org.codemc.worldguardwrapper.flag.IWrappedFlag;
import org.codemc.worldguardwrapper.flag.WrappedState;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.shop.Shop;
import de.epiceric.shopchest.utils.ClickType;
import de.epiceric.shopchest.utils.ClickType.EnumClickType;
public class WorldGuardListener implements Listener {
private ShopChest plugin;
public WorldGuardListener(ShopChest plugin) {
this.plugin = plugin;
}
private boolean isAllowed(Player player, Location location) {
ClickType clickType = ClickType.getPlayerClickType(player);
if (clickType != null && clickType.getClickType() == EnumClickType.CREATE) {
// If the player is about to create a shop, but does not have
// access to the chest, show the 'permission denied' message
// (if not previously set to allowed by another plugin).
// If the player can open the chest, that message should be hidden.
WorldGuardWrapper wgWrapper = WorldGuardWrapper.getInstance();
Optional<IWrappedFlag<WrappedState>> flag = wgWrapper.getFlag("chest-access", WrappedState.class);
if (!flag.isPresent()) plugin.debug("WorldGuard flag 'chest-access' is not present!");
WrappedState state = flag.map(f -> wgWrapper.queryFlag(player, location, f).orElse(WrappedState.DENY)).orElse(WrappedState.DENY);
return state == WrappedState.ALLOW;
}
Shop shop = plugin.getShopUtils().getShop(location);
if (shop != null) {
// Don't show 'permission denied' messages for any kind of
// shop interaction even if block interaction is not
// allowed in the region.
return true;
}
return false;
}
@EventHandler(priority = EventPriority.LOW)
public void onUseBlock(WrappedUseBlockEvent event) {
if (Config.enableWorldGuardIntegration) {
Player player = event.getPlayer();
if (event.getOriginalEvent() instanceof PlayerInteractEvent) {
Block block = event.getBlocks().get(0);
Material type = block.getType();
if (type == Material.CHEST || type == Material.TRAPPED_CHEST) {
if (isAllowed(player, block.getLocation())) {
event.setResult(Result.ALLOW);
}
}
} else if (event.getOriginalEvent() instanceof InventoryOpenEvent) {
InventoryOpenEvent orig = (InventoryOpenEvent) event.getOriginalEvent();
if (orig.getInventory().getHolder() instanceof Chest) {
if (isAllowed(player, ((Chest) orig.getInventory().getHolder()).getLocation())) {
event.setResult(Result.ALLOW);
}
}
}
}
}
}

View File

@ -1,129 +0,0 @@
package de.epiceric.shopchest.nms;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.utils.Utils;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import java.lang.reflect.Field;
import java.util.UUID;
public class ArmorStandWrapper {
private final Class<?> packetPlayOutEntityDestroyClass = Utils.getNMSClass("PacketPlayOutEntityDestroy");
private final Class<?> packetPlayOutEntityMetadataClass = Utils.getNMSClass("PacketPlayOutEntityMetadata");
private final Class<?> packetPlayOutEntityTeleportClass = Utils.getNMSClass("PacketPlayOutEntityTeleport");
private final Class<?> dataWatcherClass = Utils.getNMSClass("DataWatcher");
private final UUID uuid = UUID.randomUUID();
private final int entityId;
private ShopChest plugin;
private Object entity;
private Location location;
private String customName;
public ArmorStandWrapper(ShopChest plugin, Location location, String customName, boolean interactable) {
this.plugin = plugin;
this.location = location;
this.customName = customName;
this.entityId = Utils.getFreeEntityId();
}
public void setVisible(Player player, boolean visible) {
try {
if (visible) {
Object dataWatcher = Utils.createDataWatcher(customName, null);
Utils.sendPacket(plugin, Utils.createPacketSpawnEntity(plugin, entityId, uuid, location, EntityType.ARMOR_STAND), player);
Utils.sendPacket(plugin, packetPlayOutEntityMetadataClass.getConstructor(int.class, dataWatcherClass, boolean.class)
.newInstance(entityId, dataWatcher, true), player);
} else if (entityId != -1) {
Utils.sendPacket(plugin, packetPlayOutEntityDestroyClass.getConstructor(int[].class).newInstance((Object) new int[]{entityId}), player);
}
} catch (ReflectiveOperationException e) {
plugin.getLogger().severe("Could not change hologram visibility");
plugin.debug("Could not change armor stand visibility");
plugin.debug(e);
}
}
public void setLocation(Location location) {
this.location = location;
try {
Object packet = packetPlayOutEntityTeleportClass.getConstructor().newInstance();
Field[] fields = packetPlayOutEntityTeleportClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
}
boolean isPre9 = Utils.getMajorVersion() < 9;
fields[0].set(packet, entityId);
double y = location.getY() + (Utils.getServerVersion().equals("v1_8_R1") ? 0 : 1.975);
if (isPre9) {
fields[1].set(packet, (int)(location.getX() * 32));
fields[2].set(packet, (int)(y * 32));
fields[3].set(packet, (int)(location.getZ() * 32));
} else {
fields[1].set(packet, location.getX());
fields[2].set(packet, y);
fields[3].set(packet, location.getZ());
}
fields[4].set(packet, (byte) 0);
fields[5].set(packet, (byte) 0);
fields[6].set(packet, true);
for (Player player : location.getWorld().getPlayers()) {
Utils.sendPacket(plugin, packet, player);
}
} catch (ReflectiveOperationException e) {
plugin.getLogger().severe("Could not set hologram location");
plugin.debug("Could not set armor stand location");
plugin.debug(e);
}
}
public void setCustomName(String customName) {
this.customName = customName;
Object dataWatcher = Utils.createDataWatcher(customName, null);
try {
Object packet = packetPlayOutEntityMetadataClass.getConstructor(int.class, dataWatcherClass, boolean.class)
.newInstance(entityId, dataWatcher, true);
for (Player player : location.getWorld().getPlayers()) {
Utils.sendPacket(plugin, packet, player);
}
} catch (ReflectiveOperationException e) {
plugin.getLogger().severe("Could not set hologram text");
plugin.debug("Could not set armor stand custom name");
plugin.debug(e);
}
}
public void remove() {
for (Player player : location.getWorld().getPlayers()) {
setVisible(player, false);
}
}
public int getEntityId() {
return entityId;
}
public UUID getUuid() {
return uuid;
}
public Location getLocation() {
return location.clone();
}
public String getCustomName() {
return customName;
}
public Object getEntity() {
return entity;
}
}

View File

@ -1,90 +0,0 @@
package de.epiceric.shopchest.nms;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.utils.Utils;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.InvocationTargetException;
// For versions below 1.9.4, since Bukkit's BookMeta
// didn't have generations in those versions
public class CustomBookMeta {
public enum Generation {
ORIGINAL,
COPY_OF_ORIGINAL,
COPY_OF_COPY,
TATTERED
}
public static Generation getGeneration(ItemStack book) {
try {
Class<?> craftItemStackClass = Utils.getCraftClass("inventory.CraftItemStack");
if (craftItemStackClass == null) {
ShopChest.getInstance().debug("Failed to get NBTGeneration: Could not find CraftItemStack class");
return null;
}
Object nmsStack = craftItemStackClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, book);
Object nbtTagCompound = nmsStack.getClass().getMethod("getTag").invoke(nmsStack);
if (nbtTagCompound == null) {
ShopChest.getInstance().debug("Failed to get NBTGeneration: getTag returned null");
return null;
}
Object generationObject = nbtTagCompound.getClass().getMethod("getInt", String.class).invoke(nbtTagCompound, "generation");
if (generationObject == null) {
ShopChest.getInstance().debug("Failed to get NBTGeneration: getInt returned null");
return null;
}
if (generationObject instanceof Integer) {
int generation = (Integer) generationObject;
if (generation > 3) generation = 3;
return Generation.values()[generation];
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
ShopChest.getInstance().getLogger().severe("Failed to get NBTEntityID with reflection");
ShopChest.getInstance().debug("Failed to get NBTEntityID with reflection");
ShopChest.getInstance().debug(e);
}
return null;
}
public static void setGeneration(ItemStack book, Generation generation) {
try {
Class<?> craftItemStackClass = Utils.getCraftClass("inventory.CraftItemStack");
if (craftItemStackClass == null) {
ShopChest.getInstance().debug("Failed to get NBTGeneration: Could not find CraftItemStack class");
return;
}
Object nmsStack = craftItemStackClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, book);
Object nbtTagCompound = nmsStack.getClass().getMethod("getTag").invoke(nmsStack);
if (nbtTagCompound == null) {
ShopChest.getInstance().debug("Failed to get NBTGeneration: getTag returned null");
return;
}
nbtTagCompound.getClass().getMethod("setInt", String.class, int.class)
.invoke(nbtTagCompound, "generation", generation.ordinal());
nmsStack.getClass().getMethod("setTag", nbtTagCompound.getClass()).invoke(nmsStack, nbtTagCompound);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
ShopChest.getInstance().getLogger().severe("Failed to get NBTEntityID with reflection");
ShopChest.getInstance().debug("Failed to get NBTEntityID with reflection");
ShopChest.getInstance().debug(e);
}
}
}

View File

@ -1,277 +0,0 @@
package de.epiceric.shopchest.nms;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Player;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class Hologram {
private static final List<Hologram> HOLOGRAMS = new ArrayList<>();
/**
* @param armorStand Armor stand that's part of a hologram
* @return Hologram, the armor stand is part of
*/
public static Hologram getHologram(ArmorStand armorStand) {
for (Hologram hologram : HOLOGRAMS) {
if (hologram.contains(armorStand)) {
return hologram;
}
}
return null;
}
/**
* @param armorStand Armor stand to check
* @return Whether the armor stand is part of a hologram
*/
public static boolean isPartOfHologram(ArmorStand armorStand) {
return getHologram(armorStand) != null;
}
// concurrent since update task is in async thread
// since this is a fake entity, hologram is hidden per default
private final Set<UUID> viewers = Collections.newSetFromMap(new ConcurrentHashMap<UUID, Boolean>());
private final List<ArmorStandWrapper> wrappers = new ArrayList<>();
private final Location location;
private final ShopChest plugin;
private boolean exists;
public Hologram(ShopChest plugin, String[] lines, Location location) {
this.plugin = plugin;
this.location = location;
for (int i = 0; i < lines.length; i++) {
addLine(i, lines[i]);
}
this.exists = true;
HOLOGRAMS.add(this);
}
/**
* @return Location of the hologram
*/
public Location getLocation() {
return location.clone();
}
/**
* @return Whether the hologram exists and is not dead
*/
public boolean exists() {
return exists;
}
/**
* @param armorStand Armor stand to check
* @return Whether the given armor stand is part of the hologram
*/
public boolean contains(ArmorStand armorStand) {
for (ArmorStandWrapper wrapper : wrappers) {
if (armorStand.getUniqueId().equals(wrapper.getUuid())) {
return true;
}
}
return false;
}
/**
* @return A list of {@link ArmorStandWrapper}s of this hologram
*/
public List<ArmorStandWrapper> getArmorStandWrappers() {
return wrappers;
}
/**
* @param p Player to check
* @return Whether the hologram is visible to the player
*/
public boolean isVisible(Player p) {
return viewers.contains(p.getUniqueId());
}
/**
* @param p Player to which the hologram should be shown
*/
public void showPlayer(Player p) {
showPlayer(p, false);
}
/**
* @param p Player to which the hologram should be shown
* @param force Whether to force showing the hologram
*/
public void showPlayer(Player p, boolean force) {
if (viewers.add(p.getUniqueId()) || force) {
togglePlayer(p, true);
}
}
/**
* @param p Player from which the hologram should be hidden
*/
public void hidePlayer(Player p) {
hidePlayer(p, false);
}
/**
* @param p Player from which the hologram should be hidden
* @param force Whether to force hiding the hologram
*/
public void hidePlayer(Player p, boolean force) {
if (viewers.remove(p.getUniqueId()) || force) {
togglePlayer(p, false);
}
}
/**
* <p>Removes the hologram.</p>
*
* Hologram will be hidden from all players and all
* ArmorStand entities will be killed.
*/
public void remove() {
viewers.clear();
for (ArmorStandWrapper wrapper : wrappers) {
wrapper.remove();
}
wrappers.clear();
exists = false;
HOLOGRAMS.remove(this);
}
/**
* Remove the player from the list of viewers. The hologram is
* then counted as hidden, but no packets are sent to the player.
* @param p Player whose visibility status will be reset
*/
public void resetVisible(Player p) {
viewers.remove(p.getUniqueId());
}
private void togglePlayer(Player p, boolean visible) {
for (ArmorStandWrapper wrapper : wrappers) {
wrapper.setVisible(p, visible);
}
}
/**
* Get all hologram lines
*
* @return Hologram lines
*/
public String[] getLines() {
List<String> lines = new ArrayList<>();
for (ArmorStandWrapper wrapper : wrappers) {
lines.add(wrapper.getCustomName());
}
return lines.toArray(new String[lines.size()]);
}
/**
* Add a line
*
* @param line where to insert
* @param text text to display
*/
public void addLine(int line, String text) {
addLine(line, text, false);
}
private void addLine(int line, String text, boolean forceUpdateLine) {
if (text == null || text.isEmpty()) return;
if (line >= wrappers.size()) {
line = wrappers.size();
}
text = ChatColor.translateAlternateColorCodes('&', text);
if (Config.hologramFixedBottom) {
for (int i = 0; i < line; i++) {
ArmorStandWrapper wrapper = wrappers.get(i);
wrapper.setLocation(wrapper.getLocation().add(0, 0.25, 0));
}
} else {
for (int i = line; i < wrappers.size(); i++) {
ArmorStandWrapper wrapper = wrappers.get(i);
wrapper.setLocation(wrapper.getLocation().subtract(0, 0.25, 0));
}
}
Location loc = getLocation();
if (!Config.hologramFixedBottom) {
loc.subtract(0, line * 0.25, 0);
}
ArmorStandWrapper wrapper = new ArmorStandWrapper(plugin, loc, text, false);
wrappers.add(line, wrapper);
if (forceUpdateLine) {
for (Player player : location.getWorld().getPlayers()) {
if (viewers.contains(player.getUniqueId())) {
wrapper.setVisible(player, true);
}
}
}
}
/**
* Set a line
*
* @param line index to change
* @param text text to display
*/
public void setLine(int line, String text) {
if (text == null ||text.isEmpty()) {
removeLine(line);
return;
}
text = ChatColor.translateAlternateColorCodes('&', text);
if (line >= wrappers.size()) {
addLine(line, text, true);
return;
}
wrappers.get(line).setCustomName(text);
}
/**
* Remove a line
*
* @param line index to remove
*/
public void removeLine(int line) {
if (line < wrappers.size()) {
if (Config.hologramFixedBottom) {
for (int i = 0; i < line; i++) {
ArmorStandWrapper wrapper = wrappers.get(i);
wrapper.setLocation(wrapper.getLocation().subtract(0, 0.25, 0));
}
} else {
for (int i = line + 1; i < wrappers.size(); i++) {
ArmorStandWrapper wrapper = wrappers.get(i);
wrapper.setLocation(wrapper.getLocation().add(0, 0.25, 0));
}
}
wrappers.get(line).remove();
wrappers.remove(line);
}
}
}

View File

@ -1,236 +0,0 @@
package de.epiceric.shopchest.nms;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.utils.Utils;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JsonBuilder {
public static class Part {
private String value;
public Part() {
this("", true);
}
public Part(Object value) {
this(value, value instanceof CharSequence);
}
public Part(Object value, boolean appendQuotes) {
if (appendQuotes) {
this.value = "\"" + value + "\"";
} else {
this.value = String.valueOf(value);
}
}
@Override
public String toString() {
return value;
}
public PartArray toArray() {
return new PartArray(this);
}
public PartMap toMap() {
PartMap map = new PartMap();
map.setValue("text", new Part());
map.setValue("extra", toArray());
return map;
}
}
public static class PartMap extends Part {
private Map<String, Part> values = new HashMap<>();
public PartMap() {
}
public PartMap(Map<String, Part> values) {
this.values.putAll(values);
}
public void setValue(String key, Part value) {
values.put(key, value);
}
public void removeValue(String key) {
values.remove(key);
}
@Override
public String toString() {
StringJoiner joiner = new StringJoiner(",", "{", "}");
values.forEach((key, value) -> joiner.add("\"" + key + "\":" + value.toString()));
return joiner.toString();
}
@Override
public PartMap toMap() {
return this;
}
}
public static class PartArray extends Part {
private List<Part> parts = new ArrayList<>();
public PartArray(Part... parts) {
this.parts.addAll(Arrays.asList(parts));
}
public void addPart(Part part) {
parts.add(part);
}
@Override
public String toString() {
StringJoiner joiner = new StringJoiner(",", "[", "]");
parts.forEach(part -> joiner.add(part.toString()));
return joiner.toString();
}
@Override
public PartArray toArray() {
return this;
}
}
private static final Pattern PART_PATTERN = Pattern.compile("(([§][a-fA-Fk-oK-OrR0-9])+)([^§]*)");
private Part rootPart;
private ShopChest plugin;
private Class<?> iChatBaseComponentClass = Utils.getNMSClass("IChatBaseComponent");
private Class<?> packetPlayOutChatClass = Utils.getNMSClass("PacketPlayOutChat");
private Class<?> chatSerializerClass;
public JsonBuilder(ShopChest plugin) {
this.plugin = plugin;
if (Utils.getServerVersion().equals("v1_8_R1")) {
chatSerializerClass = Utils.getNMSClass("ChatSerializer");
} else {
chatSerializerClass = Utils.getNMSClass("IChatBaseComponent$ChatSerializer");
}
Class<?>[] requiredClasses = new Class<?>[] {
iChatBaseComponentClass, packetPlayOutChatClass, chatSerializerClass
};
for (Class<?> c : requiredClasses) {
if (c == null) {
plugin.debug("Failed to instantiate JsonBuilder: Could not find all required classes");
return;
}
}
}
public static Part parse(String text) {
Matcher matcher = PART_PATTERN.matcher(text);
if (!matcher.find()) {
return new Part(text);
}
matcher.reset();
PartArray array = new PartArray();
int lastEndIndex = 0;
while (matcher.find()) {
int startIndex = matcher.start();
int endIndex = matcher.end();
if (lastEndIndex != startIndex) {
String betweenMatches = text.substring(lastEndIndex, startIndex);
array.addPart(new Part(betweenMatches));
}
String format = matcher.group(1);
String value = matcher.group(3);
PartMap part = new PartMap();
part.setValue("text", new Part(value));
String[] formats = format.split("§");
for (String f : formats) {
switch (f.toLowerCase()) {
case "":
break;
case "k":
part.setValue("obfuscated", new Part(true));
break;
case "l":
part.setValue("bold", new Part(true));
break;
case "m":
part.setValue("strikethrough", new Part(true));
break;
case "n":
part.setValue("underlined", new Part(true));
break;
case "o":
part.setValue("italic", new Part(true));
break;
case "r":
part.removeValue("obfuscated");
part.removeValue("bold");
part.removeValue("strikethrough");
part.removeValue("underlined");
part.removeValue("italic");
part.removeValue("color");
break;
default:
part.setValue("color", new Part(ChatColor.getByChar(f).name().toLowerCase()));
}
}
array.addPart(part);
lastEndIndex = endIndex;
}
return array;
}
@Override
public String toString() {
return rootPart.toString();
}
public Part getRootPart() {
return rootPart;
}
public void setRootPart(Part rootPart) {
this.rootPart = rootPart;
}
public void sendJson(Player p) {
try {
Object iChatBaseComponent = chatSerializerClass.getMethod("a", String.class).invoke(null, toString());
Object packetPlayOutChat = packetPlayOutChatClass.getConstructor(iChatBaseComponentClass).newInstance(iChatBaseComponent);
Utils.sendPacket(plugin, packetPlayOutChat, p);
plugin.debug("Sent JSON: " + toString());
} catch (InstantiationException | InvocationTargetException |
IllegalAccessException | NoSuchMethodException e) {
plugin.getLogger().severe("Failed to send JSON with reflection");
plugin.debug("Failed to send JSON with reflection: " + toString());
plugin.debug(e);
}
}
}

View File

@ -1,90 +0,0 @@
package de.epiceric.shopchest.nms;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.utils.Utils;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.InvocationTargetException;
public class SpawnEggMeta {
private static String getNBTEntityID(ShopChest plugin, ItemStack stack) {
try {
Class<?> craftItemStackClass = Utils.getCraftClass("inventory.CraftItemStack");
if (craftItemStackClass == null) {
plugin.debug("Failed to get NBTEntityID: Could not find CraftItemStack class");
return null;
}
Object nmsStack = craftItemStackClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, stack);
Object nbtTagCompound = nmsStack.getClass().getMethod("getTag").invoke(nmsStack);
if (nbtTagCompound == null) return null;
Object entityTagCompound = nbtTagCompound.getClass().getMethod("getCompound", String.class).invoke(nbtTagCompound, "EntityTag");
if (entityTagCompound == null) return null;
Object id = entityTagCompound.getClass().getMethod("getString", String.class).invoke(entityTagCompound, "id");
if (id instanceof String) return (String) id;
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
plugin.getLogger().severe("Failed to get NBTEntityID with reflection");
plugin.debug("Failed to get NBTEntityID with reflection");
plugin.debug(e);
}
return null;
}
/**
* @param plugin An instance of the {@link ShopChest} plugin
* @param stack {@link ItemStack} (Spawn Egg) of which the Entity should be gotten
* @return The {@link EntityType} the Spawn Egg will spawn or <b>null</b> if <i>nbtEntityID</i> is null
*/
public static EntityType getEntityTypeFromItemStack(ShopChest plugin, ItemStack stack) {
if (Utils.getMajorVersion() == 8) {
EntityType type = null;
for (EntityType entityType : EntityType.values()) {
if (entityType.getTypeId() == stack.getDurability()) {
type = entityType;
break;
}
}
return type;
}
String nbtEntityID = getNBTEntityID(plugin, stack);
if (nbtEntityID == null) return null;
if (Utils.getMajorVersion() >= 11) {
if (nbtEntityID.contains(":")) nbtEntityID = nbtEntityID.split(":")[1];
return EntityType.fromName(nbtEntityID);
}
switch (nbtEntityID) {
case "PigZombie":
return EntityType.PIG_ZOMBIE;
case "CaveSpider":
return EntityType.CAVE_SPIDER;
case "LavaSlime":
return EntityType.MAGMA_CUBE;
case "MushroomCow":
return EntityType.MUSHROOM_COW;
case "EntityHorse":
return EntityType.HORSE;
case "PolarBear":
return EntityType.POLAR_BEAR;
case "Ozelot":
return EntityType.OCELOT;
default:
return EntityType.valueOf(nbtEntityID.toUpperCase());
}
}
}

View File

@ -1,476 +0,0 @@
package de.epiceric.shopchest.shop;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.config.HologramFormat;
import de.epiceric.shopchest.config.Placeholder;
import de.epiceric.shopchest.exceptions.ChestNotFoundException;
import de.epiceric.shopchest.exceptions.NotEnoughSpaceException;
import de.epiceric.shopchest.language.LanguageUtils;
import de.epiceric.shopchest.nms.Hologram;
import de.epiceric.shopchest.utils.ItemUtils;
import de.epiceric.shopchest.utils.Utils;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Chest;
import org.bukkit.block.DoubleChest;
import org.bukkit.block.data.Directional;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
public class Shop {
public enum ShopType {
NORMAL,
ADMIN,
}
private static class PreCreateResult {
private final Inventory inventory;
private final Chest[] chests;
private final BlockFace face;
private PreCreateResult(Inventory inventory, Chest[] chests, BlockFace face) {
this.inventory = inventory;
this.chests = chests;
this.face = face;
}
}
private final ShopChest plugin;
private final OfflinePlayer vendor;
private final ShopProduct product;
private final Location location;
private final double buyPrice;
private final double sellPrice;
private final ShopType shopType;
private boolean created;
private int id;
private Hologram hologram;
private Location holoLocation;
private ShopItem item;
public Shop(int id, ShopChest plugin, OfflinePlayer vendor, ShopProduct product, Location location, double buyPrice, double sellPrice, ShopType shopType) {
this.id = id;
this.plugin = plugin;
this.vendor = vendor;
this.product = product;
this.location = location;
this.buyPrice = buyPrice;
this.sellPrice = sellPrice;
this.shopType = shopType;
}
public Shop(ShopChest plugin, OfflinePlayer vendor, ShopProduct product, Location location, double buyPrice, double sellPrice, ShopType shopType) {
this(-1, plugin, vendor, product, location, buyPrice, sellPrice, shopType);
}
/**
* Test if this shop is equals to another
*
* @param o Other object to test against
* @return true if we are sure they are the same, false otherwise
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Shop shop = (Shop) o;
// id = -1 means temp shop
return id != -1 && id == shop.id;
}
@Override
public int hashCode() {
return id != -1 ? id : super.hashCode();
}
/**
* Create the shop
*
* @param showConsoleMessages to log exceptions to console
* @return Whether is was created or not
*/
public boolean create(boolean showConsoleMessages) {
if (created) return false;
plugin.debug("Creating shop (#" + id + ")");
Block b = location.getBlock();
if (b.getType() != Material.CHEST && b.getType() != Material.TRAPPED_CHEST) {
ChestNotFoundException ex = new ChestNotFoundException(String.format("No Chest found in world '%s' at location: %d; %d; %d",
b.getWorld().getName(), b.getX(), b.getY(), b.getZ()));
plugin.getShopUtils().removeShop(this, Config.removeShopOnError);
if (showConsoleMessages) plugin.getLogger().severe(ex.getMessage());
plugin.debug("Failed to create shop (#" + id + ")");
plugin.debug(ex);
return false;
} else if ((!ItemUtils.isAir(b.getRelative(BlockFace.UP).getType()))) {
NotEnoughSpaceException ex = new NotEnoughSpaceException(String.format("No space above chest in world '%s' at location: %d; %d; %d",
b.getWorld().getName(), b.getX(), b.getY(), b.getZ()));
plugin.getShopUtils().removeShop(this, Config.removeShopOnError);
if (showConsoleMessages) plugin.getLogger().severe(ex.getMessage());
plugin.debug("Failed to create shop (#" + id + ")");
plugin.debug(ex);
return false;
}
PreCreateResult preResult = preCreateHologram();
if (preResult == null) {
return false;
}
plugin.getShopCreationThreadPool().execute(() -> {
if (hologram == null || !hologram.exists()) createHologram(preResult);
if (item == null) createItem();
// Update shops for players in the same world after creation has finished
plugin.getUpdater().queue(() -> {
for (Player player : location.getWorld().getPlayers()) {
plugin.getShopUtils().resetPlayerLocation(player);
}
});
plugin.getUpdater().updateShops(location.getWorld());
});
created = true;
return true;
}
/**
* Removes the hologram of the shop
*/
public void removeHologram() {
if (hologram != null && hologram.exists()) {
plugin.debug("Removing hologram (#" + id + ")");
hologram.remove();
}
}
/**
* Removes the floating item of the shop
*/
public void removeItem() {
if (item != null) {
plugin.debug("Removing shop item (#" + id + ")");
item.remove();
}
}
/**
* <p>Creates the floating item of the shop</p>
* <b>Call this after {@link #createHologram()}, because it depends on the hologram's location</b>
*/
private void createItem() {
plugin.debug("Creating item (#" + id + ")");
Location itemLocation;
itemLocation = new Location(location.getWorld(), holoLocation.getX(), location.getY() + 0.9, holoLocation.getZ());
item = new ShopItem(plugin, product.getItemStack(), itemLocation);
}
/**
* Runs everything that needs to be called synchronously in order
* to prepare creating the hologram.
*/
private PreCreateResult preCreateHologram() {
plugin.debug("Creating hologram (#" + id + ")");
InventoryHolder ih = getInventoryHolder();
if (ih == null) return null;
Chest[] chests = new Chest[2];
BlockFace face;
if (ih instanceof DoubleChest) {
DoubleChest dc = (DoubleChest) ih;
Chest r = (Chest) dc.getRightSide();
Chest l = (Chest) dc.getLeftSide();
chests[0] = r;
chests[1] = l;
} else {
chests[0] = (Chest) ih;
}
if (Utils.getMajorVersion() < 13) {
face = ((org.bukkit.material.Directional) chests[0].getData()).getFacing();
} else {
face = ((Directional) chests[0].getBlockData()).getFacing();
}
return new PreCreateResult(ih.getInventory(), chests, face);
}
/**
* Acuatlly creates the hologram (async)
*/
private void createHologram(PreCreateResult preResult) {
String[] holoText = getHologramText(preResult.inventory);
holoLocation = getHologramLocation(preResult.chests, preResult.face);
new BukkitRunnable(){
@Override
public void run() {
hologram = new Hologram(plugin, holoText, holoLocation);
}
}.runTask(plugin);
}
/**
* Keep hologram text up to date.
* <p><b>Has to be called synchronously!</b></p>
*/
public void updateHologramText() {
String[] lines = getHologramText(getInventoryHolder().getInventory());
String[] currentLines = hologram.getLines();
int max = Math.max(lines.length, currentLines.length);
for (int i = 0; i < max; i++) {
if (i < lines.length) {
hologram.setLine(i, lines[i]);
} else {
hologram.removeLine(i);
}
}
}
private String[] getHologramText(Inventory inventory) {
List<String> lines = new ArrayList<>();
ItemStack itemStack = getProduct().getItemStack();
Map<HologramFormat.Requirement, Object> requirements = new EnumMap<>(HologramFormat.Requirement.class);
requirements.put(HologramFormat.Requirement.VENDOR, getVendor().getName());
requirements.put(HologramFormat.Requirement.AMOUNT, getProduct().getAmount());
requirements.put(HologramFormat.Requirement.ITEM_TYPE, itemStack.getType() + (itemStack.getDurability() > 0 ? ":" + itemStack.getDurability() : ""));
requirements.put(HologramFormat.Requirement.ITEM_NAME, itemStack.hasItemMeta() ? itemStack.getItemMeta().getDisplayName() : null);
requirements.put(HologramFormat.Requirement.HAS_ENCHANTMENT, !LanguageUtils.getEnchantmentString(ItemUtils.getEnchantments(itemStack)).isEmpty());
requirements.put(HologramFormat.Requirement.BUY_PRICE, getBuyPrice());
requirements.put(HologramFormat.Requirement.SELL_PRICE, getSellPrice());
requirements.put(HologramFormat.Requirement.HAS_POTION_EFFECT, ItemUtils.getPotionEffect(itemStack) != null);
requirements.put(HologramFormat.Requirement.IS_MUSIC_DISC, itemStack.getType().isRecord());
requirements.put(HologramFormat.Requirement.IS_POTION_EXTENDED, ItemUtils.isExtendedPotion(itemStack));
requirements.put(HologramFormat.Requirement.IS_WRITTEN_BOOK, itemStack.getType() == Material.WRITTEN_BOOK);
requirements.put(HologramFormat.Requirement.IS_BANNER_PATTERN, ItemUtils.isBannerPattern(itemStack));
requirements.put(HologramFormat.Requirement.ADMIN_SHOP, getShopType() == ShopType.ADMIN);
requirements.put(HologramFormat.Requirement.NORMAL_SHOP, getShopType() == ShopType.NORMAL);
requirements.put(HologramFormat.Requirement.IN_STOCK, Utils.getAmount(inventory, itemStack));
requirements.put(HologramFormat.Requirement.MAX_STACK, itemStack.getMaxStackSize());
requirements.put(HologramFormat.Requirement.CHEST_SPACE, Utils.getFreeSpaceForItem(inventory, itemStack));
requirements.put(HologramFormat.Requirement.DURABILITY, itemStack.getDurability());
Map<Placeholder, Object> placeholders = new EnumMap<>(Placeholder.class);
placeholders.put(Placeholder.VENDOR, getVendor().getName());
placeholders.put(Placeholder.AMOUNT, getProduct().getAmount());
placeholders.put(Placeholder.ITEM_NAME, getProduct().getLocalizedName());
placeholders.put(Placeholder.ENCHANTMENT, LanguageUtils.getEnchantmentString(ItemUtils.getEnchantments(itemStack)));
placeholders.put(Placeholder.BUY_PRICE, getBuyPrice());
placeholders.put(Placeholder.SELL_PRICE, getSellPrice());
placeholders.put(Placeholder.POTION_EFFECT, LanguageUtils.getPotionEffectName(itemStack));
placeholders.put(Placeholder.MUSIC_TITLE, LanguageUtils.getMusicDiscName(itemStack.getType()));
placeholders.put(Placeholder.BANNER_PATTERN_NAME, LanguageUtils.getBannerPatternName(itemStack.getType()));
placeholders.put(Placeholder.GENERATION, LanguageUtils.getBookGenerationName(itemStack));
placeholders.put(Placeholder.STOCK, Utils.getAmount(inventory, itemStack));
placeholders.put(Placeholder.MAX_STACK, itemStack.getMaxStackSize());
placeholders.put(Placeholder.CHEST_SPACE, Utils.getFreeSpaceForItem(inventory, itemStack));
placeholders.put(Placeholder.DURABILITY, itemStack.getDurability());
int lineCount = plugin.getHologramFormat().getLineCount();
for (int i = 0; i < lineCount; i++) {
String format = plugin.getHologramFormat().getFormat(i, requirements, placeholders);
for (Placeholder placeholder : placeholders.keySet()) {
String replace;
switch (placeholder) {
case BUY_PRICE:
replace = plugin.getEconomy().format(getBuyPrice());
break;
case SELL_PRICE:
replace = plugin.getEconomy().format(getSellPrice());
break;
default:
replace = String.valueOf(placeholders.get(placeholder));
}
format = format.replace(placeholder.toString(), replace);
}
if (!format.isEmpty()) {
lines.add(format);
}
}
return lines.toArray(new String[0]);
}
private Location getHologramLocation(Chest[] chests, BlockFace face) {
World w = location.getWorld();
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
Location holoLocation = new Location(w, x, y, z);
double deltaY = -0.6;
if (Config.hologramFixedBottom) deltaY = -0.85;
if (chests[1] != null) {
Chest c1 = Utils.getMajorVersion() >= 13 && (face == BlockFace.NORTH || face == BlockFace.EAST) ? chests[1] : chests[0];
Chest c2 = Utils.getMajorVersion() >= 13 && (face == BlockFace.NORTH || face == BlockFace.EAST) ? chests[0] : chests[1];
if (holoLocation.equals(c1.getLocation())) {
if (c1.getX() != c2.getX()) {
holoLocation.add(0, deltaY, 0.5);
} else if (c1.getZ() != c2.getZ()) {
holoLocation.add(0.5, deltaY, 0);
} else {
holoLocation.add(0.5, deltaY, 0.5);
}
} else {
if (c1.getX() != c2.getX()) {
holoLocation.add(1, deltaY, 0.5);
} else if (c1.getZ() != c2.getZ()) {
holoLocation.add(0.5, deltaY, 1);
} else {
holoLocation.add(0.5, deltaY, 0.5);
}
}
} else {
holoLocation.add(0.5, deltaY, 0.5);
}
holoLocation.add(0, Config.hologramLift, 0);
return holoLocation;
}
/**
* @return Whether an ID has been assigned to the shop
*/
public boolean hasId() {
return id != -1;
}
/**
* <p>Assign an ID to the shop.</p>
* Only works for the first time!
* @param id ID to set for this shop
*/
public void setId(int id) {
if (this.id == -1) {
this.id = id;
}
}
/**
* @return Whether the shop has already been created
*/
public boolean isCreated() {
return created;
}
/**
* @return The ID of the shop
*/
public int getID() {
return id;
}
/**
* @return Vendor of the shop; probably the creator of it
*/
public OfflinePlayer getVendor() {
return vendor;
}
/**
* @return Product the shop sells (or buys)
*/
public ShopProduct getProduct() {
return product;
}
/**
* @return Location of (one of) the shop's chest
*/
public Location getLocation() {
return location;
}
/**
* @return Buy price of the shop
*/
public double getBuyPrice() {
return buyPrice;
}
/**
* @return Sell price of the shop
*/
public double getSellPrice() {
return sellPrice;
}
/**
* @return Type of the shop
*/
public ShopType getShopType() {
return shopType;
}
/**
* @return Hologram of the shop
*/
public Hologram getHologram() {
return hologram;
}
/**
* @return Floating {@link ShopItem} of the shop
*/
public ShopItem getItem() {
return item;
}
public boolean hasHologram() {
return hologram != null;
}
public boolean hasItem() {
return item != null;
}
/**
* @return {@link InventoryHolder} of the shop or <b>null</b> if the shop has no chest.
*/
public InventoryHolder getInventoryHolder() {
Block b = getLocation().getBlock();
if (b.getType() == Material.CHEST || b.getType() == Material.TRAPPED_CHEST) {
Chest chest = (Chest) b.getState();
return chest.getInventory().getHolder();
}
return null;
}
}

View File

@ -1,161 +0,0 @@
package de.epiceric.shopchest.shop;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.utils.Utils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class ShopItem {
private final ShopChest plugin;
// concurrent since update task is in async thread
// since this is a fake entity, item is hidden per default
private final Set<UUID> viewers = Collections.newSetFromMap(new ConcurrentHashMap<UUID, Boolean>());
private final ItemStack itemStack;
private final Location location;
private final UUID uuid = UUID.randomUUID();
private final int entityId;
private final Class<?> packetPlayOutEntityDestroyClass = Utils.getNMSClass("PacketPlayOutEntityDestroy");
private final Class<?> packetPlayOutEntityVelocityClass = Utils.getNMSClass("PacketPlayOutEntityVelocity");
private final Class<?> packetPlayOutEntityMetadataClass = Utils.getNMSClass("PacketPlayOutEntityMetadata");
private final Class<?> dataWatcherClass = Utils.getNMSClass("DataWatcher");
private final Class<?> vec3dClass = Utils.getNMSClass("Vec3D");
private final Class<?> craftItemStackClass = Utils.getCraftClass("inventory.CraftItemStack");
private final Class<?> nmsItemStackClass = Utils.getNMSClass("ItemStack");
public ShopItem(ShopChest plugin, ItemStack itemStack, Location location) {
this.plugin = plugin;
this.itemStack = itemStack;
this.location = location;
this.entityId = Utils.getFreeEntityId();
Class<?> entityClass = Utils.getNMSClass("Entity");
Class<?>[] requiredClasses = new Class<?>[] {
nmsItemStackClass, craftItemStackClass, packetPlayOutEntityMetadataClass, dataWatcherClass,
packetPlayOutEntityDestroyClass, entityClass, packetPlayOutEntityVelocityClass,
};
for (Class<?> c : requiredClasses) {
if (c == null) {
plugin.debug("Failed to create shop item: Could not find all required classes");
return;
}
}
}
/**
* @return Clone of the location, where the shop item should be (it could have been moved by something, even though it shouldn't)
*/
public Location getLocation() {
return location.clone();
}
/**
* @return A clone of this Item's {@link ItemStack}
*/
public ItemStack getItemStack() {
return itemStack.clone();
}
/**
* @param p Player to check
* @return Whether the item is visible to the player
*/
public boolean isVisible(Player p) {
return viewers.contains(p.getUniqueId());
}
/**
* @param p Player to which the item should be shown
*/
public void showPlayer(Player p) {
showPlayer(p, false);
}
/**
* @param p Player to which the item should be shown
* @param force whether to force or not
*/
public void showPlayer(Player p, boolean force) {
if (viewers.add(p.getUniqueId()) || force) {
try {
Object nmsItemStack = craftItemStackClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, itemStack);
Object dataWatcher = Utils.createDataWatcher(null, nmsItemStack);
Utils.sendPacket(plugin, Utils.createPacketSpawnEntity(plugin, entityId, uuid, location, EntityType.DROPPED_ITEM), p);
Utils.sendPacket(plugin, packetPlayOutEntityMetadataClass.getConstructor(int.class, dataWatcherClass, boolean.class).newInstance(entityId, dataWatcher, true), p);
if (Utils.getMajorVersion() < 14) {
Utils.sendPacket(plugin, packetPlayOutEntityVelocityClass.getConstructor(int.class, double.class, double.class, double.class).newInstance(entityId, 0D, 0D, 0D), p);
} else {
Object vec3d = vec3dClass.getConstructor(double.class, double.class, double.class).newInstance(0D, 0D, 0D);
Utils.sendPacket(plugin, packetPlayOutEntityVelocityClass.getConstructor(int.class, vec3dClass).newInstance(entityId, vec3d), p);
}
} catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException | InstantiationException e) {
plugin.getLogger().severe("Failed to create item!");
plugin.debug("Failed to create item!");
plugin.debug(e);
}
}
}
/**
* @param p Player from which the item should be hidden
*/
public void hidePlayer(Player p) {
hidePlayer(p, false);
}
/**
* @param p Player from which the item should be hidden
* @param force whether to force or not
*/
public void hidePlayer(Player p, boolean force) {
if (viewers.remove(p.getUniqueId()) || force) {
try {
if (p.isOnline()) {
Object packetPlayOutEntityDestroy = packetPlayOutEntityDestroyClass.getConstructor(int[].class).newInstance((Object) new int[]{entityId});
Utils.sendPacket(plugin, packetPlayOutEntityDestroy, p);
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
plugin.getLogger().severe("Failed to destroy shop item");
plugin.debug("Failed to destroy shop item with reflection");
plugin.debug(e);
}
}
}
public void resetVisible(Player p) {
viewers.remove(p.getUniqueId());
}
/**
* Removes the item. <br>
* Item will be hidden from all players
*/
public void remove() {
// Avoid ConcurrentModificationException
for (UUID uuid : new ArrayList<>(viewers)) {
Player p = Bukkit.getPlayer(uuid);
if (p != null) hidePlayer(p);
}
}
/**
* Respawns the item at the set location for a player
* @param p Player, for which the item should be reset
*/
public void resetForPlayer(Player p) {
hidePlayer(p);
showPlayer(p);
}
}

View File

@ -1,43 +0,0 @@
package de.epiceric.shopchest.shop;
import org.bukkit.inventory.ItemStack;
import de.epiceric.shopchest.language.LanguageUtils;
public class ShopProduct {
private final ItemStack itemStack;
private final int amount;
public ShopProduct(ItemStack itemStack, int amount) {
this.itemStack = new ItemStack(itemStack);
this.itemStack.setAmount(1);
this.amount = amount;
}
public ShopProduct(ItemStack itemStack) {
this(itemStack, itemStack.getAmount());
}
/**
* @return The localized name of the product's {@link ItemStack} in the selected language file.
*/
public String getLocalizedName() {
return LanguageUtils.getItemName(getItemStack());
}
/**
* @return The {@link ItemStack} with an amount of {@code 1}.
*/
public ItemStack getItemStack() {
return itemStack;
}
/**
* @return The amount
*/
public int getAmount() {
return amount;
}
}

View File

@ -1,736 +0,0 @@
package de.epiceric.shopchest.sql;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.event.ShopBuySellEvent;
import de.epiceric.shopchest.event.ShopBuySellEvent.Type;
import de.epiceric.shopchest.exceptions.WorldNotFoundException;
import de.epiceric.shopchest.shop.Shop;
import de.epiceric.shopchest.shop.ShopProduct;
import de.epiceric.shopchest.shop.Shop.ShopType;
import de.epiceric.shopchest.utils.Callback;
import de.epiceric.shopchest.utils.Utils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import com.zaxxer.hikari.HikariDataSource;
public abstract class Database {
private final Set<String> notFoundWorlds = new HashSet<>();
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String tableShops;
String tableLogs;
String tableLogouts;
String tableFields;
ShopChest plugin;
HikariDataSource dataSource;
protected Database(ShopChest plugin) {
this.plugin = plugin;
}
abstract HikariDataSource getDataSource();
abstract String getQueryCreateTableShops();
abstract String getQueryCreateTableLog();
abstract String getQueryCreateTableLogout();
abstract String getQueryCreateTableFields();
abstract String getQueryGetTable();
private int getDatabaseVersion() throws SQLException {
try (Connection con = dataSource.getConnection()) {
try (Statement s = con.createStatement()) {
ResultSet rs = s.executeQuery("SELECT value FROM " + tableFields + " WHERE field='version'");
if (rs.next()) {
return rs.getInt("value");
}
}
}
return 0;
}
private void setDatabaseVersion(int version) throws SQLException {
String queryUpdateVersion = "REPLACE INTO " + tableFields + " VALUES ('version', ?)";
try (Connection con = dataSource.getConnection()) {
try (PreparedStatement ps = con.prepareStatement(queryUpdateVersion)) {
ps.setInt(1, version);
ps.executeUpdate();
}
}
}
private boolean update() throws SQLException {
String queryGetTable = getQueryGetTable();
try (Connection con = dataSource.getConnection()) {
boolean needsUpdate1 = false; // update "shop_log" to "economy_logs" and update "shops" with prefixes
boolean needsUpdate2 = false; // create field table and set database version
try (PreparedStatement ps = con.prepareStatement(queryGetTable)) {
ps.setString(1, "shop_log");
ResultSet rs = ps.executeQuery();
if (rs.next()) {
needsUpdate1 = true;
}
}
try (PreparedStatement ps = con.prepareStatement(queryGetTable)) {
ps.setString(1, tableFields);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
needsUpdate2 = true;
}
}
if (needsUpdate1) {
String queryRenameTableLogouts = "ALTER TABLE player_logout RENAME TO " + tableLogouts;
String queryRenameTableLogs = "ALTER TABLE shop_log RENAME TO backup_shop_log"; // for backup
String queryRenameTableShops = "ALTER TABLE shops RENAME TO backup_shops"; // for backup
plugin.getLogger().info("Updating database... (#1)");
// Rename logout table
try (Statement s = con.createStatement()) {
s.executeUpdate(queryRenameTableLogouts);
}
// Backup shops table
try (Statement s = con.createStatement()) {
s.executeUpdate(queryRenameTableShops);
}
// Backup log table
try (Statement s = con.createStatement()) {
s.executeUpdate(queryRenameTableLogs);
}
// Create new shops table
try (Statement s = con.createStatement()) {
s.executeUpdate(getQueryCreateTableShops());
}
// Create new log table
try (Statement s = con.createStatement()) {
s.executeUpdate(getQueryCreateTableLog());
}
// Convert shop table
try (Statement s = con.createStatement()) {
ResultSet rs = s.executeQuery("SELECT id,product FROM backup_shops");
while (rs.next()) {
ItemStack is = Utils.decode(rs.getString("product"));
int amount = is.getAmount();
is.setAmount(1);
String product = Utils.encode(is);
String insertQuery = "INSERT INTO " + tableShops + " SELECT id,vendor,?,?,world,x,y,z,buyprice,sellprice,shoptype FROM backup_shops WHERE id = ?";
try (PreparedStatement ps = con.prepareStatement(insertQuery)) {
ps.setString(1, product);
ps.setInt(2, amount);
ps.setInt(3, rs.getInt("id"));
ps.executeUpdate();
}
}
}
// Convert log table
try (Statement s = con.createStatement()) {
ResultSet rs = s.executeQuery("SELECT id,timestamp,executor,product,vendor FROM backup_shop_log");
while (rs.next()) {
String timestamp = rs.getString("timestamp");
long time = 0L;
try {
time = dateFormat.parse(timestamp).getTime();
} catch (ParseException e) {
plugin.debug("Failed to parse timestamp '" + timestamp + "': Time is set to 0");
plugin.debug(e);
}
String player = rs.getString("executor");
String playerUuid = player.substring(0, 36);
String playerName = player.substring(38, player.length() - 1);
String oldProduct = rs.getString("product");
String product = oldProduct.split(" x ")[1];
int amount = Integer.valueOf(oldProduct.split(" x ")[0]);
String vendor = rs.getString("vendor");
String vendorUuid = vendor.substring(0, 36);
String vendorName = vendor.substring(38).replaceAll("\\)( \\(ADMIN\\))?", "");
boolean admin = vendor.endsWith("(ADMIN)");
String insertQuery = "INSERT INTO " + tableLogs + " SELECT id,-1,timestamp,?,?,?,?,'Unknown',?,?,?,?,world,x,y,z,price,type FROM backup_shop_log WHERE id = ?";
try (PreparedStatement ps = con.prepareStatement(insertQuery)) {
ps.setLong(1, time);
ps.setString(2, playerName);
ps.setString(3, playerUuid);
ps.setString(4, product);
ps.setInt(5, amount);
ps.setString(6, vendorName);
ps.setString(7, vendorUuid);
ps.setBoolean(8, admin);
ps.setInt(9, rs.getInt("id"));
ps.executeUpdate();
}
}
}
}
if (needsUpdate2) {
plugin.getLogger().info("Updating database... (#2)");
// Create fields table
try (Statement s = con.createStatement()) {
s.executeUpdate(getQueryCreateTableFields());
}
setDatabaseVersion(2);
}
int databaseVersion = getDatabaseVersion();
if (databaseVersion < 3) {
// plugin.getLogger().info("Updating database... (#3)");
// Update database structure...
// setDatabaseVersion(3);
}
int newDatabaseVersion = getDatabaseVersion();
return needsUpdate1 || needsUpdate2 || newDatabaseVersion > databaseVersion;
}
}
/**
* <p>(Re-)Connects to the the database and initializes it.</p>
*
* All tables are created if necessary and if the database
* structure has to be updated, that is done as well.
*
* @param callback Callback that - if succeeded - returns the amount of shops
* that were found (as {@code int})
*/
public void connect(final Callback<Integer> callback) {
if (!Config.databaseTablePrefix.matches("^([a-zA-Z0-9\\-\\_]+)?$")) {
// Only letters, numbers dashes and underscores are allowed
plugin.getLogger().severe("Database table prefix contains illegal letters, using 'shopchest_' prefix.");
Config.databaseTablePrefix = "shopchest_";
}
this.tableShops = Config.databaseTablePrefix + "shops";
this.tableLogs = Config.databaseTablePrefix + "economy_logs";
this.tableLogouts = Config.databaseTablePrefix + "player_logouts";
this.tableFields = Config.databaseTablePrefix + "fields";
new BukkitRunnable() {
@Override
public void run() {
disconnect();
try {
dataSource = getDataSource();
} catch (Exception e) {
callback.onError(e);
plugin.debug(e);
return;
}
if (dataSource == null) {
Exception e = new IllegalStateException("Data source is null");
callback.onError(e);
plugin.debug(e);
return;
}
try (Connection con = dataSource.getConnection()) {
// Update database structure if necessary
if (update()) {
plugin.getLogger().info("Updating database finished");
}
// Create shop table
try (Statement s = con.createStatement()) {
s.executeUpdate(getQueryCreateTableShops());
}
// Create log table
try (Statement s = con.createStatement()) {
s.executeUpdate(getQueryCreateTableLog());
}
// Create logout table
try (Statement s = con.createStatement()) {
s.executeUpdate(getQueryCreateTableLogout());
}
// Create fields table
try (Statement s = con.createStatement()) {
s.executeUpdate(getQueryCreateTableFields());
}
// Clean up economy log
if (Config.cleanupEconomyLogDays > 0) {
cleanUpEconomy(false);
}
// Count shops entries in database
try (Statement s = con.createStatement()) {
ResultSet rs = s.executeQuery("SELECT COUNT(id) FROM " + tableShops);
if (rs.next()) {
int count = rs.getInt(1);
plugin.debug("Initialized database with " + count + " entries");
if (callback != null) {
callback.callSyncResult(count);
}
} else {
throw new SQLException("Count result set has no entries");
}
}
} catch (SQLException e) {
if (callback != null) {
callback.callSyncError(e);
}
plugin.getLogger().severe("Failed to initialize or connect to database");
plugin.debug("Failed to initialize or connect to database");
plugin.debug(e);
}
}
}.runTaskAsynchronously(plugin);
}
/**
* Remove a shop from the database
*
* @param shop Shop to remove
* @param callback Callback that - if succeeded - returns {@code null}
*/
public void removeShop(final Shop shop, final Callback<Void> callback) {
new BukkitRunnable() {
@Override
public void run() {
try (Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM " + tableShops + " WHERE id = ?")) {
ps.setInt(1, shop.getID());
ps.executeUpdate();
plugin.debug("Removing shop from database (#" + shop.getID() + ")");
if (callback != null) {
callback.callSyncResult(null);
}
} catch (SQLException ex) {
if (callback != null) {
callback.callSyncError(ex);
}
plugin.getLogger().severe("Failed to remove shop from database");
plugin.debug("Failed to remove shop from database (#" + shop.getID() + ")");
plugin.debug(ex);
}
}
}.runTaskAsynchronously(plugin);
}
/**
* Get all shops from the database
*
* @param showConsoleMessages Whether console messages (errors or warnings)
* should be shown
* @param callback Callback that - if succeeded - returns a read-only
* collection of all shops (as
* {@code Collection<Shop>})
*/
public void getShops(final boolean showConsoleMessages, final Callback<Collection<Shop>> callback) {
new BukkitRunnable() {
@Override
public void run() {
ArrayList<Shop> shops = new ArrayList<>();
try (Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM " + tableShops + "")) {
ResultSet rs = ps.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
plugin.debug("Getting Shop... (#" + id + ")");
String worldName = rs.getString("world");
World world = Bukkit.getWorld(worldName);
if (world == null) {
WorldNotFoundException ex = new WorldNotFoundException(worldName);
if (showConsoleMessages && !notFoundWorlds.contains(worldName)) {
plugin.getLogger().warning(ex.getMessage());
notFoundWorlds.add(worldName);
}
plugin.debug("Failed to get shop (#" + id + ")");
plugin.debug(ex);
continue;
}
int x = rs.getInt("x");
int y = rs.getInt("y");
int z = rs.getInt("z");
Location location = new Location(world, x, y, z);
OfflinePlayer vendor = Bukkit.getOfflinePlayer(UUID.fromString(rs.getString("vendor")));
ItemStack itemStack = Utils.decode(rs.getString("product"));
int amount = rs.getInt("amount");
ShopProduct product = new ShopProduct(itemStack, amount);
double buyPrice = rs.getDouble("buyprice");
double sellPrice = rs.getDouble("sellprice");
ShopType shopType = ShopType.valueOf(rs.getString("shoptype"));
plugin.debug("Initializing new shop... (#" + id + ")");
shops.add(new Shop(id, plugin, vendor, product, location, buyPrice, sellPrice, shopType));
}
if (callback != null) {
callback.callSyncResult(Collections.unmodifiableCollection(shops));
}
} catch (SQLException ex) {
if (callback != null) {
callback.callSyncError(ex);
}
plugin.getLogger().severe("Failed to get shops from database");
plugin.debug("Failed to get shops");
plugin.debug(ex);
}
}
}.runTaskAsynchronously(plugin);
}
/**
* Adds a shop to the database
*
* @param shop Shop to add
* @param callback Callback that - if succeeded - returns the ID the shop was
* given (as {@code int})
*/
public void addShop(final Shop shop, final Callback<Integer> callback) {
final String queryNoId = "REPLACE INTO " + tableShops + " (vendor,product,amount,world,x,y,z,buyprice,sellprice,shoptype) VALUES(?,?,?,?,?,?,?,?,?,?)";
final String queryWithId = "REPLACE INTO " + tableShops + " (id,vendor,product,amount,world,x,y,z,buyprice,sellprice,shoptype) VALUES(?,?,?,?,?,?,?,?,?,?,?)";
new BukkitRunnable() {
@Override
public void run() {
String query = shop.hasId() ? queryWithId : queryNoId;
try (Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement(query, Statement.RETURN_GENERATED_KEYS)) {
int i = 0;
if (shop.hasId()) {
i = 1;
ps.setInt(1, shop.getID());
}
ps.setString(i+1, shop.getVendor().getUniqueId().toString());
ps.setString(i+2, Utils.encode(shop.getProduct().getItemStack()));
ps.setInt(i+3, shop.getProduct().getAmount());
ps.setString(i+4, shop.getLocation().getWorld().getName());
ps.setInt(i+5, shop.getLocation().getBlockX());
ps.setInt(i+6, shop.getLocation().getBlockY());
ps.setInt(i+7, shop.getLocation().getBlockZ());
ps.setDouble(i+8, shop.getBuyPrice());
ps.setDouble(i+9, shop.getSellPrice());
ps.setString(i+10, shop.getShopType().toString());
ps.executeUpdate();
if (!shop.hasId()) {
int shopId = -1;
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()) {
shopId = rs.getInt(1);
}
shop.setId(shopId);
}
if (callback != null) {
callback.callSyncResult(shop.getID());
}
plugin.debug("Adding shop to database (#" + shop.getID() + ")");
} catch (SQLException ex) {
if (callback != null) {
callback.callSyncError(ex);
}
plugin.getLogger().severe("Failed to add shop to database");
plugin.debug("Failed to add shop to database (#" + shop.getID() + ")");
plugin.debug(ex);
}
}
}.runTaskAsynchronously(plugin);
}
/**
* Log an economy transaction to the database
*
* @param executor Player who bought/sold something
* @param shop The {@link Shop} the player bought from or sold to
* @param product The {@link ItemStack} that was bought/sold
* @param price The price the product was bought or sold for
* @param type Whether the executor bought or sold
* @param callback Callback that - if succeeded - returns {@code null}
*/
public void logEconomy(final Player executor, Shop shop, ShopProduct product, double price, Type type, final Callback<Void> callback) {
final String query = "INSERT INTO " + tableLogs + " (shop_id,timestamp,time,player_name,player_uuid,product_name,product,amount,"
+ "vendor_name,vendor_uuid,admin,world,x,y,z,price,type) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
if (Config.enableEconomyLog) {
new BukkitRunnable() {
@Override
public void run() {
try (Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement(query)) {
long millis = System.currentTimeMillis();
ps.setInt(1, shop.getID());
ps.setString(2, dateFormat.format(millis));
ps.setLong(3, millis);
ps.setString(4, executor.getName());
ps.setString(5, executor.getUniqueId().toString());
ps.setString(6, product.getLocalizedName());
ps.setString(7, Utils.encode(product.getItemStack()));
ps.setInt(8, product.getAmount());
ps.setString(9, shop.getVendor().getName());
ps.setString(10, shop.getVendor().getUniqueId().toString());
ps.setBoolean(11, shop.getShopType() == ShopType.ADMIN);
ps.setString(12, shop.getLocation().getWorld().getName());
ps.setInt(13, shop.getLocation().getBlockX());
ps.setInt(14, shop.getLocation().getBlockY());
ps.setInt(15, shop.getLocation().getBlockZ());
ps.setDouble(16, price);
ps.setString(17, type.toString());
ps.executeUpdate();
if (callback != null) {
callback.callSyncResult(null);
}
plugin.debug("Logged economy transaction to database");
} catch (SQLException ex) {
if (callback != null) {
callback.callSyncError(ex);
}
plugin.getLogger().severe("Failed to log economy transaction to database");
plugin.debug("Failed to log economy transaction to database");
plugin.debug(ex);
}
}
}.runTaskAsynchronously(plugin);
} else {
if (callback != null) {
callback.callSyncResult(null);
}
}
}
/**
* Cleans up the economy log to reduce file size
*
* @param async Whether the call should be executed asynchronously
*/
public void cleanUpEconomy(boolean async) {
BukkitRunnable runnable = new BukkitRunnable() {
@Override
public void run() {
long time = System.currentTimeMillis() - Config.cleanupEconomyLogDays * 86400000L;
String queryCleanUpLog = "DELETE FROM " + tableLogs + " WHERE time < " + time;
String queryCleanUpPlayers = "DELETE FROM " + tableLogouts + " WHERE time < " + time;
try (Connection con = dataSource.getConnection();
Statement s = con.createStatement();
Statement s2 = con.createStatement()) {
s.executeUpdate(queryCleanUpLog);
s2.executeUpdate(queryCleanUpPlayers);
plugin.getLogger().info("Cleaned up economy log");
plugin.debug("Cleaned up economy log");
} catch (SQLException ex) {
plugin.getLogger().severe("Failed to clean up economy log");
plugin.debug("Failed to clean up economy log");
plugin.debug(ex);
}
}
};
if (async) {
runnable.runTaskAsynchronously(plugin);
} else {
runnable.run();
}
}
/**
* Get the revenue a player got while he was offline
*
* @param player Player whose revenue to get
* @param logoutTime Time in milliseconds when he logged out the last time
* @param callback Callback that - if succeeded - returns the revenue the
* player made while offline (as {@code double})
*/
public void getRevenue(final Player player, final long logoutTime, final Callback<Double> callback) {
new BukkitRunnable() {
@Override
public void run() {
double revenue = 0;
try (Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM " + tableLogs + " WHERE vendor_uuid = ?")) {
ps.setString(1, player.getUniqueId().toString());
ResultSet rs = ps.executeQuery();
while (rs.next()) {
long timestamp = rs.getLong("time");
double singleRevenue = rs.getDouble("price");
ShopBuySellEvent.Type type = ShopBuySellEvent.Type.valueOf(rs.getString("type"));
if (type == ShopBuySellEvent.Type.SELL) {
singleRevenue = -singleRevenue;
}
if (timestamp > logoutTime) {
revenue += singleRevenue;
}
}
if (callback != null) {
callback.callSyncResult(revenue);
}
} catch (SQLException ex) {
if (callback != null) {
callback.callSyncError(ex);
}
plugin.getLogger().severe("Failed to get revenue from database");
plugin.debug("Failed to get revenue from player \"" + player.getUniqueId().toString() + "\"");
plugin.debug(ex);
}
}
}.runTaskAsynchronously(plugin);
}
/**
* Log a logout to the database
*
* @param player Player who logged out
* @param callback Callback that - if succeeded - returns {@code null}
*/
public void logLogout(final Player player, final Callback<Void> callback) {
new BukkitRunnable() {
@Override
public void run() {
try (Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement("REPLACE INTO " + tableLogouts + " (player,time) VALUES(?,?)")) {
ps.setString(1, player.getUniqueId().toString());
ps.setLong(2, System.currentTimeMillis());
ps.executeUpdate();
if (callback != null) {
callback.callSyncResult(null);
}
plugin.debug("Logged logout to database");
} catch (final SQLException ex) {
if (callback != null) {
callback.callSyncError(ex);
}
plugin.getLogger().severe("Failed to log last logout to database");
plugin.debug("Failed to log logout to database");
plugin.debug(ex);
}
}
}.runTaskAsynchronously(plugin);
}
/**
* Get the last logout of a player
*
* @param player Player who logged out
* @param callback Callback that - if succeeded - returns the time in
* milliseconds the player logged out (as {@code long})
* or {@code -1} if the player has not logged out yet.
*/
public void getLastLogout(final Player player, final Callback<Long> callback) {
new BukkitRunnable() {
@Override
public void run() {
try (Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM " + tableLogouts + " WHERE player = ?")) {
ps.setString(1, player.getUniqueId().toString());
ResultSet rs = ps.executeQuery();
if (rs.next()) {
if (callback != null) {
callback.callSyncResult(rs.getLong("time"));
}
}
if (callback != null) {
callback.callSyncResult(-1L);
}
} catch (SQLException ex) {
if (callback != null) {
callback.callSyncError(ex);
}
plugin.getLogger().severe("Failed to get last logout from database");
plugin.debug("Failed to get last logout from player \"" + player.getName() + "\"");
plugin.debug(ex);
}
}
}.runTaskAsynchronously(plugin);
}
/**
* Closes the data source
*/
public void disconnect() {
if (dataSource != null) {
dataSource.close();
dataSource = null;
}
}
public enum DatabaseType {
SQLite, MySQL
}
}

View File

@ -1,109 +0,0 @@
package de.epiceric.shopchest.sql;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import org.bukkit.scheduler.BukkitRunnable;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
public class MySQL extends Database {
public MySQL(ShopChest plugin) {
super(plugin);
}
@Override
HikariDataSource getDataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(String.format("jdbc:mysql://%s:%d/%s?autoReconnect=true&useSSL=false&serverTimezone=UTC",
Config.databaseMySqlHost, Config.databaseMySqlPort, Config.databaseMySqlDatabase));
config.setUsername(Config.databaseMySqlUsername);
config.setPassword(Config.databaseMySqlPassword);
config.setConnectionTestQuery("SELECT 1");
return new HikariDataSource(config);
}
/**
* Sends an asynchronous ping to the database
*/
public void ping() {
new BukkitRunnable() {
@Override
public void run() {
try (Connection con = dataSource.getConnection();
Statement s = con.createStatement()) {
plugin.debug("Pinging to MySQL server...");
s.execute("/* ping */ SELECT 1");
} catch (SQLException ex) {
plugin.getLogger().severe("Failed to ping to MySQL server. Trying to reconnect...");
plugin.debug("Failed to ping to MySQL server. Trying to reconnect...");
connect(null);
}
}
}.runTaskAsynchronously(plugin);
}
@Override
String getQueryCreateTableShops() {
return "CREATE TABLE IF NOT EXISTS " + tableShops + " ("
+ "id INTEGER PRIMARY KEY AUTO_INCREMENT,"
+ "vendor TINYTEXT NOT NULL,"
+ "product TEXT NOT NULL,"
+ "amount INTEGER NOT NULL,"
+ "world TINYTEXT NOT NULL,"
+ "x INTEGER NOT NULL,"
+ "y INTEGER NOT NULL,"
+ "z INTEGER NOT NULL,"
+ "buyprice FLOAT NOT NULL,"
+ "sellprice FLOAT NOT NULL,"
+ "shoptype TINYTEXT NOT NULL)";
}
@Override
String getQueryCreateTableLog() {
return "CREATE TABLE IF NOT EXISTS " + tableLogs + " ("
+ "id INTEGER PRIMARY KEY AUTO_INCREMENT,"
+ "shop_id INTEGER NOT NULL,"
+ "timestamp TINYTEXT NOT NULL,"
+ "time LONG NOT NULL,"
+ "player_name TINYTEXT NOT NULL,"
+ "player_uuid TINYTEXT NOT NULL,"
+ "product_name TINYTEXT NOT NULL,"
+ "product TEXT NOT NULL,"
+ "amount INTEGER NOT NULL,"
+ "vendor_name TINYTEXT NOT NULL,"
+ "vendor_uuid TINYTEXT NOT NULL,"
+ "admin BIT NOT NULL,"
+ "world TINYTEXT NOT NULL,"
+ "x INTEGER NOT NULL,"
+ "y INTEGER NOT NULL,"
+ "z INTEGER NOT NULL,"
+ "price FLOAT NOT NULL,"
+ "type TINYTEXT NOT NULL)";
}
@Override
String getQueryCreateTableLogout() {
return "CREATE TABLE IF NOT EXISTS " + tableLogouts + " ("
+ "player VARCHAR(36) PRIMARY KEY NOT NULL,"
+ "time LONG NOT NULL)";
}
@Override
String getQueryCreateTableFields() {
return "CREATE TABLE IF NOT EXISTS " + tableFields + " ("
+ "field VARCHAR(32) PRIMARY KEY NOT NULL,"
+ "value INTEGER NOT NULL)";
}
@Override
String getQueryGetTable() {
return "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=?";
}
}

View File

@ -1,140 +0,0 @@
package de.epiceric.shopchest.sql;
import de.epiceric.shopchest.ShopChest;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
public class SQLite extends Database {
public SQLite(ShopChest plugin) {
super(plugin);
}
@Override
HikariDataSource getDataSource() {
try {
// Initialize driver class so HikariCP can find it
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
plugin.getLogger().severe("Failed to initialize SQLite driver");
plugin.debug("Failed to initialize SQLite driver");
plugin.debug(e);
return null;
}
File folder = plugin.getDataFolder();
File dbFile = new File(folder, "shops.db");
if (!dbFile.exists()) {
try {
dbFile.createNewFile();
} catch (IOException ex) {
plugin.getLogger().severe("Failed to create database file");
plugin.debug("Failed to create database file");
plugin.debug(ex);
return null;
}
}
HikariConfig config = new HikariConfig();
config.setJdbcUrl(String.format("jdbc:sqlite:" + dbFile));
config.setConnectionTestQuery("SELECT 1");
return new HikariDataSource(config);
}
/**
* Vacuums the database to reduce file size
*
* @param async Whether the call should be executed asynchronously
*/
public void vacuum(boolean async) {
BukkitRunnable runnable = new BukkitRunnable() {
@Override
public void run() {
try (Connection con = dataSource.getConnection();
Statement s = con.createStatement()) {
s.executeUpdate("VACUUM");
plugin.debug("Vacuumed SQLite database");
} catch (final SQLException ex) {
plugin.getLogger().severe("Failed to vacuum database");
plugin.debug("Failed to vacuum database");
plugin.debug(ex);
}
}
};
if (async) {
runnable.runTaskAsynchronously(plugin);
} else {
runnable.run();
}
}
@Override
String getQueryCreateTableShops() {
return "CREATE TABLE IF NOT EXISTS " + tableShops + " ("
+ "id INTEGER PRIMARY KEY AUTOINCREMENT,"
+ "vendor TINYTEXT NOT NULL,"
+ "product TEXT NOT NULL,"
+ "amount INTEGER NOT NULL,"
+ "world TINYTEXT NOT NULL,"
+ "x INTEGER NOT NULL,"
+ "y INTEGER NOT NULL,"
+ "z INTEGER NOT NULL,"
+ "buyprice FLOAT NOT NULL,"
+ "sellprice FLOAT NOT NULL,"
+ "shoptype TINYTEXT NOT NULL)";
}
@Override
String getQueryCreateTableLog() {
return "CREATE TABLE IF NOT EXISTS " + tableLogs + " ("
+ "id INTEGER PRIMARY KEY AUTOINCREMENT,"
+ "shop_id INTEGER NOT NULL,"
+ "timestamp TINYTEXT NOT NULL,"
+ "time LONG NOT NULL,"
+ "player_name TINYTEXT NOT NULL,"
+ "player_uuid TINYTEXT NOT NULL,"
+ "product_name TINYTEXT NOT NULL,"
+ "product TEXT NOT NULL,"
+ "amount INTEGER NOT NULL,"
+ "vendor_name TINYTEXT NOT NULL,"
+ "vendor_uuid TINYTEXT NOT NULL,"
+ "admin BIT NOT NULL,"
+ "world TINYTEXT NOT NULL,"
+ "x INTEGER NOT NULL,"
+ "y INTEGER NOT NULL,"
+ "z INTEGER NOT NULL,"
+ "price FLOAT NOT NULL,"
+ "type TINYTEXT NOT NULL)";
}
@Override
String getQueryCreateTableLogout() {
return "CREATE TABLE IF NOT EXISTS " + tableLogouts + " ("
+ "player VARCHAR(36) PRIMARY KEY NOT NULL,"
+ "time LONG NOT NULL)";
}
@Override
String getQueryCreateTableFields() {
return "CREATE TABLE IF NOT EXISTS " + tableFields + " ("
+ "field VARCHAR(32) PRIMARY KEY NOT NULL,"
+ "value INTEGER NOT NULL)";
}
@Override
String getQueryGetTable() {
return "SELECT name FROM sqlite_master WHERE type='table' AND name=?";
}
}

View File

@ -1,34 +0,0 @@
package de.epiceric.shopchest.utils;
import de.epiceric.shopchest.ShopChest;
import org.bukkit.scheduler.BukkitRunnable;
public abstract class Callback<T> {
private ShopChest plugin;
public Callback(ShopChest plugin) {
this.plugin = plugin;
}
public void onResult(T result) {}
public void onError(Throwable throwable) {}
public final void callSyncResult(final T result) {
new BukkitRunnable() {
@Override
public void run() {
onResult(result);
}
}.runTask(plugin);
}
public final void callSyncError(final Throwable throwable) {
new BukkitRunnable() {
@Override
public void run() {
onError(throwable);
}
}.runTask(plugin);
}
}

View File

@ -1,222 +0,0 @@
package de.epiceric.shopchest.utils;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.shop.ShopProduct;
import de.epiceric.shopchest.shop.Shop.ShopType;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
public class ClickType {
private static Map<UUID, ClickType> playerClickType = new HashMap<>();
private static Map<UUID, BukkitTask> playerTimers = new HashMap<>();
private EnumClickType enumClickType;
public ClickType(EnumClickType enumClickType) {
this.enumClickType = enumClickType;
}
/**
* Clear click types, cancel timers, and reset game modes
*/
public static void clear() {
playerClickType.forEach((uuid, ct) -> {
if (ct instanceof SelectClickType) {
Player p = Bukkit.getPlayer(uuid);
if (p != null)
p.setGameMode(((SelectClickType) ct).getGameMode());
}
});
playerTimers.forEach((uuid, timer) -> timer.cancel());
}
/**
* Gets the click type of a player
*
* @param player Player whose click type should be gotten
* @return The Player's click type or <b>null</b> if he doesn't have one
*/
public static ClickType getPlayerClickType(OfflinePlayer player) {
return playerClickType.get(player.getUniqueId());
}
/**
* Removes the click type from a player and cancels the 15 second timer
*
* @param player Player to remove the click type from
*/
public static void removePlayerClickType(OfflinePlayer player) {
UUID uuid = player.getUniqueId();
if (playerClickType.get(uuid) instanceof SelectClickType && player instanceof Player) {
// Reset gamemode player has select click type
((Player) player).setGameMode(((SelectClickType) playerClickType.get(uuid)).gameMode);
}
playerClickType.remove(uuid);
// If a timer is still running, cancel it
Optional.ofNullable(playerTimers.get(uuid)).ifPresent(task -> task.cancel());
playerTimers.remove(uuid);
}
/**
* Sets the click type of a player and removes it after 15 seconds
*
* @param player Player whose click type should be set
* @param clickType Click type to set
*/
public static void setPlayerClickType(OfflinePlayer player, ClickType clickType) {
UUID uuid = player.getUniqueId();
if (playerClickType.get(uuid) instanceof SelectClickType && player instanceof Player) {
// Reset gamemode player has select click type
((Player) player).setGameMode(((SelectClickType) playerClickType.get(uuid)).gameMode);
}
playerClickType.put(uuid, clickType);
// If a timer is already running, cancel it
Optional.ofNullable(playerTimers.get(uuid)).ifPresent(task -> task.cancel());
if (clickType.getClickType() != EnumClickType.SELECT_ITEM) {
// Remove ClickType after 15 seconds if player has not clicked a chest
playerTimers.put(uuid, new BukkitRunnable() {
@Override
public void run() {
playerClickType.remove(uuid);
}
}.runTaskLater(ShopChest.getInstance(), 300));
}
}
/**
* @return Type of the click type
*/
public EnumClickType getClickType() {
return enumClickType;
}
public enum EnumClickType {
CREATE, REMOVE, INFO, OPEN, SELECT_ITEM
}
public static class CreateClickType extends ClickType {
private ShopProduct product;
private double buyPrice;
private double sellPrice;
private ShopType shopType;
public CreateClickType(ShopProduct product, double buyPrice, double sellPrice, ShopType shopType) {
super(EnumClickType.CREATE);
this.product = product;
this.sellPrice = sellPrice;
this.buyPrice = buyPrice;
this.shopType = shopType;
}
/**
* Returns the item, the player has hold in his hands
*/
public ShopProduct getProduct() {
return product;
}
/**
* Returns the buy price, the player has entered
*/
public double getBuyPrice() {
return buyPrice;
}
/**
* Returns the sell price, the player has entered
*/
public double getSellPrice() {
return sellPrice;
}
/**
* Returns the shop type, the player has entered
*/
public ShopType getShopType() {
return shopType;
}
}
public static class SelectClickType extends ClickType {
private ItemStack itemStack;
private GameMode gameMode;
private int amount;
private double buyPrice;
private double sellPrice;
private ShopType shopType;
public SelectClickType(GameMode gameMode, int amount, double buyPrice, double sellPrice, ShopType shopType) {
super(EnumClickType.SELECT_ITEM);
this.gameMode = gameMode;
this.amount = amount;
this.sellPrice = sellPrice;
this.buyPrice = buyPrice;
this.shopType = shopType;
}
/**
* Returns the selected item (or {@code null} if no item has been selected)
*/
public ItemStack getItem() {
return itemStack;
}
/**
* Sets the selected item
* @param itemStack The item to set as selected
*/
public void setItem(ItemStack itemStack) {
this.itemStack = itemStack;
}
/**
* Returns the gamemode, the player was in before entering creative mode
*/
public GameMode getGameMode() {
return gameMode;
}
/**
* Returns the amount, the player has entered
*/
public int getAmount() {
return amount;
}
/**
* Returns the buy price, the player has entered
*/
public double getBuyPrice() {
return buyPrice;
}
/**
* Returns the sell price, the player has entered
*/
public double getSellPrice() {
return sellPrice;
}
/**
* Returns the shop type, the player has entered
*/
public ShopType getShopType() {
return shopType;
}
}
}

View File

@ -1,42 +0,0 @@
package de.epiceric.shopchest.utils;
public class FastMath {
/**
* Fast sqrt, 1.57% precision
*
* @param n value to calculate square root from
* @return the square root of n
*/
public static double sqrt(double n) {
return n * Double.longBitsToDouble(6910470738111508698L - (Double.doubleToRawLongBits(n) >> 1));
}
/**
* Fast acos, 2.9% precision
*
* @param n value to calculate arc cosine from
* @return the arc cosine of n
*/
public static double acos(double n) {
int v = (int) (n * MULTIPLIER + OFFSET);
while (v > PRECISION) v -= PRECISION;
while (v < 0) v += PRECISION;
return acos[v];
}
// Below is lookup table generation
// It is only executed once at initialization
private static final int PRECISION = 512;
private static final double MULTIPLIER = PRECISION / 2D;
private static final double OFFSET = MULTIPLIER + 0.5D; // + 0.5 as cast truncate and don't round
private static final double[] acos = new double[PRECISION + 1];
static {
for (int i = 0; i <= PRECISION; i++) {
acos[i] = Math.acos(i * (2D / PRECISION) - 1);
}
}
}

View File

@ -1,76 +0,0 @@
package de.epiceric.shopchest.utils;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.Potion;
import org.bukkit.potion.PotionType;
import java.util.Arrays;
import java.util.Map;
public class ItemUtils {
public static Map<Enchantment, Integer> getEnchantments(ItemStack itemStack) {
if (itemStack.getItemMeta() instanceof EnchantmentStorageMeta) {
EnchantmentStorageMeta esm = (EnchantmentStorageMeta) itemStack.getItemMeta();
return esm.getStoredEnchants();
} else {
return itemStack.getEnchantments();
}
}
public static PotionType getPotionEffect(ItemStack itemStack) {
if (itemStack.getItemMeta() instanceof PotionMeta) {
if (Utils.getMajorVersion() < 9) {
return Potion.fromItemStack(itemStack).getType();
} else {
return ((PotionMeta) itemStack.getItemMeta()).getBasePotionData().getType();
}
}
return null;
}
public static boolean isExtendedPotion(ItemStack itemStack) {
if (itemStack.getItemMeta() instanceof PotionMeta) {
if (Utils.getMajorVersion() < 9) {
return Potion.fromItemStack(itemStack).hasExtendedDuration();
} else {
return ((PotionMeta) itemStack.getItemMeta()).getBasePotionData().isExtended();
}
}
return false;
}
public static boolean isBannerPattern(ItemStack itemStack) {
return itemStack.getType().name().endsWith("BANNER_PATTERN");
}
public static boolean isAir(Material type) {
return Arrays.asList("AIR", "CAVE_AIR", "VOID_AIR").contains(type.name());
}
/**
* Get the {@link ItemStack} from a String
* @param item Serialized ItemStack e.g. {@code "STONE"} or {@code "STONE:1"}
* @return The de-serialized ItemStack or {@code null} if the serialized item is invalid
*/
public static ItemStack getItemStack(String item) {
if (item.trim().isEmpty()) return null;
if (item.contains(":")) {
Material mat = Material.getMaterial(item.split(":")[0]);
if (mat == null) return null;
return new ItemStack(mat, 1, Short.parseShort(item.split(":")[1]));
} else {
Material mat = Material.getMaterial(item);
if (mat == null) return null;
return new ItemStack(mat, 1);
}
}
}

View File

@ -1,75 +0,0 @@
package de.epiceric.shopchest.utils;
public enum Operator {
EQUAL("==") {
@Override
public boolean compare(double a, double b) {
return Double.compare(a, b) == 0;
}
@Override
public boolean compare(String a, String b) {
return a.equals(b);
}
},
NOT_EQUAL("!=") {
@Override
public boolean compare(double a, double b) {
return Double.compare(a, b) != 0;
}
@Override
public boolean compare(String a, String b) {
return !a.equals(b);
}
},
GREATER_THAN(">") {
@Override
public boolean compare(double a, double b) {
return a > b;
}
},
GREATER_THAN_OR_EQUAL(">=") {
@Override
public boolean compare(double a, double b) {
return a >= b;
}
},
LESS_THAN("<") {
@Override
public boolean compare(double a, double b) {
return a < b;
}
},
LESS_THAN_OR_EQUAL("<=") {
@Override
public boolean compare(double a, double b) {
return a <= b;
}
};
private final String symbol;
Operator(String symbol) {
this.symbol = symbol;
}
public static Operator from(String symbol) {
for (Operator operator : values()) {
if (operator.symbol.equals(symbol)) {
return operator;
}
}
throw new IllegalArgumentException();
}
public abstract boolean compare(double a, double b);
public boolean compare(String a, String b) {
throw new UnsupportedOperationException();
}
}

View File

@ -1,24 +0,0 @@
package de.epiceric.shopchest.utils;
public class Permissions {
public static final String CREATE = "shopchest.create";
public static final String CREATE_BUY = "shopchest.create.buy";
public static final String CREATE_SELL = "shopchest.create.sell";
public static final String CREATE_ADMIN = "shopchest.create.admin";
public static final String CREATE_PROTECTED = "shopchest.create.protected";
public static final String REMOVE_OTHER = "shopchest.remove.other";
public static final String REMOVE_ADMIN = "shopchest.remove.admin";
public static final String BUY = "shopchest.buy";
public static final String SELL = "shopchest.sell";
public static final String OPEN_OTHER = "shopchest.openOther";
public static final String UPDATE_NOTIFICATION = "shopchest.notification.update";
public static final String RELOAD = "shopchest.reload";
public static final String UPDATE = "shopchest.update";
public static final String NO_LIMIT = "shopchest.limit.*";
public static final String CONFIG = "shopchest.config";
public static final String EXTEND_OTHER = "shopchest.extend.other";
public static final String EXTEND_PROTECTED = "shopchest.extend.protected";
public static final String BYPASS_EXTERNAL_PLUGIN = "shopchest.external.bypass";
}

View File

@ -1,106 +0,0 @@
package de.epiceric.shopchest.utils;
import de.epiceric.shopchest.ShopChest;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class ShopUpdater {
private final ShopChest plugin;
private final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
private volatile Thread thread;
public ShopUpdater(ShopChest plugin) {
this.plugin = plugin;
}
/**
* Start task, except if it is already
*/
public void start() {
if (!isRunning()) {
thread = new Thread(() -> {
while (!Thread.interrupted()) {
try {
queue.take().run();
} catch (InterruptedException e) {
break;
}
}
}, "Shop Updater");
thread.start();
}
}
/**
* Stop any running task then start it again
*/
public void restart() {
stop();
start();
}
/**
* Stop task properly
*/
public void stop() {
if (thread != null) {
thread.interrupt();
thread = null;
}
}
/**
* @return whether task is running or not
*/
public boolean isRunning() {
return thread != null;
}
/**
* Queue a task to update shops for the given player
*
* @param player Player to show updates
*/
public void updateShops(Player player) {
queue(() -> plugin.getShopUtils().updateShops(player));
}
/**
* Queue a task to update shops for players in the given world
*
* @param world World in whose players to show updates
*/
public void updateShops(World world) {
queue(() -> {
for (Player player : world.getPlayers()) {
plugin.getShopUtils().updateShops(player);
}
});
}
/**
* Queue a task to update shops for all players
*/
public void updateShops() {
queue(() -> {
for (Player player : Bukkit.getOnlinePlayers()) {
plugin.getShopUtils().updateShops(player);
}
});
}
/**
* Register a task to run before next loop
*
* @param runnable task to run
*/
public void queue(Runnable runnable) {
queue.add(runnable);
}
}

View File

@ -1,441 +0,0 @@
package de.epiceric.shopchest.utils;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.shop.Shop;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.Chest;
import org.bukkit.block.DoubleChest;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.util.Vector;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class ShopUtils {
// concurrent since it is updated in async task
private final Map<UUID, Location> playerLocation = new ConcurrentHashMap<>();
private final Map<Location, Shop> shopLocation = new ConcurrentHashMap<>();
private final Collection<Shop> shopLocationValues = Collections.unmodifiableCollection(shopLocation.values());
private final ShopChest plugin;
public ShopUtils(ShopChest plugin) {
this.plugin = plugin;
}
/**
* Get the shop at a given location
*
* @param location Location of the shop
* @return Shop at the given location or <b>null</b> if no shop is found there
*/
public Shop getShop(Location location) {
Location newLocation = new Location(location.getWorld(), location.getBlockX(),
location.getBlockY(), location.getBlockZ());
return shopLocation.get(newLocation);
}
/**
* Checks whether there is a shop at a given location
* @param location Location to check
* @return Whether there is a shop at the given location
*/
public boolean isShop(Location location) {
return getShop(location) != null;
}
/**
* Get all shops
* Do not use for removing while iteration!
*
* @see #getShopsCopy()
* @return Read-only collection of all shops, may contain duplicates
*/
public Collection<Shop> getShops() {
return shopLocationValues;
}
/**
* Get all shops
* Same as {@link #getShops()} but this is safe to remove while iterating
*
* @see #getShops()
* @return Copy of collection of all shops, may contain duplicates
*/
public Collection<Shop> getShopsCopy() {
return new ArrayList<>(getShops());
}
/**
* Add a shop
* @param shop Shop to add
* @param addToDatabase Whether the shop should also be added to the database
* @param callback Callback that - if succeeded - returns the ID the shop had or was given (as {@code int})
*/
public void addShop(Shop shop, boolean addToDatabase, Callback<Integer> callback) {
InventoryHolder ih = shop.getInventoryHolder();
plugin.debug("Adding shop... (#" + shop.getID() + ")");
if (ih instanceof DoubleChest) {
DoubleChest dc = (DoubleChest) ih;
Chest r = (Chest) dc.getRightSide();
Chest l = (Chest) dc.getLeftSide();
plugin.debug("Added shop as double chest. (#" + shop.getID() + ")");
shopLocation.put(r.getLocation(), shop);
shopLocation.put(l.getLocation(), shop);
} else {
plugin.debug("Added shop as single chest. (#" + shop.getID() + ")");
shopLocation.put(shop.getLocation(), shop);
}
if (addToDatabase) {
plugin.getShopDatabase().addShop(shop, callback);
} else {
if (callback != null) callback.callSyncResult(shop.getID());
}
}
/**
* Add a shop
* @param shop Shop to add
* @param addToDatabase Whether the shop should also be added to the database
*/
public void addShop(Shop shop, boolean addToDatabase) {
addShop(shop, addToDatabase, null);
}
/** Remove a shop. May not work properly if double chest doesn't exist!
* @param shop Shop to remove
* @param removeFromDatabase Whether the shop should also be removed from the database
* @param callback Callback that - if succeeded - returns null
* @see ShopUtils#removeShopById(int, boolean, Callback)
*/
public void removeShop(Shop shop, boolean removeFromDatabase, Callback<Void> callback) {
plugin.debug("Removing shop (#" + shop.getID() + ")");
InventoryHolder ih = shop.getInventoryHolder();
if (ih instanceof DoubleChest) {
DoubleChest dc = (DoubleChest) ih;
Chest r = (Chest) dc.getRightSide();
Chest l = (Chest) dc.getLeftSide();
shopLocation.remove(r.getLocation());
shopLocation.remove(l.getLocation());
} else {
shopLocation.remove(shop.getLocation());
}
shop.removeItem();
shop.removeHologram();
if (removeFromDatabase) {
plugin.getShopDatabase().removeShop(shop, callback);
} else {
if (callback != null) callback.callSyncResult(null);
}
}
/**
* Remove a shop. May not work properly if double chest doesn't exist!
* @param shop Shop to remove
* @param removeFromDatabase Whether the shop should also be removed from the database
* @see ShopUtils#removeShopById(int, boolean)
*/
public void removeShop(Shop shop, boolean removeFromDatabase) {
removeShop(shop, removeFromDatabase, null);
}
/**
* Remove a shop by its ID
* @param shopId ID of the shop to remove
* @param removeFromDatabase Whether the shop should also be removed from the database
* @param callback Callback that - if succeeded - returns null
*/
public void removeShopById(int shopId, boolean removeFromDatabase, Callback<Void> callback) {
Map<Location, Shop> toRemove = shopLocation.entrySet().stream()
.filter(e -> e.getValue().getID() == shopId)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
plugin.debug(String.format("Removing %d shop(s) with ID %d", toRemove.size(), shopId));
if (toRemove.isEmpty()) {
if (callback != null) callback.callSyncResult(null);
return;
}
toRemove.forEach((loc, shop) -> {
shopLocation.remove(loc);
shop.removeItem();
shop.removeHologram();
});
// Database#removeShop removes shop by ID so this only needs to be called once
if (removeFromDatabase) {
plugin.getShopDatabase().removeShop(toRemove.values().iterator().next(), callback);
} else {
if (callback != null) callback.callSyncResult(null);
}
}
/**
* Remove a shop by its ID
* @param shopId ID of the shop to remove
* @param removeFromDatabase Whether the shop should also be removed from the database
*/
public void removeShopById(int shopId, boolean removeFromDatabase) {
removeShopById(shopId, removeFromDatabase, null);
}
/**
* Get the shop limits of a player
* @param p Player, whose shop limits should be returned
* @return The shop limits of the given player
*/
public int getShopLimit(Player p) {
int limit = 0;
boolean useDefault = true;
for (PermissionAttachmentInfo permInfo : p.getEffectivePermissions()) {
if (permInfo.getPermission().startsWith("shopchest.limit.") && p.hasPermission(permInfo.getPermission())) {
if (permInfo.getPermission().equalsIgnoreCase(Permissions.NO_LIMIT)) {
limit = -1;
useDefault = false;
break;
} else {
String[] spl = permInfo.getPermission().split("shopchest.limit.");
if (spl.length > 1) {
try {
int newLimit = Integer.valueOf(spl[1]);
if (newLimit < 0) {
limit = -1;
break;
}
limit = Math.max(limit, newLimit);
useDefault = false;
} catch (NumberFormatException ignored) {
/* Ignore and continue */
}
}
}
}
}
if (limit < -1) limit = -1;
return (useDefault ?Config.defaultLimit : limit);
}
/**
* Get the amount of shops of a player
* @param p Player, whose shops should be counted
* @return The amount of a shops a player has (if {@link Config#excludeAdminShops} is true, admin shops won't be counted)
*/
public int getShopAmount(OfflinePlayer p) {
float shopCount = 0;
for (Shop shop : getShops()) {
if (shop.getVendor().equals(p)) {
if (shop.getShopType() != Shop.ShopType.ADMIN) {
shopCount++;
InventoryHolder ih = shop.getInventoryHolder();
if (ih instanceof DoubleChest)
shopCount -= 0.5;
}
}
}
return Math.round(shopCount);
}
/**
* Reload the shops
* @param reloadConfig Whether the configuration should also be reloaded
* @param showConsoleMessages Whether messages about the language file should be shown in the console
* @param callback Callback that - if succeeded - returns the amount of shops that were reloaded (as {@code int})
*/
public void reloadShops(boolean reloadConfig, final boolean showConsoleMessages, final Callback<Integer> callback) {
plugin.debug("Reloading shops...");
if (reloadConfig) {
plugin.getShopChestConfig().reload(false, true, showConsoleMessages);
plugin.getHologramFormat().reload();
plugin.getUpdater().restart();
}
plugin.getShopDatabase().connect(new Callback<Integer>(plugin) {
@Override
public void onResult(Integer result) {
for (Shop shop : getShopsCopy()) {
removeShop(shop, false);
plugin.debug("Removed shop (#" + shop.getID() + ")");
}
plugin.getShopDatabase().getShops(showConsoleMessages, new Callback<Collection<Shop>>(plugin) {
@Override
public void onResult(Collection<Shop> result) {
for (Shop shop : result) {
if (shop.create(showConsoleMessages)) {
addShop(shop, false);
}
}
if (callback != null) callback.callSyncResult(result.size());
}
@Override
public void onError(Throwable throwable) {
if (callback != null) callback.callSyncError(throwable);
}
});
}
@Override
public void onError(Throwable throwable) {
if (callback != null) callback.callSyncError(throwable);
}
});
}
/**
* Update hologram and item of all shops for a player
* @param player Player to show the updates
*/
public void updateShops(Player player) {
updateShops(player, false);
}
/**
* Update hologram and item of all shops for a player
* @param player Player to show the updates
* @param force Whether update should be forced even if player has not moved
*/
public void updateShops(Player player, boolean force) {
if (!force && player.getLocation().equals(playerLocation.get(player.getUniqueId()))) {
// Player has not moved, so don't calculate shops again.
return;
}
if (Config.onlyShowShopsInSight) {
updateVisibleShops(player);
} else {
updateNearestShops(player);
}
playerLocation.put(player.getUniqueId(), player.getLocation());
}
/**
* Remove a saved location of a player to force a recalculation
* of whether the hologram should be visible.
* This should only be called when really needed
* @param player Player whose saved location will be reset
*/
public void resetPlayerLocation(Player player) {
playerLocation.remove(player.getUniqueId());
}
private void updateVisibleShops(Player player) {
double itemDistSquared = Math.pow(Config.maximalItemDistance, 2);
double maxDist = Config.maximalDistance;
double nearestDistSquared = Double.MAX_VALUE;
Shop nearestShop = null;
Location pLoc = player.getEyeLocation();
Vector pDir = pLoc.getDirection();
// Display holograms based on sight
for (double i = 0; i <= maxDist; i++) {
Location loc = pLoc.clone();
Vector dir = pDir.clone();
double factor = Math.min(i, maxDist);
loc.add(dir.multiply(factor));
Location locBelow = loc.clone().subtract(0, 1, 0);
// Check block below as player may look at hologram
Shop shop = getShop(loc);
if (shop == null) {
shop = getShop(locBelow);
}
if (shop != null && shop.hasHologram()) {
double distSquared = pLoc.distanceSquared(loc);
if (distSquared < nearestDistSquared) {
nearestDistSquared = distSquared;
nearestShop = shop;
}
}
}
for (Shop shop : getShops()) {
if (!shop.equals(nearestShop) && shop.hasHologram()) {
shop.getHologram().hidePlayer(player);
}
// Display item based on distance
Location shopLocation = shop.getLocation();
if (shopLocation.getWorld().getName().equals(player.getWorld().getName())) {
double distSquared = shop.getLocation().distanceSquared(player.getLocation());
if (shop.hasItem()) {
if (distSquared <= itemDistSquared) {
shop.getItem().showPlayer(player);
} else {
shop.getItem().hidePlayer(player);
}
}
}
}
if (nearestShop != null) {
nearestShop.getHologram().showPlayer(player);
}
}
private void updateNearestShops(Player p) {
double holoDistSqr = Math.pow(Config.maximalDistance, 2);
double itemDistSqr = Math.pow(Config.maximalItemDistance, 2);
Location playerLocation = p.getLocation();
for (Shop shop : getShops()) {
if (playerLocation.getWorld().getName().equals(shop.getLocation().getWorld().getName())) {
double distSqr = shop.getLocation().distanceSquared(playerLocation);
if (shop.hasHologram()) {
if (distSqr <= holoDistSqr) {
shop.getHologram().showPlayer(p);
} else {
shop.getHologram().hidePlayer(p);
}
}
if (shop.hasItem()) {
if (distSqr <= itemDistSqr) {
shop.getItem().showPlayer(p);
} else {
shop.getItem().hidePlayer(p);
}
}
}
}
}
}

View File

@ -1,88 +0,0 @@
package de.epiceric.shopchest.utils;
import de.epiceric.shopchest.ShopChest;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class UpdateChecker {
private ShopChest plugin;
private String version;
private String link;
public UpdateChecker(ShopChest plugin) {
this.plugin = plugin;
}
/**
* Check if an update is needed
*
* @return {@link UpdateCheckerResult#TRUE} if an update is available,
* {@link UpdateCheckerResult#FALSE} if no update is needed or
* {@link UpdateCheckerResult#ERROR} if an error occurred
*/
public UpdateCheckerResult check() {
try {
plugin.debug("Checking for updates...");
URL url = new URL("https://api.spiget.org/v2/resources/11431/versions?size=1&page=1&sort=-releaseDate");
URLConnection conn = url.openConnection();
conn.setRequestProperty("User-Agent", "ShopChest/UpdateChecker");
InputStreamReader reader = new InputStreamReader(conn.getInputStream());
JsonElement element = new JsonParser().parse(reader);
if (element.isJsonArray()) {
JsonObject result = element.getAsJsonArray().get(0).getAsJsonObject();
String id = result.get("id").getAsString();
version = result.get("name").getAsString();
link = "https://www.spigotmc.org/resources/shopchest.11431/download?version=" + id;
} else {
plugin.debug("Failed to check for updates");
plugin.debug("Result: " + element.toString());
return UpdateCheckerResult.ERROR;
}
if (plugin.getDescription().getVersion().equals(version)) {
plugin.debug("No update found");
return UpdateCheckerResult.FALSE;
} else {
plugin.debug("Update found: " + version);
return UpdateCheckerResult.TRUE;
}
} catch (Exception e) {
plugin.debug("Failed to check for updates");
plugin.debug(e);
return UpdateCheckerResult.ERROR;
}
}
/**
* @return Latest Version or <b>null</b> if no update is available
*/
public String getVersion() {
return version;
}
/**
* @return Download Link of the latest version of <b>null</b> if no update is available
*/
public String getLink() {
return link;
}
public enum UpdateCheckerResult {
TRUE,
FALSE,
ERROR
}
}

View File

@ -1,646 +0,0 @@
package de.epiceric.shopchest.utils;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Chest;
import org.bukkit.block.DoubleChest;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.BookMeta;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.util.Vector;
import de.epiceric.shopchest.ShopChest;
import de.epiceric.shopchest.config.Placeholder;
import de.epiceric.shopchest.language.LanguageUtils;
import de.epiceric.shopchest.language.Message;
import de.epiceric.shopchest.language.Replacement;
import de.epiceric.shopchest.nms.CustomBookMeta;
import de.epiceric.shopchest.nms.JsonBuilder;
import de.epiceric.shopchest.shop.Shop;
public class Utils {
/**
* Check if two items are similar to each other
* @param itemStack1 The first item
* @param itemStack2 The second item
* @return {@code true} if the given items are similar or {@code false} if not
*/
public static boolean isItemSimilar(ItemStack itemStack1, ItemStack itemStack2) {
if (itemStack1 == null || itemStack2 == null) {
return false;
}
ItemMeta itemMeta1 = itemStack1.getItemMeta();
ItemMeta itemMeta2 = itemStack2.getItemMeta();
if (itemMeta1 instanceof BookMeta && itemMeta2 instanceof BookMeta) {
BookMeta bookMeta1 = (BookMeta) itemStack1.getItemMeta();
BookMeta bookMeta2 = (BookMeta) itemStack2.getItemMeta();
if ((getMajorVersion() == 9 && getRevision() == 1) || getMajorVersion() == 8) {
CustomBookMeta.Generation generation1 = CustomBookMeta.getGeneration(itemStack1);
CustomBookMeta.Generation generation2 = CustomBookMeta.getGeneration(itemStack2);
if (generation1 == null) CustomBookMeta.setGeneration(itemStack1, CustomBookMeta.Generation.ORIGINAL);
if (generation2 == null) CustomBookMeta.setGeneration(itemStack2, CustomBookMeta.Generation.ORIGINAL);
} else {
if (bookMeta1.getGeneration() == null) bookMeta1.setGeneration(BookMeta.Generation.ORIGINAL);
if (bookMeta2.getGeneration() == null) bookMeta2.setGeneration(BookMeta.Generation.ORIGINAL);
}
itemStack1.setItemMeta(bookMeta1);
itemStack2.setItemMeta(bookMeta2);
itemStack1 = decode(encode(itemStack1));
itemStack2 = decode(encode(itemStack2));
}
return itemStack1.isSimilar(itemStack2);
}
/**
* Gets the amount of items in an inventory
*
* @param inventory The inventory, in which the items are counted
* @param itemStack The items to count
* @return Amount of given items in the given inventory
*/
public static int getAmount(Inventory inventory, ItemStack itemStack) {
int amount = 0;
ArrayList<ItemStack> inventoryItems = new ArrayList<>();
if (inventory instanceof PlayerInventory) {
for (int i = 0; i < 37; i++) {
if (i == 36) {
if (getMajorVersion() < 9) {
break;
}
i = 40;
}
inventoryItems.add(inventory.getItem(i));
}
} else {
for (int i = 0; i < inventory.getSize(); i++) {
inventoryItems.add(inventory.getItem(i));
}
}
for (ItemStack item : inventoryItems) {
if (isItemSimilar(item, itemStack)) {
amount += item.getAmount();
}
}
return amount;
}
/**
* Get the amount of the given item, that fits in the given inventory
*
* @param inventory Inventory, where to search for free space
* @param itemStack Item, of which the amount that fits in the inventory should be returned
* @return Amount of the given item, that fits in the given inventory
*/
public static int getFreeSpaceForItem(Inventory inventory, ItemStack itemStack) {
HashMap<Integer, Integer> slotFree = new HashMap<>();
if (inventory instanceof PlayerInventory) {
for (int i = 0; i < 37; i++) {
if (i == 36) {
if (getMajorVersion() < 9) {
break;
}
i = 40;
}
ItemStack item = inventory.getItem(i);
if (item == null || item.getType() == Material.AIR) {
slotFree.put(i, itemStack.getMaxStackSize());
} else {
if (isItemSimilar(item, itemStack)) {
int amountInSlot = item.getAmount();
int amountToFullStack = itemStack.getMaxStackSize() - amountInSlot;
slotFree.put(i, amountToFullStack);
}
}
}
} else {
for (int i = 0; i < inventory.getSize(); i++) {
ItemStack item = inventory.getItem(i);
if (item == null || item.getType() == Material.AIR) {
slotFree.put(i, itemStack.getMaxStackSize());
} else {
if (isItemSimilar(item, itemStack)) {
int amountInSlot = item.getAmount();
int amountToFullStack = itemStack.getMaxStackSize() - amountInSlot;
slotFree.put(i, amountToFullStack);
}
}
}
}
int freeAmount = 0;
for (int value : slotFree.values()) {
freeAmount += value;
}
return freeAmount;
}
/**
* @param p Player whose item in his main hand should be returned
* @return {@link ItemStack} in his main hand, or {@code null} if he doesn't hold one
*/
public static ItemStack getItemInMainHand(Player p) {
if (getMajorVersion() < 9) {
if (p.getItemInHand().getType() == Material.AIR)
return null;
else
return p.getItemInHand();
}
if (p.getInventory().getItemInMainHand().getType() == Material.AIR)
return null;
else
return p.getInventory().getItemInMainHand();
}
/**
* @param p Player whose item in his off hand should be returned
* @return {@link ItemStack} in his off hand, or {@code null} if he doesn't hold one or the server version is below 1.9
*/
public static ItemStack getItemInOffHand(Player p) {
if (getMajorVersion() < 9)
return null;
else if (p.getInventory().getItemInOffHand().getType() == Material.AIR)
return null;
else
return p.getInventory().getItemInOffHand();
}
/**
* @param p Player whose item in his hand should be returned
* @return Item in his main hand, or the item in his off if he doesn't have one in this main hand, or {@code null}
* if he doesn't have one in both hands
*/
public static ItemStack getPreferredItemInHand(Player p) {
if (getMajorVersion() < 9)
return getItemInMainHand(p);
else if (getItemInMainHand(p) != null)
return getItemInMainHand(p);
else
return getItemInOffHand(p);
}
/**
* @param p Player to check if he has an axe in one of his hands
* @return Whether a player has an axe in one of his hands
*/
public static boolean hasAxeInHand(Player p) {
List<String> axes;
if (Utils.getMajorVersion() < 13)
axes = Arrays.asList("WOOD_AXE", "STONE_AXE", "IRON_AXE", "GOLD_AXE", "DIAMOND_AXE");
else
axes = Arrays.asList("WOODEN_AXE", "STONE_AXE", "IRON_AXE", "GOLDEN_AXE", "DIAMOND_AXE");
ItemStack item = getItemInMainHand(p);
if (item == null || !axes.contains(item.getType().toString())) {
item = getItemInOffHand(p);
}
return item != null && axes.contains(item.getType().toString());
}
/**
* <p>Check if a player is allowed to create a shop that sells or buys the given item.</p>
* @param player Player to check
* @param item Item to be sold or bought
* @param buy Whether buying should be enabled
* @param sell Whether selling should be enabled
* @return Whether the player is allowed
*/
public static boolean hasPermissionToCreateShop(Player player, ItemStack item, boolean buy, boolean sell) {
if (hasPermissionToCreateShop(player, item, Permissions.CREATE)) {
return true;
} else if (!sell && buy && hasPermissionToCreateShop(player, item,Permissions.CREATE_BUY)) {
return true;
} else if (!buy && sell && hasPermissionToCreateShop(player, item, Permissions.CREATE_SELL)) {
return true;
} else if (buy && sell && hasPermissionToCreateShop(player, item, Permissions.CREATE_BUY, Permissions.CREATE_SELL)) {
return true;
}
return false;
}
private static boolean hasPermissionToCreateShop(Player player, ItemStack item, String... permissions) {
for (String permission : permissions) {
boolean b1 = false;
boolean b2 = false;
boolean b3 = false;
if (player.hasPermission(permission)) {
b1 = true;
}
if (item != null) {
if (item.getDurability() == 0) {
String perm1 = permission + "." + item.getType().toString();
String perm2 = permission + "." + item.getType().toString() + ".0";
if (player.hasPermission(perm1) || player.hasPermission(perm2)) {
b2 = true;
}
}
if (player.hasPermission(permission + "." + item.getType().toString() + "." + item.getDurability())) {
b3 = true;
}
}
if (!(b1 || b2 || b3)) {
return false;
}
}
return true;
}
/**
* Get a set for the location(s) of the shop's chest(s)
* @param shop The shop
* @return A set of 1 or 2 locations
*/
public static Set<Location> getChestLocations(Shop shop) {
Set<Location> chestLocations = new HashSet<>();
InventoryHolder ih = shop.getInventoryHolder();
if (ih instanceof DoubleChest) {
DoubleChest dc = (DoubleChest) ih;
chestLocations.add(((Chest) dc.getLeftSide()).getLocation());
chestLocations.add(((Chest) dc.getRightSide()).getLocation());
} else {
chestLocations.add(shop.getLocation());
}
return chestLocations;
}
/**
* Send a clickable update notification to the given player.
* @param plugin An instance of the {@link ShopChest} plugin
* @param p The player to receive the notification
*/
public static void sendUpdateMessage(ShopChest plugin, Player p) {
JsonBuilder jb = new JsonBuilder(plugin);
Map<String, JsonBuilder.Part> hoverEvent = new HashMap<>();
hoverEvent.put("action", new JsonBuilder.Part("show_text"));
hoverEvent.put("value", new JsonBuilder.Part(LanguageUtils.getMessage(Message.UPDATE_CLICK_TO_DOWNLOAD)));
Map<String, JsonBuilder.Part> clickEvent = new HashMap<>();
clickEvent.put("action", new JsonBuilder.Part("open_url"));
clickEvent.put("value", new JsonBuilder.Part(plugin.getDownloadLink()));
JsonBuilder.PartMap rootPart = JsonBuilder.parse(LanguageUtils.getMessage(Message.UPDATE_AVAILABLE,
new Replacement(Placeholder.VERSION, plugin.getLatestVersion()))).toMap();
rootPart.setValue("hoverEvent", new JsonBuilder.PartMap(hoverEvent));
rootPart.setValue("clickEvent", new JsonBuilder.PartMap(clickEvent));
jb.setRootPart(rootPart);
jb.sendJson(p);
}
/**
* @param className Name of the class
* @return Class in {@code net.minecraft.server.[VERSION]} package with the specified name or {@code null} if the class was not found
*/
public static Class<?> getNMSClass(String className) {
try {
return Class.forName("net.minecraft.server." + getServerVersion() + "." + className);
} catch (ClassNotFoundException e) {
return null;
}
}
/**
* @param className Name of the class
* @return Class in {@code org.bukkit.craftbukkit.[VERSION]} package with the specified name or {@code null} if the class was not found
*/
public static Class<?> getCraftClass(String className) {
try {
return Class.forName("org.bukkit.craftbukkit." + getServerVersion() + "." + className);
} catch (ClassNotFoundException e) {
return null;
}
}
/**
* Create a NMS data watcher object to send via a {@code PacketPlayOutEntityMetadata} packet.
* Gravity will be disabled and the custom name will be displayed if available.
* @param customName Custom Name of the entity or {@code null}
* @param nmsItemStack NMS ItemStack or {@code null} if armor stand
*/
public static Object createDataWatcher(String customName, Object nmsItemStack) {
String version = getServerVersion();
int majorVersion = getMajorVersion();
try {
Class<?> entityClass = getNMSClass("Entity");
Class<?> entityArmorStandClass = getNMSClass("EntityArmorStand");
Class<?> entityItemClass = getNMSClass("EntityItem");
Class<?> dataWatcherClass = getNMSClass("DataWatcher");
Class<?> dataWatcherObjectClass = getNMSClass("DataWatcherObject");
byte entityFlags = nmsItemStack == null ? (byte) 0b100000 : 0; // invisible if armor stand
byte armorStandFlags = nmsItemStack == null ? (byte) 0b10000 : 0; // marker (since 1.8_R2)
Object dataWatcher = dataWatcherClass.getConstructor(entityClass).newInstance((Object) null);
if (majorVersion < 9) {
if (getRevision() == 1) armorStandFlags = 0; // Marker not supported on 1.8_R1
Method a = dataWatcherClass.getMethod("a", int.class, Object.class);
a.invoke(dataWatcher, 0, entityFlags); // flags
a.invoke(dataWatcher, 1, (short) 300); // air ticks (?)
a.invoke(dataWatcher, 3, (byte) (customName != null ? 1 : 0)); // custom name visible
a.invoke(dataWatcher, 2, customName != null ? customName : ""); // custom name
a.invoke(dataWatcher, 4, (byte) 1); // silent
a.invoke(dataWatcher, 10, nmsItemStack == null ? armorStandFlags : nmsItemStack); // item / armor stand flags
} else {
Method register = dataWatcherClass.getMethod("register", dataWatcherObjectClass, Object.class);
String[] dataWatcherObjectFieldNames;
if ("v1_9_R1".equals(version)) {
dataWatcherObjectFieldNames = new String[] {"ax", "ay", "aA", "az", "aB", null, "c", "a"};
} else if ("v1_9_R2".equals(version)){
dataWatcherObjectFieldNames = new String[] {"ay", "az", "aB", "aA", "aC", null, "c", "a"};
} else if ("v1_10_R1".equals(version)) {
dataWatcherObjectFieldNames = new String[] {"aa", "az", "aB", "aA", "aC", "aD", "c", "a"};
} else if ("v1_11_R1".equals(version)) {
dataWatcherObjectFieldNames = new String[] {"Z", "az", "aB", "aA", "aC", "aD", "c", "a"};
} else if ("v1_12_R1".equals(version) || "v1_12_R2".equals(version)) {
dataWatcherObjectFieldNames = new String[] {"Z", "aA", "aC", "aB", "aD", "aE", "c", "a"};
} else if ("v1_13_R1".equals(version) || "v1_13_R2".equals(version)) {
dataWatcherObjectFieldNames = new String[] {"ac", "aD", "aF", "aE", "aG", "aH", "b", "a"};
} else if ("v1_14_R1".equals(version)) {
dataWatcherObjectFieldNames = new String[] {"W", "AIR_TICKS", "aA", "az", "aB", "aC", "ITEM", "b"};
} else {
return null;
}
Field fEntityFlags = entityClass.getDeclaredField(dataWatcherObjectFieldNames[0]);
Field fAirTicks = entityClass.getDeclaredField(dataWatcherObjectFieldNames[1]);
Field fNameVisible = entityClass.getDeclaredField(dataWatcherObjectFieldNames[2]);
Field fCustomName = entityClass.getDeclaredField(dataWatcherObjectFieldNames[3]);
Field fSilent = entityClass.getDeclaredField(dataWatcherObjectFieldNames[4]);
Field fNoGravity = majorVersion >= 10 ? entityClass.getDeclaredField(dataWatcherObjectFieldNames[5]) : null;
Field fItem = entityItemClass.getDeclaredField(dataWatcherObjectFieldNames[6]);
Field fArmorStandFlags = entityArmorStandClass.getDeclaredField(dataWatcherObjectFieldNames[7]);
fEntityFlags.setAccessible(true);
fAirTicks.setAccessible(true);
fNameVisible.setAccessible(true);
fCustomName.setAccessible(true);
fSilent.setAccessible(true);
if (majorVersion >= 10) fNoGravity.setAccessible(true);
fItem.setAccessible(true);
fArmorStandFlags.setAccessible(true);
register.invoke(dataWatcher, fEntityFlags.get(null), entityFlags);
register.invoke(dataWatcher, fAirTicks.get(null), 300);
register.invoke(dataWatcher, fNameVisible.get(null), customName != null);
register.invoke(dataWatcher, fSilent.get(null), true);
if (majorVersion < 13) register.invoke(dataWatcher, fCustomName.get(null), customName != null ? customName : "");
if (nmsItemStack != null) {
register.invoke(dataWatcher, fItem.get(null), majorVersion < 11 ? com.google.common.base.Optional.of(nmsItemStack) : nmsItemStack);
} else {
register.invoke(dataWatcher, fArmorStandFlags.get(null), armorStandFlags);
}
if (majorVersion >= 10) {
register.invoke(dataWatcher, fNoGravity.get(null), true);
if (majorVersion >= 13) {
if (customName != null) {
Class<?> chatSerializerClass = Utils.getNMSClass("IChatBaseComponent$ChatSerializer");
Object iChatBaseComponent = chatSerializerClass.getMethod("a", String.class).invoke(null, JsonBuilder.parse(customName).toString());
register.invoke(dataWatcher, fCustomName.get(null), Optional.of(iChatBaseComponent));
} else {
register.invoke(dataWatcher, fCustomName.get(null), Optional.empty());
}
}
}
}
return dataWatcher;
} catch (InstantiationException | InvocationTargetException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException e) {
ShopChest.getInstance().getLogger().severe("Failed to create data watcher!");
ShopChest.getInstance().debug("Failed to create data watcher");
ShopChest.getInstance().debug(e);
}
return null;
}
/**
* Get a free entity ID for use in {@link #createPacketSpawnEntity(ShopChest, int, UUID, Location, Vector, EntityType)}
*
* @return The id or {@code -1} if a free entity ID could not be retrieved.
*/
public static int getFreeEntityId() {
try {
Class<?> entityClass = getNMSClass("Entity");
Field entityCountField = entityClass.getDeclaredField("entityCount");
entityCountField.setAccessible(true);
if (entityCountField.getType() == int.class) {
int id = entityCountField.getInt(null);
entityCountField.setInt(null, id+1);
return id;
} else if (entityCountField.getType() == AtomicInteger.class) {
return ((AtomicInteger) entityCountField.get(null)).incrementAndGet();
}
return -1;
} catch (Exception e) {
return -1;
}
}
/**
* Create a {@code PacketPlayOutSpawnEntity} object.
* Only {@link EntityType#ARMOR_STAND} and {@link EntityType#DROPPED_ITEM} are supported!
*/
public static Object createPacketSpawnEntity(ShopChest plugin, int id, UUID uuid, Location loc, EntityType type) {
try {
Class<?> packetClass = getNMSClass("PacketPlayOutSpawnEntity");
Object packet = packetClass.getConstructor().newInstance();
boolean isPre9 = getMajorVersion() < 9;
boolean isPre14 = getMajorVersion() < 14;
Field[] fields = new Field[12];
fields[0] = packetClass.getDeclaredField("a"); // ID
fields[1] = packetClass.getDeclaredField("b"); // UUID (Only 1.9+)
fields[2] = packetClass.getDeclaredField(isPre9 ? "b" : "c"); // Loc X
fields[3] = packetClass.getDeclaredField(isPre9 ? "c" : "d"); // Loc Y
fields[4] = packetClass.getDeclaredField(isPre9 ? "d" : "e"); // Loc Z
fields[5] = packetClass.getDeclaredField(isPre9 ? "e" : "f"); // Mot X
fields[6] = packetClass.getDeclaredField(isPre9 ? "f" : "g"); // Mot Y
fields[7] = packetClass.getDeclaredField(isPre9 ? "g" : "h"); // Mot Z
fields[8] = packetClass.getDeclaredField(isPre9 ? "h" : "i"); // Pitch
fields[9] = packetClass.getDeclaredField(isPre9 ? "i" : "j"); // Yaw
fields[10] = packetClass.getDeclaredField(isPre9 ? "j" : "k"); // Type
fields[11] = packetClass.getDeclaredField(isPre9 ? "k" : "l"); // Data
for (Field field : fields) {
field.setAccessible(true);
}
Object entityType = null;
if (!isPre14) {
Class<?> entityTypesClass = getNMSClass("EntityTypes");
entityType = entityTypesClass.getField(type == EntityType.ARMOR_STAND ? "ARMOR_STAND" : "ITEM").get(null);
}
double y = loc.getY();
if (type == EntityType.ARMOR_STAND && !getServerVersion().equals("v1_8_R1")) {
// Marker armor stand => lift by normal armor stand height
y += 1.975;
}
fields[0].set(packet, id);
if (!isPre9) fields[1].set(packet, uuid);
if (isPre9) {
fields[2].set(packet, (int)(loc.getX() * 32));
fields[3].set(packet, (int)(y * 32));
fields[4].set(packet, (int)(loc.getZ() * 32));
} else {
fields[2].set(packet, loc.getX());
fields[3].set(packet, y);
fields[4].set(packet, loc.getZ());
}
fields[5].set(packet, 0);
fields[6].set(packet, 0);
fields[7].set(packet, 0);
fields[8].set(packet, 0);
fields[9].set(packet, 0);
if (isPre14) fields[10].set(packet, type == EntityType.ARMOR_STAND ? 78 : 2);
else fields[10].set(packet, entityType);
fields[11].set(packet, 0);
return packet;
} catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
plugin.getLogger().severe("Failed to create packet to spawn entity!");
plugin.debug("Failed to create packet to spawn entity!");
plugin.debug(e);
return null;
}
}
/**
* Send a packet to a player
* @param plugin An instance of the {@link ShopChest} plugin
* @param packet Packet to send
* @param player Player to which the packet should be sent
* @return {@code true} if the packet was sent, or {@code false} if an exception was thrown
*/
public static boolean sendPacket(ShopChest plugin, Object packet, Player player) {
try {
if (packet == null) {
plugin.debug("Failed to send packet: Packet is null");
return false;
}
Class<?> packetClass = getNMSClass("Packet");
if (packetClass == null) {
plugin.debug("Failed to send packet: Could not find Packet class");
return false;
}
Object nmsPlayer = player.getClass().getMethod("getHandle").invoke(player);
Object playerConnection = nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer);
playerConnection.getClass().getMethod("sendPacket", packetClass).invoke(playerConnection, packet);
return true;
} catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException | InvocationTargetException e) {
plugin.getLogger().severe("Failed to send packet " + packet.getClass().getName());
plugin.debug("Failed to send packet " + packet.getClass().getName());
plugin.debug(e);
return false;
}
}
/**
* @return The current server version with revision number (e.g. v1_9_R2, v1_10_R1)
*/
public static String getServerVersion() {
String packageName = Bukkit.getServer().getClass().getPackage().getName();
return packageName.substring(packageName.lastIndexOf('.') + 1);
}
/**
* @return The revision of the current server version (e.g. <i>2</i> for v1_9_R2, <i>1</i> for v1_10_R1)
*/
public static int getRevision() {
return Integer.parseInt(getServerVersion().substring(getServerVersion().length() - 1));
}
/**
* @return The major version of the server (e.g. <i>9</i> for 1.9.2, <i>10</i> for 1.10)
*/
public static int getMajorVersion() {
return Integer.parseInt(getServerVersion().split("_")[1]);
}
/**
* Encodes an {@link ItemStack} in a Base64 String
* @param itemStack {@link ItemStack} to encode
* @return Base64 encoded String
*/
public static String encode(ItemStack itemStack) {
YamlConfiguration config = new YamlConfiguration();
config.set("i", itemStack);
return Base64.getEncoder().encodeToString(config.saveToString().getBytes(StandardCharsets.UTF_8));
}
/**
* Decodes an {@link ItemStack} from a Base64 String
* @param string Base64 encoded String to decode
* @return Decoded {@link ItemStack}
*/
public static ItemStack decode(String string) {
YamlConfiguration config = new YamlConfiguration();
try {
config.loadFromString(new String(Base64.getDecoder().decode(string), StandardCharsets.UTF_8));
} catch (IllegalArgumentException | InvalidConfigurationException e) {
e.printStackTrace();
return null;
}
return config.getItemStack("i", null);
}
}

View File

@ -1,220 +0,0 @@
# ===============================================
# ====== Configuration File of 'ShopChest' ======
# ===============================================
#
# Lines starting with '#' are comments and are ignored by the server.
#
# You can find item names in the 'item_names.txt' file.
# Set the main command you have to enter to manage the shops.
# (default: "/shop ...")
main-command-name: "shop"
# Set the language file for all translatable messages or names.
# The value must equal to the name of one of a file in the 'lang' folder
# (without the '.lang' extension).
language-file: "en_US"
# Set the item with which a player can click a shop to retrieve information.
# You can set this to an empty string ("") to disable this feature.
shop-info-item: "STICK"
# Set whether buys or sells need to be confirmed by the player
# in order to prevent accidents.
confirm-shopping: false
# Set whether players should be able to select the shop item from the
# creative inventory if they don't hold an item in their hand.
# !! This feature may be exploitable, players could get access to creative mode!
creative-select-item: false
# Set whether the (current) shop creation price should be refunded
# when the shop is removed by its creator.
refund-shop-creation: false
# Set whether the plugin will check for updates on server start
# and notify permitted players on join.
# The command is not affected by this setting and will continue to
# check for updates.
enable-update-checker: true
# Set whether buys and sells should be logged in the database.
enable-economy-log: false
# Set the maximum age for economy log entries in days.
# All log entries older than this will be deleted on server start.
# Set this to 0 to disable this feature.
cleanup-economy-log-days: 30
# Set whether a debug log file should be created.
# The file may get large! Please enable this setting when reporting issues.
enable-debug-log: false
# Set whether various protection plugins should be hooked into (if installed)
# in order to allow or deny shop creation in certain locations.
enable-worldguard-integration: true
enable-towny-integration: true
enable-authme-integration: true
enable-plotsquared-integration: true
enable-uskyblock-integration: true
enable-askyblock-integration: true
enable-islandworld-integration: true
enable-griefprevention-integration: true
enable-areashop-integration: true
# Set whether the vendor of a shop should get messages when players buy
# or sell something from/to his shop or when his shop is out of stock.
enable-vendor-messages: true
# Set whether only the shop a player is pointing at should be shown.
# If set to false, every shop near the player (with the specified
# distance) will be shown to him.
only-show-shops-in-sight: true
# Set whether the hologram's location should be fixed at the bottom,
# so when it gets more lines, it won't interfere with the item or chest,
# but goes higher.
hologram-fixed-bottom: true
# Set the amount (may be negative) a hologram should be lifted in the y-axis.
# A value of '1' equals to one block, and a value of '0.25' is equal to the
# height of one line.
hologram-lift: 0
# Set whether players should be allowed to buy or sell less items
# than the vendor has specified, in case the player does not have enough
# money or items, or if the chest does not have enough items or space,
# or if the vendor does not have enough money.
# The price will be calculated correspondingly.
auto-calculate-item-amount: false
# Set whether prices may contain decimals (prices of existing shops will stay).
allow-decimals-in-price: true
# Set whether players should be allowed to sell/buy broken items.
allow-broken-items: false
# Set whether the level of a potion or tipped arrow (if upgraded) should be
# appended to the item name. If set to true, the level ("II") will be
# displayed after the item name, but only if the item does not have a
# custom name.
append-potion-level-to-item-name: false
# Set whether shops should automatically be removed from the database if
# an error occurred while loading.
# (e.g. no chest, no space above chest, or unknown world)
remove-shop-on-error: false
# Set whether the mouse buttons should be inverted.
# Default:
# Right-Click -> Buy
# Left-Click -> Sell
invert-mouse-buttons: false
# Set the maximal distance (in blocks) to the shop where the
# player can see the hologram.
maximal-distance: 2
# Set the maximal distance (in blocks) to the shop where the
# player can see the floating shop item.
maximal-item-distance: 40
# Set whether the buy price must be greater than or equal to the sell price.
buy-greater-or-equal-sell: true
# Set the minimum and maximum prices for each individual item.
minimum-prices:
# "DIAMOND": 0.5
maximum-prices:
# "STONE": 2
# Set the items of which a player can't create a shop.
blacklist:
# - "DIORITE"
# Set the price a player has to pay in order to create...
# You can set this to 0 to disable costs.
shop-creation-price:
# ...a normal shop
normal: 5
# ...an admin shop
admin: 0
# Shop limits are handled with permissions.
# A player with permission "shopchest.limit.X" has a limit of X shops,
# a player with permission "shopchest.limit.*" does not have a shop limit.
# Admin shops are excluded from the shop limit.
shop-limits:
# Set the amount of shops that anyone who doesn't have a
# specific permission may have.
# If you don't want the players to have a limit by default
# set the value to -1.
default: 5
# Set the events of AreaShop when shops on that region should be removed.
# Valid values are: DELETE, UNRENT, RESELL, SELL
areashop-remove-shops:
- "DELETE"
- "UNRENT"
- "RESELL"
- "SELL"
# Set whether the custom WorldGuard flags should be allowed by default.
worldguard-default-flag-values:
create-shop: false
use-shop: false
use-admin-shop: false
# Set the types of Towny plots where shop creation should be allowed.
# Valid values are:
# RESIDENTIAL, COMMERCIAL, ARENA, EMBASSY, WILDS, SPLEEF, INN, JAIL, FARM
towny-shop-plots:
residents:
- "COMMERCIAL"
mayor:
- "COMMERCIAL"
king:
- "COMMERCIAL"
# Configuration of the database, where everything is stored.
# Shops are found in the table 'shopchest_shops', and logged economy
# transactions are found in the table 'shopchest_economy_logs'
database:
# Select the type of database which should be used
# Either use 'SQLite' or 'MySQL'. Otherwise you will break the plugin!
type: "SQLite"
# Set the prefix of all table names related to this plugin.
table-prefix: "shopchest_"
# If the specified type is 'MySQL', here you configure the...
mysql:
# ...interval in seconds, when the database should be pinged,
# to keep the connection alive
# You can set this to '0' to disable the ping interval
ping-interval: 3600
# ...hostname where the database is accessible
hostname: ""
# ...port where the database is accessible (default: 3306)
port: 3306
# ...database you want to use
database: ""
# ...username you are going to login with
username: ""
# ...password you are going to login with
password: ""

View File

@ -1,78 +0,0 @@
# ===============================================
# === ShopChest's hologram configuration file ===
# ===============================================
#
# Valid requirements are:
# VENDOR, AMOUNT, ITEM_TYPE, ITEM_NAME, HAS_ENCHANTMENT, BUY_PRICE,
# SELL_PRICE, HAS_POTION_EFFECT, IS_MUSIC_DISC, IS_POTION_EXTENDED,
# IS_WRITTEN_BOOK, IS_BANNER_PATTERN, ADMIN_SHOP, NORMAL_SHOP,
# IN_STOCK, MAX_STACK, CHEST_SPACE, DURABILITY
#
# You can also use the requirements for conditions.
# ITEM_TYPE will return the type of the item (-> item_names.txt),
# ITEM_NAME can be compared against a custom named item's name (may be null).
#
# Examples:
# - IN_STOCK > 0
# - VENDOR == "EpicEric"
# - BUY_PRICE <= SELL_PRICE
# - ITEM_TYPE == "STONE:2"
# - ITEM_TYPE != "IRON_INGOT"
# - ITEM_NAME == "The Mighty Sword"
# - (AMOUNT > 10) && (AMOUNT <= 20)
# - (IN_STOCK > 0) || ADMIN_SHOP
#
# Valid placeholders are:
# %VENDOR%, %AMOUNT%, %ITEMNAME%, %ENCHANTMENT%, %BUY-PRICE%,
# %SELL-PRICE%, %POTION-EFFECT%, %MUSIC-TITLE%, %BANNER-PATTERN-NAME%,
# %GENERATION%, %STOCK%, %MAX-STACK%, %CHEST-SPACE%, %DURABILITY%
#
# In the format, placeholders can also be used for scripts.
# Examples:
# - "In Stock: {%STOCK% / 64} Stk."
# - "In Stock: {(%STOCK% - (%STOCK% % 64)) / 64} Stk. {%STOCK% % 64}"
#
# Other information:
# - Options can be called however you want.
# - Color codes can be used in the format.
# - Options are checked from top to bottom; the first to
# fulfill the requirements will be taken.
# - All scripts have to be in JavaScript syntax.
# - Lines start with 0.
lines:
0:
options:
normal-shop:
format: "%VENDOR%"
requirements:
- NORMAL_SHOP
admin-shop:
format: "&cAdmin Shop"
requirements:
- ADMIN_SHOP
1:
options:
default:
format: "%AMOUNT% x %ITEMNAME%"
requirements:
2:
options:
buy-and-sell:
format: "Buy %BUY-PRICE% | %SELL-PRICE% Sell"
requirements:
- BUY_PRICE > 0
- SELL_PRICE > 0
only-buy:
format: "Buy %BUY-PRICE%"
requirements:
- BUY_PRICE > 0
only-sell:
format: "Sell %SELL-PRICE%"
requirements:
- SELL_PRICE > 0

View File

@ -1,971 +0,0 @@
Item names for Bukkit 1.14
(Source: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html)
ACACIA_BOAT
ACACIA_BUTTON
ACACIA_DOOR
ACACIA_FENCE
ACACIA_FENCE_GATE
ACACIA_LEAVES
ACACIA_LOG
ACACIA_PLANKS
ACACIA_PRESSURE_PLATE
ACACIA_SAPLING
ACACIA_SIGN
ACACIA_SLAB
ACACIA_STAIRS
ACACIA_TRAPDOOR
ACACIA_WALL_SIGN
ACACIA_WOOD
ACTIVATOR_RAIL
AIR
ALLIUM
ANDESITE
ANDESITE_SLAB
ANDESITE_STAIRS
ANDESITE_WALL
ANVIL
APPLE
ARMOR_STAND
ARROW
ATTACHED_MELON_STEM
ATTACHED_PUMPKIN_STEM
AZURE_BLUET
BAKED_POTATO
BAMBOO
BAMBOO_SAPLING
BARREL
BARRIER
BAT_SPAWN_EGG
BEACON
BEDROCK
BEEF
BEETROOT
BEETROOT_SEEDS
BEETROOT_SOUP
BEETROOTS
BELL
BIRCH_BOAT
BIRCH_BUTTON
BIRCH_DOOR
BIRCH_FENCE
BIRCH_FENCE_GATE
BIRCH_LEAVES
BIRCH_LOG
BIRCH_PLANKS
BIRCH_PRESSURE_PLATE
BIRCH_SAPLING
BIRCH_SIGN
BIRCH_SLAB
BIRCH_STAIRS
BIRCH_TRAPDOOR
BIRCH_WALL_SIGN
BIRCH_WOOD
BLACK_BANNER
BLACK_BED
BLACK_CARPET
BLACK_CONCRETE
BLACK_CONCRETE_POWDER
BLACK_DYE
BLACK_GLAZED_TERRACOTTA
BLACK_SHULKER_BOX
BLACK_STAINED_GLASS
BLACK_STAINED_GLASS_PANE
BLACK_TERRACOTTA
BLACK_WALL_BANNER
BLACK_WOOL
BLAST_FURNACE
BLAZE_POWDER
BLAZE_ROD
BLAZE_SPAWN_EGG
BLUE_BANNER
BLUE_BED
BLUE_CARPET
BLUE_CONCRETE
BLUE_CONCRETE_POWDER
BLUE_DYE
BLUE_GLAZED_TERRACOTTA
BLUE_ICE
BLUE_ORCHID
BLUE_SHULKER_BOX
BLUE_STAINED_GLASS
BLUE_STAINED_GLASS_PANE
BLUE_TERRACOTTA
BLUE_WALL_BANNER
BLUE_WOOL
BONE
BONE_BLOCK
BONE_MEAL
BOOK
BOOKSHELF
BOW
BOWL
BRAIN_CORAL
BRAIN_CORAL_BLOCK
BRAIN_CORAL_FAN
BRAIN_CORAL_WALL_FAN
BREAD
BREWING_STAND
BRICK
BRICK_SLAB
BRICK_STAIRS
BRICK_WALL
BRICKS
BROWN_BANNER
BROWN_BED
BROWN_CARPET
BROWN_CONCRETE
BROWN_CONCRETE_POWDER
BROWN_DYE
BROWN_GLAZED_TERRACOTTA
BROWN_MUSHROOM
BROWN_MUSHROOM_BLOCK
BROWN_SHULKER_BOX
BROWN_STAINED_GLASS
BROWN_STAINED_GLASS_PANE
BROWN_TERRACOTTA
BROWN_WALL_BANNER
BROWN_WOOL
BUBBLE_COLUMN
BUBBLE_CORAL
BUBBLE_CORAL_BLOCK
BUBBLE_CORAL_FAN
BUBBLE_CORAL_WALL_FAN
BUCKET
CACTUS
CAKE
CAMPFIRE
CARROT
CARROT_ON_A_STICK
CARROTS
CARTOGRAPHY_TABLE
CARVED_PUMPKIN
CAT_SPAWN_EGG
CAULDRON
CAVE_AIR
CAVE_SPIDER_SPAWN_EGG
CHAIN_COMMAND_BLOCK
CHAINMAIL_BOOTS
CHAINMAIL_CHESTPLATE
CHAINMAIL_HELMET
CHAINMAIL_LEGGINGS
CHARCOAL
CHEST
CHEST_MINECART
CHICKEN
CHICKEN_SPAWN_EGG
CHIPPED_ANVIL
CHISELED_QUARTZ_BLOCK
CHISELED_RED_SANDSTONE
CHISELED_SANDSTONE
CHISELED_STONE_BRICKS
CHORUS_FLOWER
CHORUS_FRUIT
CHORUS_PLANT
CLAY
CLAY_BALL
CLOCK
COAL
COAL_BLOCK
COAL_ORE
COARSE_DIRT
COBBLESTONE
COBBLESTONE_SLAB
COBBLESTONE_STAIRS
COBBLESTONE_WALL
COBWEB
COCOA
COCOA_BEANS
COD
COD_BUCKET
COD_SPAWN_EGG
COMMAND_BLOCK
COMMAND_BLOCK_MINECART
COMPARATOR
COMPASS
COMPOSTER
CONDUIT
COOKED_BEEF
COOKED_CHICKEN
COOKED_COD
COOKED_MUTTON
COOKED_PORKCHOP
COOKED_RABBIT
COOKED_SALMON
COOKIE
CORNFLOWER
COW_SPAWN_EGG
CRACKED_STONE_BRICKS
CRAFTING_TABLE
CREEPER_BANNER_PATTERN
CREEPER_HEAD
CREEPER_SPAWN_EGG
CREEPER_WALL_HEAD
CROSSBOW
CUT_RED_SANDSTONE
CUT_RED_SANDSTONE_SLAB
CUT_SANDSTONE
CUT_SANDSTONE_SLAB
CYAN_BANNER
CYAN_BED
CYAN_CARPET
CYAN_CONCRETE
CYAN_CONCRETE_POWDER
CYAN_DYE
CYAN_GLAZED_TERRACOTTA
CYAN_SHULKER_BOX
CYAN_STAINED_GLASS
CYAN_STAINED_GLASS_PANE
CYAN_TERRACOTTA
CYAN_WALL_BANNER
CYAN_WOOL
DAMAGED_ANVIL
DANDELION
DARK_OAK_BOAT
DARK_OAK_BUTTON
DARK_OAK_DOOR
DARK_OAK_FENCE
DARK_OAK_FENCE_GATE
DARK_OAK_LEAVES
DARK_OAK_LOG
DARK_OAK_PLANKS
DARK_OAK_PRESSURE_PLATE
DARK_OAK_SAPLING
DARK_OAK_SIGN
DARK_OAK_SLAB
DARK_OAK_STAIRS
DARK_OAK_TRAPDOOR
DARK_OAK_WALL_SIGN
DARK_OAK_WOOD
DARK_PRISMARINE
DARK_PRISMARINE_SLAB
DARK_PRISMARINE_STAIRS
DAYLIGHT_DETECTOR
DEAD_BRAIN_CORAL
DEAD_BRAIN_CORAL_BLOCK
DEAD_BRAIN_CORAL_FAN
DEAD_BRAIN_CORAL_WALL_FAN
DEAD_BUBBLE_CORAL
DEAD_BUBBLE_CORAL_BLOCK
DEAD_BUBBLE_CORAL_FAN
DEAD_BUBBLE_CORAL_WALL_FAN
DEAD_BUSH
DEAD_FIRE_CORAL
DEAD_FIRE_CORAL_BLOCK
DEAD_FIRE_CORAL_FAN
DEAD_FIRE_CORAL_WALL_FAN
DEAD_HORN_CORAL
DEAD_HORN_CORAL_BLOCK
DEAD_HORN_CORAL_FAN
DEAD_HORN_CORAL_WALL_FAN
DEAD_TUBE_CORAL
DEAD_TUBE_CORAL_BLOCK
DEAD_TUBE_CORAL_FAN
DEAD_TUBE_CORAL_WALL_FAN
DEBUG_STICK
DETECTOR_RAIL
DIAMOND
DIAMOND_AXE
DIAMOND_BLOCK
DIAMOND_BOOTS
DIAMOND_CHESTPLATE
DIAMOND_HELMET
DIAMOND_HOE
DIAMOND_HORSE_ARMOR
DIAMOND_LEGGINGS
DIAMOND_ORE
DIAMOND_PICKAXE
DIAMOND_SHOVEL
DIAMOND_SWORD
DIORITE
DIORITE_SLAB
DIORITE_STAIRS
DIORITE_WALL
DIRT
DISPENSER
DOLPHIN_SPAWN_EGG
DONKEY_SPAWN_EGG
DRAGON_BREATH
DRAGON_EGG
DRAGON_HEAD
DRAGON_WALL_HEAD
DRIED_KELP
DRIED_KELP_BLOCK
DROPPER
DROWNED_SPAWN_EGG
EGG
ELDER_GUARDIAN_SPAWN_EGG
ELYTRA
EMERALD
EMERALD_BLOCK
EMERALD_ORE
ENCHANTED_BOOK
ENCHANTED_GOLDEN_APPLE
ENCHANTING_TABLE
END_CRYSTAL
END_GATEWAY
END_PORTAL
END_PORTAL_FRAME
END_ROD
END_STONE
END_STONE_BRICK_SLAB
END_STONE_BRICK_STAIRS
END_STONE_BRICK_WALL
END_STONE_BRICKS
ENDER_CHEST
ENDER_EYE
ENDER_PEARL
ENDERMAN_SPAWN_EGG
ENDERMITE_SPAWN_EGG
EVOKER_SPAWN_EGG
EXPERIENCE_BOTTLE
FARMLAND
FEATHER
FERMENTED_SPIDER_EYE
FERN
FILLED_MAP
FIRE
FIRE_CHARGE
FIRE_CORAL
FIRE_CORAL_BLOCK
FIRE_CORAL_FAN
FIRE_CORAL_WALL_FAN
FIREWORK_ROCKET
FIREWORK_STAR
FISHING_ROD
FLETCHING_TABLE
FLINT
FLINT_AND_STEEL
FLOWER_BANNER_PATTERN
FLOWER_POT
FOX_SPAWN_EGG
FROSTED_ICE
FURNACE
FURNACE_MINECART
GHAST_SPAWN_EGG
GHAST_TEAR
GLASS
GLASS_BOTTLE
GLASS_PANE
GLISTERING_MELON_SLICE
GLOBE_BANNER_PATTERN
GLOWSTONE
GLOWSTONE_DUST
GOLD_BLOCK
GOLD_INGOT
GOLD_NUGGET
GOLD_ORE
GOLDEN_APPLE
GOLDEN_AXE
GOLDEN_BOOTS
GOLDEN_CARROT
GOLDEN_CHESTPLATE
GOLDEN_HELMET
GOLDEN_HOE
GOLDEN_HORSE_ARMOR
GOLDEN_LEGGINGS
GOLDEN_PICKAXE
GOLDEN_SHOVEL
GOLDEN_SWORD
GRANITE
GRANITE_SLAB
GRANITE_STAIRS
GRANITE_WALL
GRASS
GRASS_BLOCK
GRASS_PATH
GRAVEL
GRAY_BANNER
GRAY_BED
GRAY_CARPET
GRAY_CONCRETE
GRAY_CONCRETE_POWDER
GRAY_DYE
GRAY_GLAZED_TERRACOTTA
GRAY_SHULKER_BOX
GRAY_STAINED_GLASS
GRAY_STAINED_GLASS_PANE
GRAY_TERRACOTTA
GRAY_WALL_BANNER
GRAY_WOOL
GREEN_BANNER
GREEN_BED
GREEN_CARPET
GREEN_CONCRETE
GREEN_CONCRETE_POWDER
GREEN_DYE
GREEN_GLAZED_TERRACOTTA
GREEN_SHULKER_BOX
GREEN_STAINED_GLASS
GREEN_STAINED_GLASS_PANE
GREEN_TERRACOTTA
GREEN_WALL_BANNER
GREEN_WOOL
GRINDSTONE
GUARDIAN_SPAWN_EGG
GUNPOWDER
HAY_BLOCK
HEART_OF_THE_SEA
HEAVY_WEIGHTED_PRESSURE_PLATE
HOPPER
HOPPER_MINECART
HORN_CORAL
HORN_CORAL_BLOCK
HORN_CORAL_FAN
HORN_CORAL_WALL_FAN
HORSE_SPAWN_EGG
HUSK_SPAWN_EGG
ICE
INFESTED_CHISELED_STONE_BRICKS
INFESTED_COBBLESTONE
INFESTED_CRACKED_STONE_BRICKS
INFESTED_MOSSY_STONE_BRICKS
INFESTED_STONE
INFESTED_STONE_BRICKS
INK_SAC
IRON_AXE
IRON_BARS
IRON_BLOCK
IRON_BOOTS
IRON_CHESTPLATE
IRON_DOOR
IRON_HELMET
IRON_HOE
IRON_HORSE_ARMOR
IRON_INGOT
IRON_LEGGINGS
IRON_NUGGET
IRON_ORE
IRON_PICKAXE
IRON_SHOVEL
IRON_SWORD
IRON_TRAPDOOR
ITEM_FRAME
JACK_O_LANTERN
JIGSAW
JUKEBOX
JUNGLE_BOAT
JUNGLE_BUTTON
JUNGLE_DOOR
JUNGLE_FENCE
JUNGLE_FENCE_GATE
JUNGLE_LEAVES
JUNGLE_LOG
JUNGLE_PLANKS
JUNGLE_PRESSURE_PLATE
JUNGLE_SAPLING
JUNGLE_SIGN
JUNGLE_SLAB
JUNGLE_STAIRS
JUNGLE_TRAPDOOR
JUNGLE_WALL_SIGN
JUNGLE_WOOD
KELP
KELP_PLANT
KNOWLEDGE_BOOK
LADDER
LANTERN
LAPIS_BLOCK
LAPIS_LAZULI
LAPIS_ORE
LARGE_FERN
LAVA
LAVA_BUCKET
LEAD
LEATHER
LEATHER_BOOTS
LEATHER_CHESTPLATE
LEATHER_HELMET
LEATHER_HORSE_ARMOR
LEATHER_LEGGINGS
LECTERN
LEVER
LIGHT_BLUE_BANNER
LIGHT_BLUE_BED
LIGHT_BLUE_CARPET
LIGHT_BLUE_CONCRETE
LIGHT_BLUE_CONCRETE_POWDER
LIGHT_BLUE_DYE
LIGHT_BLUE_GLAZED_TERRACOTTA
LIGHT_BLUE_SHULKER_BOX
LIGHT_BLUE_STAINED_GLASS
LIGHT_BLUE_STAINED_GLASS_PANE
LIGHT_BLUE_TERRACOTTA
LIGHT_BLUE_WALL_BANNER
LIGHT_BLUE_WOOL
LIGHT_GRAY_BANNER
LIGHT_GRAY_BED
LIGHT_GRAY_CARPET
LIGHT_GRAY_CONCRETE
LIGHT_GRAY_CONCRETE_POWDER
LIGHT_GRAY_DYE
LIGHT_GRAY_GLAZED_TERRACOTTA
LIGHT_GRAY_SHULKER_BOX
LIGHT_GRAY_STAINED_GLASS
LIGHT_GRAY_STAINED_GLASS_PANE
LIGHT_GRAY_TERRACOTTA
LIGHT_GRAY_WALL_BANNER
LIGHT_GRAY_WOOL
LIGHT_WEIGHTED_PRESSURE_PLATE
LILAC
LILY_OF_THE_VALLEY
LILY_PAD
LIME_BANNER
LIME_BED
LIME_CARPET
LIME_CONCRETE
LIME_CONCRETE_POWDER
LIME_DYE
LIME_GLAZED_TERRACOTTA
LIME_SHULKER_BOX
LIME_STAINED_GLASS
LIME_STAINED_GLASS_PANE
LIME_TERRACOTTA
LIME_WALL_BANNER
LIME_WOOL
LINGERING_POTION
LLAMA_SPAWN_EGG
LOOM
MAGENTA_BANNER
MAGENTA_BED
MAGENTA_CARPET
MAGENTA_CONCRETE
MAGENTA_CONCRETE_POWDER
MAGENTA_DYE
MAGENTA_GLAZED_TERRACOTTA
MAGENTA_SHULKER_BOX
MAGENTA_STAINED_GLASS
MAGENTA_STAINED_GLASS_PANE
MAGENTA_TERRACOTTA
MAGENTA_WALL_BANNER
MAGENTA_WOOL
MAGMA_BLOCK
MAGMA_CREAM
MAGMA_CUBE_SPAWN_EGG
MAP
MELON
MELON_SEEDS
MELON_SLICE
MELON_STEM
MILK_BUCKET
MINECART
MOJANG_BANNER_PATTERN
MOOSHROOM_SPAWN_EGG
MOSSY_COBBLESTONE
MOSSY_COBBLESTONE_SLAB
MOSSY_COBBLESTONE_STAIRS
MOSSY_COBBLESTONE_WALL
MOSSY_STONE_BRICK_SLAB
MOSSY_STONE_BRICK_STAIRS
MOSSY_STONE_BRICK_WALL
MOSSY_STONE_BRICKS
MOVING_PISTON
MULE_SPAWN_EGG
MUSHROOM_STEM
MUSHROOM_STEW
MUSIC_DISC_11
MUSIC_DISC_13
MUSIC_DISC_BLOCKS
MUSIC_DISC_CAT
MUSIC_DISC_CHIRP
MUSIC_DISC_FAR
MUSIC_DISC_MALL
MUSIC_DISC_MELLOHI
MUSIC_DISC_STAL
MUSIC_DISC_STRAD
MUSIC_DISC_WAIT
MUSIC_DISC_WARD
MUTTON
MYCELIUM
NAME_TAG
NAUTILUS_SHELL
NETHER_BRICK
NETHER_BRICK_FENCE
NETHER_BRICK_SLAB
NETHER_BRICK_STAIRS
NETHER_BRICK_WALL
NETHER_BRICKS
NETHER_PORTAL
NETHER_QUARTZ_ORE
NETHER_STAR
NETHER_WART
NETHER_WART_BLOCK
NETHERRACK
NOTE_BLOCK
OAK_BOAT
OAK_BUTTON
OAK_DOOR
OAK_FENCE
OAK_FENCE_GATE
OAK_LEAVES
OAK_LOG
OAK_PLANKS
OAK_PRESSURE_PLATE
OAK_SAPLING
OAK_SIGN
OAK_SLAB
OAK_STAIRS
OAK_TRAPDOOR
OAK_WALL_SIGN
OAK_WOOD
OBSERVER
OBSIDIAN
OCELOT_SPAWN_EGG
ORANGE_BANNER
ORANGE_BED
ORANGE_CARPET
ORANGE_CONCRETE
ORANGE_CONCRETE_POWDER
ORANGE_DYE
ORANGE_GLAZED_TERRACOTTA
ORANGE_SHULKER_BOX
ORANGE_STAINED_GLASS
ORANGE_STAINED_GLASS_PANE
ORANGE_TERRACOTTA
ORANGE_TULIP
ORANGE_WALL_BANNER
ORANGE_WOOL
OXEYE_DAISY
PACKED_ICE
PAINTING
PANDA_SPAWN_EGG
PAPER
PARROT_SPAWN_EGG
PEONY
PETRIFIED_OAK_SLAB
PHANTOM_MEMBRANE
PHANTOM_SPAWN_EGG
PIG_SPAWN_EGG
PILLAGER_SPAWN_EGG
PINK_BANNER
PINK_BED
PINK_CARPET
PINK_CONCRETE
PINK_CONCRETE_POWDER
PINK_DYE
PINK_GLAZED_TERRACOTTA
PINK_SHULKER_BOX
PINK_STAINED_GLASS
PINK_STAINED_GLASS_PANE
PINK_TERRACOTTA
PINK_TULIP
PINK_WALL_BANNER
PINK_WOOL
PISTON
PISTON_HEAD
PLAYER_HEAD
PLAYER_WALL_HEAD
PODZOL
POISONOUS_POTATO
POLAR_BEAR_SPAWN_EGG
POLISHED_ANDESITE
POLISHED_ANDESITE_SLAB
POLISHED_ANDESITE_STAIRS
POLISHED_DIORITE
POLISHED_DIORITE_SLAB
POLISHED_DIORITE_STAIRS
POLISHED_GRANITE
POLISHED_GRANITE_SLAB
POLISHED_GRANITE_STAIRS
POPPED_CHORUS_FRUIT
POPPY
PORKCHOP
POTATO
POTATOES
POTION
POTTED_ACACIA_SAPLING
POTTED_ALLIUM
POTTED_AZURE_BLUET
POTTED_BAMBOO
POTTED_BIRCH_SAPLING
POTTED_BLUE_ORCHID
POTTED_BROWN_MUSHROOM
POTTED_CACTUS
POTTED_CORNFLOWER
POTTED_DANDELION
POTTED_DARK_OAK_SAPLING
POTTED_DEAD_BUSH
POTTED_FERN
POTTED_JUNGLE_SAPLING
POTTED_LILY_OF_THE_VALLEY
POTTED_OAK_SAPLING
POTTED_ORANGE_TULIP
POTTED_OXEYE_DAISY
POTTED_PINK_TULIP
POTTED_POPPY
POTTED_RED_MUSHROOM
POTTED_RED_TULIP
POTTED_SPRUCE_SAPLING
POTTED_WHITE_TULIP
POTTED_WITHER_ROSE
POWERED_RAIL
PRISMARINE
PRISMARINE_BRICK_SLAB
PRISMARINE_BRICK_STAIRS
PRISMARINE_BRICKS
PRISMARINE_CRYSTALS
PRISMARINE_SHARD
PRISMARINE_SLAB
PRISMARINE_STAIRS
PRISMARINE_WALL
PUFFERFISH
PUFFERFISH_BUCKET
PUFFERFISH_SPAWN_EGG
PUMPKIN
PUMPKIN_PIE
PUMPKIN_SEEDS
PUMPKIN_STEM
PURPLE_BANNER
PURPLE_BED
PURPLE_CARPET
PURPLE_CONCRETE
PURPLE_CONCRETE_POWDER
PURPLE_DYE
PURPLE_GLAZED_TERRACOTTA
PURPLE_SHULKER_BOX
PURPLE_STAINED_GLASS
PURPLE_STAINED_GLASS_PANE
PURPLE_TERRACOTTA
PURPLE_WALL_BANNER
PURPLE_WOOL
PURPUR_BLOCK
PURPUR_PILLAR
PURPUR_SLAB
PURPUR_STAIRS
QUARTZ
QUARTZ_BLOCK
QUARTZ_PILLAR
QUARTZ_SLAB
QUARTZ_STAIRS
RABBIT
RABBIT_FOOT
RABBIT_HIDE
RABBIT_SPAWN_EGG
RABBIT_STEW
RAIL
RAVAGER_SPAWN_EGG
RED_BANNER
RED_BED
RED_CARPET
RED_CONCRETE
RED_CONCRETE_POWDER
RED_DYE
RED_GLAZED_TERRACOTTA
RED_MUSHROOM
RED_MUSHROOM_BLOCK
RED_NETHER_BRICK_SLAB
RED_NETHER_BRICK_STAIRS
RED_NETHER_BRICK_WALL
RED_NETHER_BRICKS
RED_SAND
RED_SANDSTONE
RED_SANDSTONE_SLAB
RED_SANDSTONE_STAIRS
RED_SANDSTONE_WALL
RED_SHULKER_BOX
RED_STAINED_GLASS
RED_STAINED_GLASS_PANE
RED_TERRACOTTA
RED_TULIP
RED_WALL_BANNER
RED_WOOL
REDSTONE
REDSTONE_BLOCK
REDSTONE_LAMP
REDSTONE_ORE
REDSTONE_TORCH
REDSTONE_WALL_TORCH
REDSTONE_WIRE
REPEATER
REPEATING_COMMAND_BLOCK
ROSE_BUSH
ROTTEN_FLESH
SADDLE
SALMON
SALMON_BUCKET
SALMON_SPAWN_EGG
SAND
SANDSTONE
SANDSTONE_SLAB
SANDSTONE_STAIRS
SANDSTONE_WALL
SCAFFOLDING
SCUTE
SEA_LANTERN
SEA_PICKLE
SEAGRASS
SHEARS
SHEEP_SPAWN_EGG
SHIELD
SHULKER_BOX
SHULKER_SHELL
SHULKER_SPAWN_EGG
SILVERFISH_SPAWN_EGG
SKELETON_HORSE_SPAWN_EGG
SKELETON_SKULL
SKELETON_SPAWN_EGG
SKELETON_WALL_SKULL
SKULL_BANNER_PATTERN
SLIME_BALL
SLIME_BLOCK
SLIME_SPAWN_EGG
SMITHING_TABLE
SMOKER
SMOOTH_QUARTZ
SMOOTH_QUARTZ_SLAB
SMOOTH_QUARTZ_STAIRS
SMOOTH_RED_SANDSTONE
SMOOTH_RED_SANDSTONE_SLAB
SMOOTH_RED_SANDSTONE_STAIRS
SMOOTH_SANDSTONE
SMOOTH_SANDSTONE_SLAB
SMOOTH_SANDSTONE_STAIRS
SMOOTH_STONE
SMOOTH_STONE_SLAB
SNOW
SNOW_BLOCK
SNOWBALL
SOUL_SAND
SPAWNER
SPECTRAL_ARROW
SPIDER_EYE
SPIDER_SPAWN_EGG
SPLASH_POTION
SPONGE
SPRUCE_BOAT
SPRUCE_BUTTON
SPRUCE_DOOR
SPRUCE_FENCE
SPRUCE_FENCE_GATE
SPRUCE_LEAVES
SPRUCE_LOG
SPRUCE_PLANKS
SPRUCE_PRESSURE_PLATE
SPRUCE_SAPLING
SPRUCE_SIGN
SPRUCE_SLAB
SPRUCE_STAIRS
SPRUCE_TRAPDOOR
SPRUCE_WALL_SIGN
SPRUCE_WOOD
SQUID_SPAWN_EGG
STICK
STICKY_PISTON
STONE
STONE_AXE
STONE_BRICK_SLAB
STONE_BRICK_STAIRS
STONE_BRICK_WALL
STONE_BRICKS
STONE_BUTTON
STONE_HOE
STONE_PICKAXE
STONE_PRESSURE_PLATE
STONE_SHOVEL
STONE_SLAB
STONE_STAIRS
STONE_SWORD
STONECUTTER
STRAY_SPAWN_EGG
STRING
STRIPPED_ACACIA_LOG
STRIPPED_ACACIA_WOOD
STRIPPED_BIRCH_LOG
STRIPPED_BIRCH_WOOD
STRIPPED_DARK_OAK_LOG
STRIPPED_DARK_OAK_WOOD
STRIPPED_JUNGLE_LOG
STRIPPED_JUNGLE_WOOD
STRIPPED_OAK_LOG
STRIPPED_OAK_WOOD
STRIPPED_SPRUCE_LOG
STRIPPED_SPRUCE_WOOD
STRUCTURE_BLOCK
STRUCTURE_VOID
SUGAR
SUGAR_CANE
SUNFLOWER
SUSPICIOUS_STEW
SWEET_BERRIES
SWEET_BERRY_BUSH
TALL_GRASS
TALL_SEAGRASS
TERRACOTTA
TIPPED_ARROW
TNT
TNT_MINECART
TORCH
TOTEM_OF_UNDYING
TRADER_LLAMA_SPAWN_EGG
TRAPPED_CHEST
TRIDENT
TRIPWIRE
TRIPWIRE_HOOK
TROPICAL_FISH
TROPICAL_FISH_BUCKET
TROPICAL_FISH_SPAWN_EGG
TUBE_CORAL
TUBE_CORAL_BLOCK
TUBE_CORAL_FAN
TUBE_CORAL_WALL_FAN
TURTLE_EGG
TURTLE_HELMET
TURTLE_SPAWN_EGG
VEX_SPAWN_EGG
VILLAGER_SPAWN_EGG
VINDICATOR_SPAWN_EGG
VINE
VOID_AIR
WALL_TORCH
WANDERING_TRADER_SPAWN_EGG
WATER
WATER_BUCKET
WET_SPONGE
WHEAT
WHEAT_SEEDS
WHITE_BANNER
WHITE_BED
WHITE_CARPET
WHITE_CONCRETE
WHITE_CONCRETE_POWDER
WHITE_DYE
WHITE_GLAZED_TERRACOTTA
WHITE_SHULKER_BOX
WHITE_STAINED_GLASS
WHITE_STAINED_GLASS_PANE
WHITE_TERRACOTTA
WHITE_TULIP
WHITE_WALL_BANNER
WHITE_WOOL
WITCH_SPAWN_EGG
WITHER_ROSE
WITHER_SKELETON_SKULL
WITHER_SKELETON_SPAWN_EGG
WITHER_SKELETON_WALL_SKULL
WOLF_SPAWN_EGG
WOODEN_AXE
WOODEN_HOE
WOODEN_PICKAXE
WOODEN_SHOVEL
WOODEN_SWORD
WRITABLE_BOOK
WRITTEN_BOOK
YELLOW_BANNER
YELLOW_BED
YELLOW_CARPET
YELLOW_CONCRETE
YELLOW_CONCRETE_POWDER
YELLOW_DYE
YELLOW_GLAZED_TERRACOTTA
YELLOW_SHULKER_BOX
YELLOW_STAINED_GLASS
YELLOW_STAINED_GLASS_PANE
YELLOW_TERRACOTTA
YELLOW_WALL_BANNER
YELLOW_WOOL
ZOMBIE_HEAD
ZOMBIE_HORSE_SPAWN_EGG
ZOMBIE_PIGMAN_SPAWN_EGG
ZOMBIE_SPAWN_EGG
ZOMBIE_VILLAGER_SPAWN_EGG
ZOMBIE_WALL_HEAD

View File

@ -1,919 +0,0 @@
message.shop-created=&6Dir wurden &c%CREATION-PRICE% &6abgenommen, um diesen Shop zu erstellen.
message.admin-shop-created=&6Dir wurden &c%CREATION-PRICE% &6abgenommen, um diesen Admin Shop zu erstellen.
message.chest-already-shop=&cTruhe ist bereits ein Shop.
message.chest-blocked=&cÜber der Truhe ist kein Platz.
message.double-chest-blocked=&cÜber der Truhe ist kein Platz.
message.shop-removed=&6Shop entfernt.
message.shop-removed-refund=&6Shop entfernt. Dir wurden &c%CREATION-PRICE%&6 erstattet.
message.all-shops-removed=&6Alle (&c%AMOUNT%&6) Shops von &c%VENDOR%&6 wurden entfernt.
message.chest-no-shop=&cTruhe ist kein Shop.
message.shop-create-not-enough-money=&cNicht genug Geld. Du brauchst &6%CREATION-PRICE% &cum einen Shop zu erstellen.
message.shopInfo.vendor=&6Verkäufer: &e%VENDOR%
message.shopInfo.product=&6Produkt: &e%AMOUNT% x %ITEMNAME%
message.shopInfo.stock=&6Auf Lager: &e%STOCK%
message.shopInfo.chest-space=&6Platz in Truhe: &e%CHEST-SPACE%
message.shopInfo.price=&6Preis: Kauf: &e%BUY-PRICE%&6 Verkauf: &e%SELL-PRICE%
message.shopInfo.disabled=&7Deaktiviert
message.shopInfo.is-normal=&6Typ: &eNormal
message.shopInfo.is-admin=&6Typ: &eAdmin
message.buy-and-sell-disabled=&cDu kannst keinen Shop ohne Kauf- und Verkaufspreis erstellen.
message.buy-success=&aDu hast &6%AMOUNT% x %ITEMNAME%&a für &6%BUY-PRICE%&a von &6%VENDOR% &agekauft.
message.buy-success-admin=&aDu hast &6%AMOUNT% x %ITEMNAME%&a für &6%BUY-PRICE% &agekauft.
message.sell-success=&aDu hast &6%AMOUNT% x %ITEMNAME%&a für &6%SELL-PRICE%&a an &6%VENDOR% &averkauft.
message.sell-success-admin=&aDu hast &6%AMOUNT% x %ITEMNAME%&a für &6%SELL-PRICE% &averkauft.
message.someone-bought=&6%PLAYER% &ahat &6%AMOUNT% x %ITEMNAME%&a für &6%BUY-PRICE%&a von deinem Shop gekauft.
message.someone-sold=&6%PLAYER% &ahat &6%AMOUNT% x %ITEMNAME%&a für &6%SELL-PRICE%&a an deinen Shop verkauft.
message.revenue-while-offline=&6Während du offline warst, haben deine Shops einen Umsatz von &c%REVENUE%&6 gemacht.
message.not-enough-inventory-space=&cNicht genug Platz im Inventar.
message.chest-not-enough-inventory-space=&cShop ist voll.
message.not-enough-money=&cNicht genug Geld.
message.not-enough-items=&cNicht genug Items.
message.vendor-not-enough-money=&cVerkäufer hat nicht genug Geld.
message.out-of-stock=&cShop ausverkauft.
message.vendor-out-of-stock=&cDein Shop, der &6%AMOUNT% x %ITEMNAME% &cverkauft, ist ausverkauft.
message.error-occurred=&cEin Fehler ist aufgetreten: %ERROR%
message.amount-and-price-not-number=&cAnzahl und Preise müssen Zahlen sein.
message.amount-is-zero=&cAnzahl muss größer als 0 sein.
message.prices-contain-decimals=&cPreise dürfen keine Dezimalen enthalten.
message.no-item-in-hand=&cKein Item in der Hand.
message.click-chest-to-create-shop=&aKlicke innerhalb von 15 Sekunden auf eine Truhe, um einen Shop zu erstellen.
message.click-chest-to-remove-shop=&aKlicke innerhalb von 15 Sekunden auf einen Shop, um ihn zu entfernen.
message.click-chest-for-info=&aKlicke innerhalb von 15 Sekunden auf einen Shop, um Informationen über ihn zu bekommen.
message.click-chest-to-open-shop=&Klicke innerhalb von 15 Sekunden auf einen Shop, um ihn zu öffnen.
message.click-to-confirm=&aKlicke noch einmal zum Bestätigen.
message.opened-shop=&aDu hast &6%VENDOR%&as Shop geöffnet.
message.cannot-break-shop=&cDu kannst einen Shop nicht zerstören.
message.cannot-sell-broken-item=&cDu kannst kein kaputtes Artikel verkaufen.
message.buy-price-too-low=&cDer Kaufpreis muss höher sein als %MIN-PRICE%.
message.sell-price-too-low=&cDer Verkaufspreis muss höher sein als %MIN-PRICE%.
message.buy-price-too-high=&cDer Kaufpreis muss geringer sein als %MAX-PRICE%.
message.sell-price-too-high=&cDer Verkaufspreis muss geringer sein als %MAX-PRICE%.
message.buying-disabled=&cKaufen ist an diesem Shop nicht möglich.
message.selling-disabled=&cVerkaufen ist an diesem Shop nicht möglich.
message.reloaded-shops=&a%AMOUNT% Shop/s wurden erfolgreich neu geladen.
message.shop-limit-reached=&cDu hast dein Limit von &6%LIMIT% &cShop/s erreicht.
message.occupied-shop-slots=&6Du hast &c%AMOUNT%/%LIMIT% &6Shop Slot/s benutzt.
message.cannot-sell-item=&cDu kannst für diesen Artikel keinen Shop erstellen.
message.use-in-creative=&cDu kannst im Kreativ-Modus keine Shops benutzen.
message.select-item=&aÖffne dein Inventar und lass ein Item fallen, um es auszuwählen.
message.item-selected=&aItem wurde ausgewählt: &6%ITEMNAME%
message.creation-cancelled=&cShoperstellung wurde abgebrochen.
message.update.update-available=&6&lVersion &c&l%VERSION% &6&lvon &c&lShopChest &6&list verfügbar.
message.update.click-to-download=Klicke hier zum Herunterladen
message.update.no-update=&6&lKeine neue Aktualisierung verfügbar.
message.update.checking=&6&lSuche nach Aktualisierungen...
message.update.error=&c&lFehler beim Suchen nach Aktualisierungen.
message.noPermission.create=&cDu hast keine Berechtigung einen Shop zu erstellen.
message.noPermission.create-admin=&cDu hast keine Berechtigung einen Admin-Shop zu erstellen.
message.noPermission.create-protected=&cDu hast keine Berechtigung hier einen Shop zu erstellen.
message.noPermission.open-others=&cDu hast keine Berechtigung diesen Shop zu öffnen.
message.noPermission.buy=&cDu hast keine Berechtigung etwas zu kaufen.
message.noPermission.sell=&cDu hast keine Berechtigung etwas zu verkaufen.
message.noPermission.buy-here=&cDu hast keine Berechtigung hier etwas zu kaufen.
message.noPermission.sell-here=&cDu hast keine Berechtigung hier etwas zu verkaufen.
message.noPermission.remove-others=&cDu hast keine Berechtigung diesen Shop zu entfernen.
message.noPermission.remove-admin=&cDu hast keine Berechtigung einen Admin Shop zu entfernen.
message.noPermission.reload=&cDu hast keine Berechtigung die Shops neu zu laden.
message.noPermission.update=&cDu hast keine Berechtigung nach Aktualisierungen zu suchen.
message.noPermission.config=&cDu hast keine Berechtigung Konfigurationswerte zu verändern.
message.noPermission.extend-others=&cDu hast keine Berechtigung diesen Shop zu erweitern.
message.noPermission.extend-protected=&cDu hast keine Berechtigung diesen Shop nach hier zu erweitern.
message.commandDescription.header=&6==== &c/%COMMAND% &6Hilfe
message.commandDescription.footer=&6==== Ende
message.commandDescription.create=&a/%COMMAND% create <amount> <buy-price> <sell-price> - Erstelle einen Shop.
message.commandDescription.create-admin=&a/%COMMAND% create <amount> <buy-price> <sell-price> [normal|admin] - Erstelle einen Shop.
message.commandDescription.remove=&a/%COMMAND% remove - Entferne einen Shop.
message.commandDescription.info=&a/%COMMAND% info - Rufe Informationen über den Shop ab.
message.commandDescription.removeall=&a/%COMMAND% removeall - Entferne alle Shops eines Spielers.
message.commandDescription.reload=&a/%COMMAND% reload - Lade die Shops neu.
message.commandDescription.update=&a/%COMMAND% update - Suche nach Aktualisierungen.
message.commandDescription.limits=&a/%COMMAND% limits - Betrachte die Shop Limits.
message.commandDescription.open=&a/%COMMAND% open - Öffne einen Shop.
message.commandDescription.config=&a/%COMMAND% config <set|add|remove> <property> <value> - Verändere Konfigurationswerte.
message.config.set=&6Eigenschaft &a%PROPERTY% &6wurde auf &a%VALUE% &6gesetzt.
message.config.added=&6Wert &a%VALUE% &6wurde zu &a%PROPERTY% &6hinzugefügt.
message.config.removed=&6Wert &a%VALUE% &6wurde aus &a%PROPERTY% &6entfernt.
book.generation.0=Original
book.generation.1=Kopie des Originals
book.generation.2=Kopie einer Kopie
book.generation.3=Zerrissen
effect.damageBoost=Stärke
effect.fireResistance=Feuerschutz
effect.harm=Direktschaden
effect.heal=Direktheilung
effect.invisibility=Unsichtbarkeit
effect.jump=Sprungkraft
effect.luck=Glück
effect.moveSlowdown=Langsamkeit
effect.moveSpeed=Schnelligkeit
effect.nightVision=Nachtsicht
effect.poison=Vergiftung
effect.regeneration=Regeneration
effect.waterBreathing=Unterwasseratem
effect.weakness=Schwäche
enchantment.arrowDamage=Stärke
enchantment.arrowFire=Flamme
enchantment.arrowInfinite=Unendlich
enchantment.arrowKnockback=Schlag
enchantment.binding_curse=Fluch der Bindung
enchantment.damage.all=Schärfe
enchantment.damage.arthropods=Nemesis der Gliederfüßer
enchantment.damage.undead=Bann
enchantment.digging=Effizienz
enchantment.durability=Haltbarkeit
enchantment.fire=Verbrennung
enchantment.fishingSpeed=Köder
enchantment.frostWalker=Eisläufer
enchantment.knockback=Rückstoß
enchantment.level.1=I
enchantment.level.10=X
enchantment.level.2=II
enchantment.level.3=III
enchantment.level.4=IV
enchantment.level.5=V
enchantment.level.6=VI
enchantment.level.7=VII
enchantment.level.8=VIII
enchantment.level.9=IX
enchantment.lootBonus=Plünderung
enchantment.lootBonusDigger=Glück
enchantment.lootBonusFishing=Glück des Meeres
enchantment.mending=Reparatur
enchantment.oxygen=Atmung
enchantment.protect.all=Schutz
enchantment.protect.explosion=Explosionsschutz
enchantment.protect.fall=Federfall
enchantment.protect.fire=Feuerschutz
enchantment.protect.projectile=Schusssicher
enchantment.sweeping=Schwungkraft
enchantment.thorns=Dornen
enchantment.untouching=Behutsamkeit
enchantment.vanishing_curse=Fluch des Verschwindens
enchantment.waterWalker=Wasserläufer
enchantment.waterWorker=Wasseraffinität
entity.Bat.name=Fledermaus
entity.Blaze.name=Lohe
entity.CaveSpider.name=Höhlenspinne
entity.Chicken.name=Huhn
entity.Cow.name=Kuh
entity.Creeper.name=Creeper
entity.Donkey.name=Esel
entity.ElderGuardian.name=Großer Wächter
entity.Enderman.name=Enderman
entity.Endermite.name=Endermite
entity.EntityHorse.name=Pferd
entity.EvocationIllager.name=Magier
entity.Ghast.name=Ghast
entity.Guardian.name=Wächter
entity.Horse.name=Pferd
entity.Husk.name=Wüstenzombie
entity.IllusionIllager.name=Illusionist
entity.LavaSlime.name=Magmawürfel
entity.Llama.name=Lama
entity.Mule.name=Maultier
entity.MushroomCow.name=Mooshroom
entity.Ozelot.name=Ozelot
entity.Parrot.name=Papagei
entity.Pig.name=Schwein
entity.PigZombie.name=Schweinezombie
entity.PolarBear.name=Eisbär
entity.Rabbit.name=Kaninchen
entity.Sheep.name=Schaf
entity.Shulker.name=Shulker
entity.Silverfish.name=Silberfischchen
entity.Skeleton.name=Skelett
entity.SkeletonHorse.name=Skelettpferd
entity.Slime.name=Schleim
entity.Spider.name=Spinne
entity.Squid.name=Tintenfisch
entity.Stray.name=Eiswanderer
entity.Vex.name=Plagegeist
entity.Villager.name=Dorfbewohner
entity.VindicationIllager.name=Diener
entity.Witch.name=Hexe
entity.WitherSkeleton.name=Witherskelett
entity.Wolf.name=Wolf
entity.Zombie.name=Zombie
entity.ZombieHorse.name=Zombiepferd
entity.ZombieVillager.name=Dorfbewohnerzombie
item.apple.name=Apfel
item.appleGold.name=Goldener Apfel
item.armorStand.name=Rüstungsständer
item.arrow.name=Pfeil
item.banner.black.name=Schwarzes Banner
item.banner.blue.name=Blaues Banner
item.banner.brown.name=Braunes Banner
item.banner.cyan.name=Türkises Banner
item.banner.gray.name=Graues Banner
item.banner.green.name=Grünes Banner
item.banner.lightBlue.name=Hellblaues Banner
item.banner.lime.name=Hellgrünes Banner
item.banner.magenta.name=Magenta Banner
item.banner.orange.name=Oranges Banner
item.banner.pink.name=Rosa Banner
item.banner.purple.name=Violettes Banner
item.banner.red.name=Rotes Banner
item.banner.silver.name=Hellgraues Banner
item.banner.white.name=Weißes Banner
item.banner.yellow.name=Gelbes Banner
item.bed.black.name=Schwarzes Bett
item.bed.blue.name=Blaues Bett
item.bed.brown.name=Braunes Bett
item.bed.cyan.name=Türkises Bett
item.bed.gray.name=Graues Bett
item.bed.green.name=Grünes Bett
item.bed.lightBlue.name=Hellblaues Bett
item.bed.lime.name=Hellgrünes Bett
item.bed.magenta.name=Magenta Bett
item.bed.name=Bett
item.bed.orange.name=Oranges Bett
item.bed.pink.name=Rosa Bett
item.bed.purple.name=Violettes Bett
item.bed.red.name=Rotes Bett
item.bed.silver.name=Hellgraues Bett
item.bed.white.name=Weißes Bett
item.bed.yellow.name=Gelbes Bett
item.beefCooked.name=Steak
item.beefRaw.name=Rohes Rindfleisch
item.beetroot.name=Rote Bete
item.beetroot_seeds.name=Rote-Bete-Samen
item.beetroot_soup.name=Borschtsch
item.blazePowder.name=Lohenstaub
item.blazeRod.name=Lohenrute
item.boat.acacia.name=Akazienholzboot
item.boat.birch.name=Birkenholzboot
item.boat.dark_oak.name=Schwarzeichenholzboot
item.boat.jungle.name=Tropenholzboot
item.boat.oak.name=Eichenholzboot
item.boat.spruce.name=Fichtenholzboot
item.bone.name=Knochen
item.book.name=Buch
item.bootsChain.name=Kettenstiefel
item.bootsCloth.name=Lederstiefel
item.bootsDiamond.name=Diamantstiefel
item.bootsGold.name=Goldstiefel
item.bootsIron.name=Eisenstiefel
item.bow.name=Bogen
item.bowl.name=Schüssel
item.bread.name=Brot
item.brewingStand.name=Braustand
item.brick.name=Ziegel
item.bucket.name=Eimer
item.bucketLava.name=Lavaeimer
item.bucketWater.name=Wassereimer
item.cake.name=Kuchen
item.carrotGolden.name=Goldene Karotte
item.carrotOnAStick.name=Karottenrute
item.carrots.name=Karotte
item.cauldron.name=Kessel
item.charcoal.name=Holzkohle
item.chestplateChain.name=Kettenhemd
item.chestplateCloth.name=Lederjacke
item.chestplateDiamond.name=Diamantharnisch
item.chestplateGold.name=Goldharnisch
item.chestplateIron.name=Eisenharnisch
item.chickenCooked.name=Gebratenes Hühnchen
item.chickenRaw.name=Rohes Hühnchen
item.chorusFruit.name=Chorusfrucht
item.chorusFruitPopped.name=Geplatzte Chorusfrucht
item.clay.name=Tonklumpen
item.clock.name=Uhr
item.coal.name=Kohle
item.comparator.name=Redstone-Komparator
item.compass.name=Kompass
item.cookie.name=Keks
item.diamond.name=Diamant
item.diode.name=Redstone-Verstärker
item.doorAcacia.name=Akazienholztür
item.doorBirch.name=Birkenholztür
item.doorDarkOak.name=Schwarzeichenholztür
item.doorIron.name=Eisentür
item.doorJungle.name=Tropenholztür
item.doorOak.name=Eichenholztür
item.doorSpruce.name=Fichtenholztür
item.dragon_breath.name=Drachenatem
item.dyePowder.black.name=Tintenbeutel
item.dyePowder.blue.name=Lapislazuli
item.dyePowder.brown.name=Kakaobohnen
item.dyePowder.cyan.name=Türkiser Farbstoff
item.dyePowder.gray.name=Grauer Farbstoff
item.dyePowder.green.name=Kaktusgrün
item.dyePowder.lightBlue.name=Hellblauer Farbstoff
item.dyePowder.lime.name=Hellgrüner Farbstoff
item.dyePowder.magenta.name=Magenta Farbstoff
item.dyePowder.orange.name=Oranger Farbstoff
item.dyePowder.pink.name=Rosa Farbstoff
item.dyePowder.purple.name=Violetter Farbstoff
item.dyePowder.red.name=Roter Farbstoff
item.dyePowder.silver.name=Hellgrauer Farbstoff
item.dyePowder.white.name=Knochenmehl
item.dyePowder.yellow.name=Gelber Farbstoff
item.egg.name=Ei
item.elytra.name=Elytren
item.emerald.name=Smaragd
item.emptyMap.name=Leere Karte
item.enchantedBook.name=Verzaubertes Buch
item.end_crystal.name=Enderkristall
item.enderPearl.name=Enderperle
item.expBottle.name=Erfahrungsfläschchen
item.eyeOfEnder.name=Enderauge
item.feather.name=Feder
item.fermentedSpiderEye.name=Fermentiertes Spinnenauge
item.fireball.name=Feuerkugel
item.fireworks.name=Feuerwerksrakete
item.fireworksCharge.name=Feuerwerksstern
item.fish.clownfish.raw.name=Clownfisch
item.fish.cod.cooked.name=Gebratener Kabeljau
item.fish.cod.raw.name=Roher Kabeljau
item.fish.pufferfish.raw.name=Kugelfisch
item.fish.salmon.cooked.name=Gebratener Lachs
item.fish.salmon.raw.name=Roher Lachs
item.fishingRod.name=Angel
item.flint.name=Feuerstein
item.flintAndSteel.name=Feuerzeug
item.flowerPot.name=Blumentopf
item.frame.name=Rahmen
item.ghastTear.name=Ghastträne
item.glassBottle.name=Glasflasche
item.goldNugget.name=Goldklumpen
item.hatchetDiamond.name=Diamantaxt
item.hatchetGold.name=Goldaxt
item.hatchetIron.name=Eisenaxt
item.hatchetStone.name=Steinaxt
item.hatchetWood.name=Holzaxt
item.helmetChain.name=Kettenhaube
item.helmetCloth.name=Lederkappe
item.helmetDiamond.name=Diamanthelm
item.helmetGold.name=Goldhelm
item.helmetIron.name=Eisenhelm
item.hoeDiamond.name=Diamanthacke
item.hoeGold.name=Goldhacke
item.hoeIron.name=Eisenhacke
item.hoeStone.name=Steinhacke
item.hoeWood.name=Holzhacke
item.horsearmordiamond.name=Diamantene Pferderüstung
item.horsearmorgold.name=Goldene Pferderüstung
item.horsearmormetal.name=Eiserne Pferderüstung
item.ingotGold.name=Goldbarren
item.ingotIron.name=Eisenbarren
item.ironNugget.name=Eisenklumpen
item.knowledgeBook.name=Buch des Wissens
item.leash.name=Leine
item.leather.name=Leder
item.leggingsChain.name=Kettenhose
item.leggingsCloth.name=Lederhose
item.leggingsDiamond.name=Diamantbeinschutz
item.leggingsGold.name=Goldbeinschutz
item.leggingsIron.name=Eisenbeinschutz
item.magmaCream.name=Magmacreme
item.map.name=Karte
item.melon.name=Melonenscheibe
item.milk.name=Milch
item.minecart.name=Lore
item.minecartChest.name=Güterlore
item.minecartCommandBlock.name=Befehlsblocklore
item.minecartFurnace.name=Antriebslore
item.minecartHopper.name=Trichterlore
item.minecartTnt.name=TNT-Lore
item.monsterPlacer.name=Erschaffe
item.mushroomStew.name=Pilzsuppe
item.muttonCooked.name=Gebratenes Hammelfleisch
item.muttonRaw.name=Rohes Hammelfleisch
item.nameTag.name=Namensschild
item.netherStalkSeeds.name=Netherwarze
item.netherStar.name=Netherstern
item.netherbrick.name=Netherziegel
item.netherquartz.name=Netherquarz
item.painting.name=Gemälde
item.paper.name=Papier
item.pickaxeDiamond.name=Diamantspitzhacke
item.pickaxeGold.name=Goldspitzhacke
item.pickaxeIron.name=Eisenspitzhacke
item.pickaxeStone.name=Steinspitzhacke
item.pickaxeWood.name=Holzspitzhacke
item.porkchopCooked.name=Gebratenes Schweinefleisch
item.porkchopRaw.name=Rohes Schweinefleisch
item.potato.name=Kartoffel
item.potatoBaked.name=Ofenkartoffel
item.potatoPoisonous.name=Giftige Kartoffel
item.potion.name=Trank
item.prismarineCrystals.name=Prismarinkristalle
item.prismarineShard.name=Prismarinscherbe
item.pumpkinPie.name=Kürbiskuchen
item.rabbitCooked.name=Gebratenes Kaninchen
item.rabbitFoot.name=Hasenpfote
item.rabbitHide.name=Kaninchenfell
item.rabbitRaw.name=Rohes Kaninchen
item.rabbitStew.name=Kaninchenragout
item.record.11.desc=C418 - 11
item.record.13.desc=C418 - 13
item.record.blocks.desc=C418 - Blocks
item.record.cat.desc=C418 - Cat
item.record.chirp.desc=C418 - Chirp
item.record.far.desc=C418 - Far
item.record.mall.desc=C418 - Mall
item.record.mellohi.desc=C418 - Mellohi
item.record.name=Schallplatte
item.record.stal.desc=C418 - Stal
item.record.strad.desc=C418 - Strad
item.record.wait.desc=C418 - Wait
item.record.ward.desc=C418 - Ward
item.redstone.name=Redstone
item.reeds.name=Zuckerrohr
item.rottenFlesh.name=Verrottetes Fleisch
item.saddle.name=Sattel
item.seeds.name=Weizenkörner
item.seeds_melon.name=Melonenkerne
item.seeds_pumpkin.name=Kürbiskerne
item.shears.name=Schere
item.shield.name=Schild
item.shovelDiamond.name=Diamantschaufel
item.shovelGold.name=Goldschaufel
item.shovelIron.name=Eisenschaufel
item.shovelStone.name=Steinschaufel
item.shovelWood.name=Holzschaufel
item.shulkerShell.name=Shulkerschale
item.sign.name=Schild
item.skull.char.name=Kopf
item.skull.creeper.name=Creeperkopf
item.skull.dragon.name=Drachenkopf
item.skull.skeleton.name=Skelettschädel
item.skull.wither.name=Witherskelettschädel
item.skull.zombie.name=Zombiekopf
item.slimeball.name=Schleimball
item.snowball.name=Schneeball
item.speckledMelon.name=Glitzernde Melonenscheibe
item.spectral_arrow.name=Spektralpfeil
item.spiderEye.name=Spinnenauge
item.stick.name=Stock
item.string.name=Faden
item.sugar.name=Zucker
item.sulphur.name=Schwarzpulver
item.swordDiamond.name=Diamantschwert
item.swordGold.name=Goldschwert
item.swordIron.name=Eisenschwert
item.swordStone.name=Steinschwert
item.swordWood.name=Holzschwert
item.tipped_arrow.name=Getränkter Pfeil
item.totem.name=Totem der Unsterblichkeit
item.wheat.name=Weizen
item.writingBook.name=Buch und Feder
item.writtenBook.name=Beschriebenes Buch
item.yellowDust.name=Glowstonestaub
lingering_potion.effect.awkward=Seltsamer Verweiltrank
lingering_potion.effect.empty=Nicht braubarer Verweiltrank
lingering_potion.effect.fire_resistance=Verweiltrank der Feuerresistenz
lingering_potion.effect.harming=Verweiltrank des Schadens
lingering_potion.effect.healing=Verweiltrank der Heilung
lingering_potion.effect.invisibility=Verweiltrank der Unsichtbarkeit
lingering_potion.effect.leaping=Verweiltrank der Sprungkraft
lingering_potion.effect.luck=Verweiltrank des Glücks
lingering_potion.effect.mundane=Gewöhnlicher Verweiltrank
lingering_potion.effect.night_vision=Verweiltrank der Nachtsicht
lingering_potion.effect.poison=Verweiltrank der Vergiftung
lingering_potion.effect.regeneration=Verweiltrank der Regeneration
lingering_potion.effect.slowness=Verweiltrank der Langsamkeit
lingering_potion.effect.strength=Verweiltrank der Stärke
lingering_potion.effect.swiftness=Verweiltrank der Schnelligkeit
lingering_potion.effect.thick=Dickflüssiger Verweiltrank
lingering_potion.effect.water=Verweilende Wasserflasche
lingering_potion.effect.water_breathing=Verweiltrank der Unterwasseratmung
lingering_potion.effect.weakness=Verweiltrank der Schwäche
potion.effect.awkward=Seltsamer Trank
potion.effect.empty=Nicht braubarer Trank
potion.effect.fire_resistance=Trank der Feuerresistenz
potion.effect.harming=Trank des Schadens
potion.effect.healing=Trank der Heilung
potion.effect.invisibility=Trank der Unsichtbarkeit
potion.effect.leaping=Trank der Sprungkraft
potion.effect.luck=Trank des Glücks
potion.effect.mundane=Gewöhnlicher Trank
potion.effect.night_vision=Trank der Nachtsicht
potion.effect.poison=Trank der Vergiftung
potion.effect.regeneration=Trank der Regeneration
potion.effect.slowness=Trank der Langsamkeit
potion.effect.strength=Trank der Stärke
potion.effect.swiftness=Trank der Schnelligkeit
potion.effect.thick=Dickflüssiger Trank
potion.effect.water=Wasserflasche
potion.effect.water_breathing=Trank der Unterwasseratmung
potion.effect.weakness=Trank der Schwäche
splash_potion.effect.awkward=Seltsamer Wurftrank
splash_potion.effect.empty=Nicht braubarer Wurftrank
splash_potion.effect.fire_resistance=Wurftrank der Feuerresistenz
splash_potion.effect.harming=Wurftrank des Schadens
splash_potion.effect.healing=Wurftrank der Heilung
splash_potion.effect.invisibility=Wurftrank der Unsichtbarkeit
splash_potion.effect.leaping=Wurftrank der Sprungkraft
splash_potion.effect.luck=Wurftrank des Glücks
splash_potion.effect.mundane=Gewöhnlicher Wurftrank
splash_potion.effect.night_vision=Wurftrank der Nachtsicht
splash_potion.effect.poison=Wurftrank der Vergiftung
splash_potion.effect.regeneration=Wurftrank der Regeneration
splash_potion.effect.slowness=Wurftrank der Langsamkeit
splash_potion.effect.strength=Wurftrank der Stärke
splash_potion.effect.swiftness=Wurftrank der Schnelligkeit
splash_potion.effect.thick=Dickflüssiger Wurftrank
splash_potion.effect.water=Werfbare Wasserflasche
splash_potion.effect.water_breathing=Wurftrank der Unterwasseratmung
splash_potion.effect.weakness=Wurftrank der Schwäche
tile.acaciaFence.name=Akazienholzzaun
tile.acaciaFenceGate.name=Akazienholzzauntor
tile.activatorRail.name=Aktivierungsschiene
tile.anvil.intact.name=Amboss
tile.anvil.slightlyDamaged.name=Leicht beschädigter Amboss
tile.anvil.veryDamaged.name=Stark beschädigter Amboss
tile.barrier.name=Barriere
tile.beacon.name=Leuchtfeuer
tile.bedrock.name=Grundgestein
tile.birchFence.name=Birkenholzzaun
tile.birchFenceGate.name=Birkenholzzauntor
tile.blockCoal.name=Kohleblock
tile.blockDiamond.name=Diamantblock
tile.blockEmerald.name=Smaragdblock
tile.blockGold.name=Goldblock
tile.blockIron.name=Eisenblock
tile.blockLapis.name=Lapislazuliblock
tile.blockRedstone.name=Redstone-Block
tile.boneBlock.name=Knochenblock
tile.bookshelf.name=Bücherregal
tile.brick.name=Ziegelsteine
tile.button.name=Knopf
tile.cactus.name=Kaktus
tile.chainCommandBlock.name=Ketten-Befehlsblock
tile.chest.name=Truhe
tile.chestTrap.name=Redstone-Truhe
tile.chorusFlower.name=Chorusblüte
tile.chorusPlant.name=Choruspflanze
tile.clay.name=Ton
tile.clayHardened.name=Keramik
tile.clayHardenedStained.black.name=Schwarze Keramik
tile.clayHardenedStained.blue.name=Blaue Keramik
tile.clayHardenedStained.brown.name=Braune Keramik
tile.clayHardenedStained.cyan.name=Türkise Keramik
tile.clayHardenedStained.gray.name=Graue Keramik
tile.clayHardenedStained.green.name=Grüne Keramik
tile.clayHardenedStained.lightBlue.name=Hellblaue Keramik
tile.clayHardenedStained.lime.name=Hellgrüne Keramik
tile.clayHardenedStained.magenta.name=Magenta Keramik
tile.clayHardenedStained.orange.name=Orange Keramik
tile.clayHardenedStained.pink.name=Rosa Keramik
tile.clayHardenedStained.purple.name=Violette Keramik
tile.clayHardenedStained.red.name=Rote Keramik
tile.clayHardenedStained.silver.name=Hellgraue Keramik
tile.clayHardenedStained.white.name=Weiße Keramik
tile.clayHardenedStained.yellow.name=Gelbe Keramik
tile.cloth.black.name=Schwarze Wolle
tile.cloth.blue.name=Blaue Wolle
tile.cloth.brown.name=Braune Wolle
tile.cloth.cyan.name=Türkise Wolle
tile.cloth.gray.name=Graue Wolle
tile.cloth.green.name=Grüne Wolle
tile.cloth.lightBlue.name=Hellblaue Wolle
tile.cloth.lime.name=Hellgrüne Wolle
tile.cloth.magenta.name=Magenta Wolle
tile.cloth.orange.name=Orange Wolle
tile.cloth.pink.name=Rosa Wolle
tile.cloth.purple.name=Violette Wolle
tile.cloth.red.name=Rote Wolle
tile.cloth.silver.name=Hellgraue Wolle
tile.cloth.white.name=Weiße Wolle
tile.cloth.yellow.name=Gelbe Wolle
tile.cobbleWall.mossy.name=Bemooste Bruchsteinmauer
tile.cobbleWall.normal.name=Bruchsteinmauer
tile.commandBlock.name=Befehlsblock
tile.concrete.black.name=Schwarzer Beton
tile.concrete.blue.name=Blauer Beton
tile.concrete.brown.name=Brauner Beton
tile.concrete.cyan.name=Türkiser Beton
tile.concrete.gray.name=Grauer Beton
tile.concrete.green.name=Grüner Beton
tile.concrete.lightBlue.name=Hellblauer Beton
tile.concrete.lime.name=Hellgrüner Beton
tile.concrete.magenta.name=Magenta Beton
tile.concrete.orange.name=Oranger Beton
tile.concrete.pink.name=Rosa Beton
tile.concrete.purple.name=Violetter Beton
tile.concrete.red.name=Roter Beton
tile.concrete.silver.name=Hellgrauer Beton
tile.concrete.white.name=Weißer Beton
tile.concrete.yellow.name=Gelber Beton
tile.concretePowder.black.name=Schwarzer Trockenbeton
tile.concretePowder.blue.name=Blauer Trockenbeton
tile.concretePowder.brown.name=Brauner Trockenbeton
tile.concretePowder.cyan.name=Türkiser Trockenbeton
tile.concretePowder.gray.name=Grauer Trockenbeton
tile.concretePowder.green.name=Grüner Trockenbeton
tile.concretePowder.lightBlue.name=Hellblauer Trockenbeton
tile.concretePowder.lime.name=Hellgrüner Trockenbeton
tile.concretePowder.magenta.name=Magenta Trockenbeton
tile.concretePowder.orange.name=Oranger Trockenbeton
tile.concretePowder.pink.name=Rosa Trockenbeton
tile.concretePowder.purple.name=Violetter Trockenbeton
tile.concretePowder.red.name=Roter Trockenbeton
tile.concretePowder.silver.name=Hellgrauer Trockenbeton
tile.concretePowder.white.name=Weißer Trockenbeton
tile.concretePowder.yellow.name=Gelber Trockenbeton
tile.darkOakFence.name=Schwarzeichenholzzaun
tile.darkOakFenceGate.name=Schwarzeichenholzzauntor
tile.daylightDetector.name=Tageslichtsensor
tile.deadbush.name=Toter Busch
tile.detectorRail.name=Sensorschiene
tile.dirt.coarse.name=Grobe Erde
tile.dirt.default.name=Erde
tile.dirt.podzol.name=Podsol
tile.dispenser.name=Werfer
tile.doublePlant.fern.name=Großer Farn
tile.doublePlant.grass.name=Hohes Gras
tile.doublePlant.paeonia.name=Pfingstrose
tile.doublePlant.rose.name=Rosenstrauch
tile.doublePlant.sunflower.name=Sonnenblume
tile.doublePlant.syringa.name=Flieder
tile.dragonEgg.name=Drachenei
tile.dropper.name=Spender
tile.enchantmentTable.name=Zaubertisch
tile.endBricks.name=Endsteinziegel
tile.endPortalFrame.name=Endportalrahmen
tile.endRod.name=Endstab
tile.enderChest.name=Endertruhe
tile.farmland.name=Ackerboden
tile.fence.name=Eichenholzzaun
tile.fenceGate.name=Eichenholzzauntor
tile.fenceIron.name=Eisengitter
tile.fire.name=Feuer
tile.flower1.dandelion.name=Löwenzahn
tile.flower2.allium.name=Sternlauch
tile.flower2.blueOrchid.name=Blaue Orchidee
tile.flower2.houstonia.name=Porzellansternchen
tile.flower2.oxeyeDaisy.name=Margerite
tile.flower2.poppy.name=Mohn
tile.flower2.tulipOrange.name=Orange Tulpe
tile.flower2.tulipPink.name=Rosa Tulpe
tile.flower2.tulipRed.name=Rote Tulpe
tile.flower2.tulipWhite.name=Weiße Tulpe
tile.furnace.name=Ofen
tile.glass.name=Glas
tile.glazedTerracottaBlack.name=Schwarze glasierte Keramik
tile.glazedTerracottaBlue.name=Blaue glasierte Keramik
tile.glazedTerracottaBrown.name=Braune glasierte Keramik
tile.glazedTerracottaCyan.name=Türkise glasierte Keramik
tile.glazedTerracottaGray.name=Graue glasierte Keramik
tile.glazedTerracottaGreen.name=Grüne glasierte Keramik
tile.glazedTerracottaLightBlue.name=Hellblaue glasierte Keramik
tile.glazedTerracottaLime.name=Hellgrüne glasierte Keramik
tile.glazedTerracottaMagenta.name=Magenta glasierte Keramik
tile.glazedTerracottaOrange.name=Orange glasierte Keramik
tile.glazedTerracottaPink.name=Rosa glasierte Keramik
tile.glazedTerracottaPurple.name=Violette glasierte Keramik
tile.glazedTerracottaRed.name=Rote glasierte Keramik
tile.glazedTerracottaSilver.name=Hellgraue glasierte Keramik
tile.glazedTerracottaWhite.name=Weiße glasierte Keramik
tile.glazedTerracottaYellow.name=Gelbe glasierte Keramik
tile.goldenRail.name=Antriebsschiene
tile.grass.name=Grasblock
tile.grassPath.name=Trampelpfad
tile.gravel.name=Kies
tile.hayBlock.name=Strohballen
tile.hellrock.name=Netherrack
tile.hellsand.name=Seelensand
tile.hopper.name=Trichter
tile.ice.name=Eis
tile.icePacked.name=Packeis
tile.ironTrapdoor.name=Eisenfalltür
tile.jukebox.name=Plattenspieler
tile.jungleFence.name=Tropenholzzaun
tile.jungleFenceGate.name=Tropenholzzauntor
tile.ladder.name=Leiter
tile.lava.name=Lava
tile.leaves.acacia.name=Akazienlaub
tile.leaves.big_oak.name=Schwarzeichenlaub
tile.leaves.birch.name=Birkenlaub
tile.leaves.jungle.name=Tropenbaumlaub
tile.leaves.oak.name=Eichenlaub
tile.leaves.spruce.name=Fichtennadeln
tile.lever.name=Hebel
tile.lightgem.name=Glowstone
tile.litpumpkin.name=Kürbislaterne
tile.log.acacia.name=Akazienholz
tile.log.big_oak.name=Schwarzeichenholz
tile.log.birch.name=Birkenholz
tile.log.jungle.name=Tropenholz
tile.log.oak.name=Eichenholz
tile.log.spruce.name=Fichtenholz
tile.magma.name=Magmablock
tile.melon.name=Melone
tile.mobSpawner.name=Monsterspawner
tile.monsterStoneEgg.brick.name=Steinziegel (Silberfischchen)
tile.monsterStoneEgg.chiseledbrick.name=Gemeißelte Steinziegel (Silberfischchen)
tile.monsterStoneEgg.cobble.name=Bruchstein (Silberfischchen)
tile.monsterStoneEgg.crackedbrick.name=Rissige Steinziegel (Silberfischchen)
tile.monsterStoneEgg.mossybrick.name=Bemooste Steinziegel (Silberfischchen)
tile.monsterStoneEgg.stone.name=Stein (Silberfischchen)
tile.mushroom.name=Pilz
tile.musicBlock.name=Notenblock
tile.mycel.name=Myzel
tile.netherBrick.name=Netherziegel
tile.netherFence.name=Netherziegelzaun
tile.netherStalk.name=Netherwarze
tile.netherWartBlock.name=Netherwarzenblock
tile.netherquartz.name=Netherquarzerz
tile.notGate.name=Redstone-Fackel
tile.observer.name=Beobachter
tile.obsidian.name=Obsidian
tile.oreCoal.name=Steinkohle
tile.oreDiamond.name=Diamanterz
tile.oreEmerald.name=Smaragderz
tile.oreGold.name=Golderz
tile.oreIron.name=Eisenerz
tile.oreLapis.name=Lapislazulierz
tile.oreRedstone.name=Redstone-Erz
tile.pistonBase.name=Kolben
tile.pistonStickyBase.name=Klebriger Kolben
tile.portal.name=Portal
tile.pressurePlateStone.name=Steindruckplatte
tile.pressurePlateWood.name=Holzdruckplatte
tile.prismarine.bricks.name=Prismarinziegel
tile.prismarine.dark.name=Dunkler Prismarin
tile.prismarine.rough.name=Prismarin
tile.pumpkin.name=Kürbis
tile.purpurBlock.name=Purpurblock
tile.purpurPillar.name=Purpursäule
tile.purpurSlab.name=Purpurstufe
tile.quartzBlock.chiseled.name=Gemeißelter Quarzblock
tile.quartzBlock.default.name=Quarzblock
tile.quartzBlock.lines.name=Quarzsäule
tile.rail.name=Schiene
tile.redNetherBrick.name=Rote Netherziegel
tile.redSandStone.chiseled.name=Gemeißelter roter Sandstein
tile.redSandStone.default.name=Roter Sandstein
tile.redSandStone.smooth.name=Glatter roter Sandstein
tile.redstoneLight.name=Redstone-Lampe
tile.repeatingCommandBlock.name=Wiederhol-Befehlsblock
tile.sand.default.name=Sand
tile.sand.red.name=Roter Sand
tile.sandStone.chiseled.name=Gemeißelter Sandstein
tile.sandStone.default.name=Sandstein
tile.sandStone.smooth.name=Glatter Sandstein
tile.sapling.acacia.name=Akaziensetzling
tile.sapling.big_oak.name=Schwarzeichensetzling
tile.sapling.birch.name=Birkensetzling
tile.sapling.jungle.name=Tropenbaumsetzling
tile.sapling.oak.name=Eichensetzling
tile.sapling.spruce.name=Fichtensetzling
tile.seaLantern.name=Seelaterne
tile.shulkerBoxBlack.name=Schwarze Shulkerkiste
tile.shulkerBoxBlue.name=Blaue Shulkerkiste
tile.shulkerBoxBrown.name=Braune Shulkerkiste
tile.shulkerBoxCyan.name=Türkise Shulkerkiste
tile.shulkerBoxGray.name=Graue Shulkerkiste
tile.shulkerBoxGreen.name=Grüne Shulkerkiste
tile.shulkerBoxLightBlue.name=Hellblaue Shulkerkiste
tile.shulkerBoxLime.name=Hellgrüne Shulkerkiste
tile.shulkerBoxMagenta.name=Magenta Shulkerkiste
tile.shulkerBoxOrange.name=Orange Shulkerkiste
tile.shulkerBoxPink.name=Rosa Shulkerkiste
tile.shulkerBoxPurple.name=Violette Shulkerkiste
tile.shulkerBoxRed.name=Rote Shulkerkiste
tile.shulkerBoxSilver.name=Hellgraue Shulkerkiste
tile.shulkerBoxWhite.name=Weiße Shulkerkiste
tile.shulkerBoxYellow.name=Gelbe Shulkerkiste
tile.slime.name=Schleimblock
tile.snow.name=Schnee
tile.sponge.dry.name=Schwamm
tile.sponge.wet.name=Nasser Schwamm
tile.spruceFence.name=Fichtenholzzaun
tile.spruceFenceGate.name=Fichtenholzzauntor
tile.stainedGlass.black.name=Schwarzes Glas
tile.stainedGlass.blue.name=Blaues Glas
tile.stainedGlass.brown.name=Braunes Glas
tile.stainedGlass.cyan.name=Türkises Glas
tile.stainedGlass.gray.name=Graues Glas
tile.stainedGlass.green.name=Grünes Glas
tile.stainedGlass.lightBlue.name=Hellblaues Glas
tile.stainedGlass.lime.name=Hellgrünes Glas
tile.stainedGlass.magenta.name=Magenta Glas
tile.stainedGlass.orange.name=Oranges Glas
tile.stainedGlass.pink.name=Rosa Glas
tile.stainedGlass.purple.name=Violettes Glas
tile.stainedGlass.red.name=Rotes Glas
tile.stainedGlass.silver.name=Hellgraues Glas
tile.stainedGlass.white.name=Weißes Glas
tile.stainedGlass.yellow.name=Gelbes Glas
tile.stairsBrick.name=Ziegeltreppe
tile.stairsNetherBrick.name=Netherziegeltreppe
tile.stairsPurpur.name=Purpurtreppe
tile.stairsQuartz.name=Quarztreppe
tile.stairsRedSandStone.name=Rote Sandsteintreppe
tile.stairsSandStone.name=Sandsteintreppe
tile.stairsStone.name=Bruchsteintreppe
tile.stairsStoneBrickSmooth.name=Steinziegeltreppe
tile.stairsWood.name=Eichenholztreppe
tile.stairsWoodAcacia.name=Akazienholztreppe
tile.stairsWoodBirch.name=Birkenholztreppe
tile.stairsWoodDarkOak.name=Schwarzeichenholztreppe
tile.stairsWoodJungle.name=Tropenholztreppe
tile.stairsWoodSpruce.name=Fichtenholztreppe
tile.stone.andesite.name=Andesit
tile.stone.andesiteSmooth.name=Polierter Andesit
tile.stone.diorite.name=Diorit
tile.stone.dioriteSmooth.name=Polierter Diorit
tile.stone.granite.name=Granit
tile.stone.graniteSmooth.name=Polierter Granit
tile.stone.stone.name=Stein
tile.stoneMoss.name=Bemooster Bruchstein
tile.stoneSlab.brick.name=Ziegelstufe
tile.stoneSlab.cobble.name=Bruchsteinstufe
tile.stoneSlab.netherBrick.name=Netherziegelstufe
tile.stoneSlab.quartz.name=Quarzstufe
tile.stoneSlab.sand.name=Sandsteinstufe
tile.stoneSlab.smoothStoneBrick.name=Steinziegelstufe
tile.stoneSlab.stone.name=Steinstufe
tile.stoneSlab.wood.name=Holzstufe
tile.stoneSlab2.red_sandstone.name=Rote Sandsteinstufe
tile.stonebrick.name=Bruchstein
tile.stonebricksmooth.chiseled.name=Gemeißelte Steinziegel
tile.stonebricksmooth.cracked.name=Rissige Steinziegel
tile.stonebricksmooth.default.name=Steinziegel
tile.stonebricksmooth.mossy.name=Bemooste Steinziegel
tile.structureBlock.name=Konstruktionsblock
tile.structureVoid.name=Konstruktionsleere
tile.tallgrass.fern.name=Farn
tile.tallgrass.grass.name=Gras
tile.tallgrass.shrub.name=Busch
tile.thinGlass.name=Glasscheibe
tile.thinStainedGlass.black.name=Schwarze Glasscheibe
tile.thinStainedGlass.blue.name=Blaue Glasscheibe
tile.thinStainedGlass.brown.name=Braune Glasscheibe
tile.thinStainedGlass.cyan.name=Türkise Glasscheibe
tile.thinStainedGlass.gray.name=Graue Glasscheibe
tile.thinStainedGlass.green.name=Grüne Glasscheibe
tile.thinStainedGlass.lightBlue.name=Hellblaue Glasscheibe
tile.thinStainedGlass.lime.name=Hellgrüne Glasscheibe
tile.thinStainedGlass.magenta.name=Magenta Glasscheibe
tile.thinStainedGlass.orange.name=Orange Glasscheibe
tile.thinStainedGlass.pink.name=Rosa Glasscheibe
tile.thinStainedGlass.purple.name=Violette Glasscheibe
tile.thinStainedGlass.red.name=Rote Glasscheibe
tile.thinStainedGlass.silver.name=Hellgraue Glasscheibe
tile.thinStainedGlass.white.name=Weiße Glasscheibe
tile.thinStainedGlass.yellow.name=Gelbe Glasscheibe
tile.tnt.name=TNT
tile.torch.name=Fackel
tile.trapdoor.name=Holzfalltür
tile.tripWireSource.name=Haken
tile.vine.name=Ranken
tile.water.name=Wasser
tile.waterlily.name=Seerosenblatt
tile.web.name=Spinnennetz
tile.weightedPlate_heavy.name=Wägeplatte (hohe Gewichte)
tile.weightedPlate_light.name=Wägeplatte (niedrige Gewichte)
tile.whiteStone.name=Endstein
tile.wood.acacia.name=Akazienholzbretter
tile.wood.big_oak.name=Schwarzeichenholzbretter
tile.wood.birch.name=Birkenholzbretter
tile.wood.jungle.name=Tropenholzbretter
tile.wood.oak.name=Eichenholzbretter
tile.wood.spruce.name=Fichtenholzbretter
tile.woodSlab.acacia.name=Akazienholzstufe
tile.woodSlab.big_oak.name=Schwarzeichenholzstufe
tile.woodSlab.birch.name=Birkenholzstufe
tile.woodSlab.jungle.name=Tropenholzstufe
tile.woodSlab.oak.name=Eichenholzstufe
tile.woodSlab.spruce.name=Fichtenholzstufe
tile.woolCarpet.black.name=Schwarzer Teppich
tile.woolCarpet.blue.name=Blauer Teppich
tile.woolCarpet.brown.name=Brauner Teppich
tile.woolCarpet.cyan.name=Türkiser Teppich
tile.woolCarpet.gray.name=Grauer Teppich
tile.woolCarpet.green.name=Grüner Teppich
tile.woolCarpet.lightBlue.name=Hellblauer Teppich
tile.woolCarpet.lime.name=Hellgrüner Teppich
tile.woolCarpet.magenta.name=Magenta Teppich
tile.woolCarpet.orange.name=Oranger Teppich
tile.woolCarpet.pink.name=Rosa Teppich
tile.woolCarpet.purple.name=Violetter Teppich
tile.woolCarpet.red.name=Roter Teppich
tile.woolCarpet.silver.name=Hellgrauer Teppich
tile.woolCarpet.white.name=Weißer Teppich
tile.woolCarpet.yellow.name=Gelber Teppich
tile.workbench.name=Werkbank
tipped_arrow.effect.awkward=Getränkter Pfeil
tipped_arrow.effect.empty=Nicht herstellbarer getränkter Pfeil
tipped_arrow.effect.fire_resistance=Pfeil der Feuerresistenz
tipped_arrow.effect.harming=Pfeil des Schadens
tipped_arrow.effect.healing=Pfeil der Heilung
tipped_arrow.effect.invisibility=Pfeil der Unsichtbarkeit
tipped_arrow.effect.leaping=Pfeil der Sprungkraft
tipped_arrow.effect.luck=Pfeil des Glücks
tipped_arrow.effect.mundane=Getränkter Pfeil
tipped_arrow.effect.night_vision=Pfeil der Nachtsicht
tipped_arrow.effect.poison=Pfeil der Vergiftung
tipped_arrow.effect.regeneration=Pfeil der Regeneration
tipped_arrow.effect.slowness=Pfeil der Langsamkeit
tipped_arrow.effect.strength=Pfeil der Stärke
tipped_arrow.effect.swiftness=Pfeil der Schnelligkeit
tipped_arrow.effect.thick=Getränkter Pfeil
tipped_arrow.effect.water=Nasser Pfeil
tipped_arrow.effect.water_breathing=Pfeil der Unterwasseratmung
tipped_arrow.effect.weakness=Pfeil der Schwäche

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,93 +0,0 @@
# Do not change anything in here unless you know what you're doing!
name: ${project.name}
main: de.epiceric.shopchest.ShopChest
version: ${project.version}
author: EpicEric
website: ${project.url}
description: Create your own nice-looking chest shops and sell your stuff to other players!
softdepend: [WorldGuard, Towny, AuthMe, PlotSquared, uSkyBlock, ASkyBlock, IslandWorld, GriefPrevention, AreaShop, Multiverse-Core, MultiWorld]
depend: [Vault]
api-version: 1.13
permissions:
shopchest.*:
description: Gives access to all ShopChest permissions.
children:
shopchest.create: true
shopchest.create.buy: true
shopchest.create.sell: true
shopchest.create.admin: true
shopchest.create.protected: true
shopchest.remove.other: true
shopchest.remove.admin: true
shopchest.buy: true
shopchest.openOther: true
shopchest.notification.update: true
shopchest.reload: true
shopchest.update: true
shopchest.limit.*: true
shopchest.config: true
shopchest.extend.other: true
shopchest.extend.protected: true
shopchest.external.bypass: true
shopchest.create:
description: Allows you to create a shop.
children:
shopchest.create.buy: true
shopchest.create.sell: true
default: true
shopchest.create.buy:
description: Allows you to create a buy-shop.
default: true
shopchest.create.sell:
description: Allows you to create a sell-shop.
default: true
shopchest.create.admin:
description: Allows you to create an admin shop.
children:
shopchest.create: true
default: op
shopchest.create.protected:
description: Allows you to create a shop on a protected chest or in a protected region.
children:
shopchest.create: true
default: op
shopchest.remove.other:
description: Allows you to remove other players' shops.
default: op
shopchest.remove.admin:
description: Allows you to remove admin shops.
default: op
shopchest.buy:
description: Allows you to buy something.
default: true
shopchest.sell:
description: Allows you to sell something.
default: true
shopchest.openOther:
description: Allows you to open other players' shops.
default: op
shopchest.notification.update:
description: Allows you to get update notification on join.
default: op
shopchest.reload:
description: Allows you to reload the shops.
default: op
shopchest.update:
description: Allows you to check for updates.
default: op
shopchest.limit.*:
default: op
shopchest.config:
description: Allows you to change configuration values per command.
default: op
shopchest.extend.other:
description: Allows you to extend other players' shops.
default: op
shopchest.extend.protected:
description: Allows you to extend shops into a protected region.
default: op
shopchest.external.bypass:
description: Allows you to to use shops regions/plots that deny shop use.
default: op

View File

@ -11,7 +11,6 @@
<modules>
<module>api</module>
<module>implementation</module>
<module>new-implementation</module>
<module>nms</module>
</modules>