├── .gitignore ├── LICENSE ├── assembly └── pom.xml ├── bukkit ├── pom.xml └── src │ └── main │ ├── java │ └── net │ │ └── craftingstore │ │ └── bukkit │ │ ├── BukkitPluginConfiguration.java │ │ ├── CraftingStoreBukkit.java │ │ ├── CraftingStoreBukkitImpl.java │ │ ├── commands │ │ ├── BuyCommand.java │ │ └── CraftingStoreCommand.java │ │ ├── config │ │ └── Config.java │ │ ├── events │ │ └── DonationReceivedEvent.java │ │ ├── hooks │ │ ├── PlaceholderAPIHook.java │ │ └── VaultHook.java │ │ ├── inventory │ │ ├── BuyInventoryBuilder.java │ │ ├── BuyMenuInventoryHolder.java │ │ ├── CraftingStoreInventoryHolder.java │ │ ├── InventoryBuilder.java │ │ ├── InventoryItemBuilder.java │ │ ├── InventoryItemHandler.java │ │ └── handlers │ │ │ ├── BackButtonHandler.java │ │ │ ├── BuyButtonHandler.java │ │ │ ├── BuyablePackageHandler.java │ │ │ ├── CategoryItemHandler.java │ │ │ ├── CloseButtonHandler.java │ │ │ └── MessageButtonHandler.java │ │ ├── listeners │ │ ├── AdminJoinListener.java │ │ ├── InventoryListener.java │ │ └── PendingDonationJoinListener.java │ │ └── util │ │ ├── ChatColorUtil.java │ │ ├── VersionUtil.java │ │ └── XMaterial.java │ └── resources │ ├── config.yml │ └── plugin.yml ├── bungee ├── pom.xml └── src │ └── main │ ├── java │ └── net │ │ └── craftingstore │ │ └── bungee │ │ ├── BungeePluginConfiguration.java │ │ ├── CraftingStoreBungee.java │ │ ├── CraftingStoreBungeeImpl.java │ │ ├── commands │ │ └── CraftingStoreCommand.java │ │ ├── config │ │ └── Config.java │ │ ├── events │ │ └── DonationReceivedEvent.java │ │ └── listeners │ │ ├── AdminJoinListener.java │ │ └── PendingDonationJoinListener.java │ └── resources │ └── bungee.yml ├── core ├── pom.xml └── src │ └── main │ └── java │ └── net │ └── craftingstore │ └── core │ ├── CraftingStore.java │ ├── CraftingStoreAPI.java │ ├── CraftingStorePlugin.java │ ├── PluginConfiguration.java │ ├── exceptions │ └── CraftingStoreApiException.java │ ├── http │ ├── CraftingStoreAPIImpl.java │ ├── CraftingStoreCachedAPI.java │ └── util │ │ ├── GenericOf.java │ │ ├── InformationAdapter.java │ │ ├── InventoryAdapter.java │ │ ├── JsonResponseHandler.java │ │ └── JsonResponseHandlerV7.java │ ├── jobs │ ├── ExecuteDonationsJob.java │ └── ProcessPendingPaymentsJob.java │ ├── logging │ ├── CraftingStoreLogger.java │ └── impl │ │ └── JavaLogger.java │ ├── models │ ├── api │ │ ├── ApiCategory.java │ │ ├── ApiDonation.java │ │ ├── ApiInventory.java │ │ ├── ApiPackageInformation.java │ │ ├── ApiPayment.java │ │ ├── ApiTopDonator.java │ │ ├── Root.java │ │ ├── RootV7.java │ │ ├── inventory │ │ │ ├── CraftingStoreInventory.java │ │ │ ├── InventoryItem.java │ │ │ ├── InventoryItemEnhancement.java │ │ │ ├── InventoryItemIcon.java │ │ │ ├── InventoryItemType.java │ │ │ └── types │ │ │ │ ├── InventoryItemBackButton.java │ │ │ │ ├── InventoryItemBuyButton.java │ │ │ │ ├── InventoryItemBuyDetails.java │ │ │ │ ├── InventoryItemBuyablePackage.java │ │ │ │ ├── InventoryItemCategory.java │ │ │ │ ├── InventoryItemCloseButton.java │ │ │ │ └── InventoryItemMessage.java │ │ ├── misc │ │ │ ├── ApiKeyResult.java │ │ │ ├── CraftingStoreInformation.java │ │ │ └── UpdateInformation.java │ │ ├── provider │ │ │ ├── ProviderInformation.java │ │ │ ├── ProviderType.java │ │ │ └── SocketProviderInformation.java │ │ └── request │ │ │ ├── PackageInformationRequest.java │ │ │ └── PaymentCreateRequest.java │ └── donation │ │ ├── Donation.java │ │ ├── DonationPackage.java │ │ └── DonationPlayer.java │ ├── provider │ ├── CraftingStoreProvider.java │ ├── ProviderSelector.java │ ├── ProviderStatus.java │ └── SocketProvider.java │ ├── runner │ └── DonationRunner.java │ ├── scheduler │ ├── APICacheRenewer.java │ ├── DonationChecker.java │ ├── InformationUpdater.java │ ├── InventoryRenewer.java │ └── ProviderChecker.java │ └── util │ └── ArrayUtil.java ├── pom.xml ├── sponge ├── pom.xml └── src │ └── main │ └── java │ └── net │ └── craftingstore │ └── sponge │ ├── CraftingStoreSponge.java │ ├── CraftingStoreSpongeImpl.java │ ├── SpongePluginConfiguration.java │ ├── commands │ ├── BuyCommand.java │ └── CraftingStoreCommand.java │ ├── config │ └── Config.java │ ├── events │ └── DonationReceivedEvent.java │ ├── inventory │ ├── CraftingStoreInventoryProperty.java │ ├── InventoryAttachment.java │ ├── InventoryBuilder.java │ ├── InventoryItemHandler.java │ └── handlers │ │ ├── BackButtonHandler.java │ │ ├── CategoryItemHandler.java │ │ ├── CloseButtonHandler.java │ │ └── MessageButtonHandler.java │ ├── listeners │ ├── InventoryClickListener.java │ └── PendingDonationJoinListener.java │ ├── logging │ └── Slf4jLogger.java │ └── module │ ├── ConfigModule.java │ └── CraftingStoreModule.java └── velocity ├── pom.xml └── src └── main ├── java └── net │ └── craftingstore │ └── velocity │ ├── CraftingStoreVelocity.java │ ├── CraftingStoreVelocityImpl.java │ ├── VelocityPluginConfiguration.java │ ├── annotation │ └── Prefix.java │ ├── command │ └── CraftingStoreCommand.java │ ├── config │ └── Config.java │ ├── events │ ├── DonationReceivedEvent.java │ └── DonationResult.java │ ├── listeners │ └── PendingDonationJoinListener.java │ ├── logging │ └── Slf4jLogger.java │ └── module │ ├── ConfigModule.java │ └── CraftingStoreModule.java └── resources └── config.json /.gitignore: -------------------------------------------------------------------------------- 1 | ### Maven template 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.versionsBackup 6 | pom.xml.next 7 | release.properties 8 | dependency-reduced-pom.xml 9 | buildNumber.properties 10 | .mvn/timing.properties 11 | .mvn/wrapper/maven-wrapper.jar 12 | .flattened-pom.xml 13 | 14 | # IntelliJ project files 15 | .idea 16 | *.iml 17 | out 18 | gen 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 CraftingStore.net 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bukkit/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | net.craftingstore 9 | craftingstore 10 | ${revision} 11 | 12 | 13 | bukkit 14 | 15 | 16 | 17 | org.apache.maven.plugins 18 | maven-compiler-plugin 19 | 20 | 8 21 | 8 22 | 23 | 24 | 25 | 26 | 27 | src/main/resources 28 | true 29 | 30 | 31 | 32 | 33 | 34 | 35 | spigot-repo 36 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/ 37 | 38 | 39 | 40 | PlaceholderAPI 41 | https://repo.extendedclip.com/content/repositories/placeholderapi/ 42 | 43 | 44 | razyr-dev 45 | https://rayzr.dev/repo/ 46 | 47 | 48 | codemc 49 | https://repo.codemc.org/repository/maven-public 50 | 51 | 52 | 53 | jitpack.io 54 | https://jitpack.io 55 | 56 | 57 | papermc 58 | https://repo.papermc.io/repository/maven-public/ 59 | 60 | 61 | 62 | 63 | 64 | net.craftingstore 65 | core 66 | ${project.version} 67 | 68 | 69 | io.papermc.paper 70 | paper-api 71 | 1.20.6-R0.1-SNAPSHOT 72 | provided 73 | 74 | 75 | net.md-5 76 | bungeecord-chat 77 | 1.20-R0.2 78 | provided 79 | 80 | 81 | me.clip 82 | placeholderapi 83 | 2.10.7 84 | provided 85 | 86 | 87 | com.github.cryptomorin 88 | XSeries 89 | 9.4.0 90 | 91 | 92 | com.github.MilkBowl 93 | VaultAPI 94 | 1.7 95 | provided 96 | 97 | 98 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/BukkitPluginConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit; 2 | 3 | import net.craftingstore.core.PluginConfiguration; 4 | 5 | public class BukkitPluginConfiguration implements PluginConfiguration { 6 | 7 | private CraftingStoreBukkit plugin; 8 | 9 | BukkitPluginConfiguration(CraftingStoreBukkit plugin) { 10 | this.plugin = plugin; 11 | } 12 | 13 | @Override 14 | public String getName() { 15 | return "Bukkit"; 16 | } 17 | 18 | @Override 19 | public String[] getMainCommands() { 20 | return new String[]{"craftingstore", "cs"}; 21 | } 22 | 23 | @Override 24 | public String getVersion() { 25 | return plugin.getDescription().getVersion(); 26 | } 27 | 28 | @Override 29 | public String getPlatform() { 30 | return plugin.getServer().getVersion(); 31 | } 32 | 33 | @Override 34 | public boolean isBuyCommandEnabled() { 35 | return !plugin.getConfig().getBoolean("disable-buy-command", false); 36 | } 37 | 38 | @Override 39 | public int getTimeBetweenCommands() { 40 | return plugin.getConfig().getInt("time-between-commands", 200); 41 | } 42 | 43 | @Override 44 | public String getNotEnoughBalanceMessage() { 45 | return plugin.getConfig().getString("not-enough-balance-message", "&4You do not have enough in-game money in your account! You can also buy this package on the website:"); 46 | } 47 | 48 | @Override 49 | public boolean isUsingAlternativeApi() { 50 | return plugin.getConfig().getBoolean("use-alternative-api", false); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/CraftingStoreBukkit.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit; 2 | 3 | import net.craftingstore.bukkit.commands.BuyCommand; 4 | import net.craftingstore.bukkit.commands.CraftingStoreCommand; 5 | import net.craftingstore.bukkit.config.Config; 6 | import net.craftingstore.bukkit.hooks.PlaceholderAPIHook; 7 | import net.craftingstore.bukkit.hooks.VaultHook; 8 | import net.craftingstore.bukkit.listeners.InventoryListener; 9 | import net.craftingstore.bukkit.listeners.AdminJoinListener; 10 | import net.craftingstore.bukkit.listeners.PendingDonationJoinListener; 11 | import net.craftingstore.bukkit.util.VersionUtil; 12 | import net.craftingstore.core.CraftingStore; 13 | import org.bukkit.Bukkit; 14 | import org.bukkit.ChatColor; 15 | import org.bukkit.configuration.file.FileConfiguration; 16 | import org.bukkit.plugin.java.JavaPlugin; 17 | 18 | public class CraftingStoreBukkit extends JavaPlugin { 19 | 20 | private CraftingStore craftingStore; 21 | private Config config; 22 | private String prefix = ChatColor.GRAY + "[" + ChatColor.RED + "CraftingStore" + ChatColor.GRAY + "] " + ChatColor.WHITE; 23 | private VaultHook vaultHook; 24 | 25 | @Override 26 | public void onEnable() { 27 | config = new Config("config.yml", this); 28 | this.craftingStore = new CraftingStore(new CraftingStoreBukkitImpl(this)); 29 | 30 | this.getCommand("craftingstore").setExecutor(new CraftingStoreCommand(this)); 31 | if (this.craftingStore.getImplementation().getConfiguration().isBuyCommandEnabled()) { 32 | this.getCommand("csbuy").setExecutor(new BuyCommand(this)); 33 | } 34 | 35 | this.getServer().getPluginManager().registerEvents(new InventoryListener(this), this); 36 | this.getServer().getPluginManager().registerEvents(new AdminJoinListener(this), this); 37 | this.getServer().getPluginManager().registerEvents(new PendingDonationJoinListener(this), this); 38 | 39 | // PlaceholderAPI hook 40 | if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { 41 | new PlaceholderAPIHook(craftingStore); 42 | craftingStore.getLogger().info("Hooked with PlaceholderAPI"); 43 | } 44 | // Vault hook 45 | if (Bukkit.getPluginManager().isPluginEnabled("Vault")) { 46 | this.vaultHook = new VaultHook(this); 47 | if (this.vaultHook.register()) { 48 | craftingStore.getLogger().info("Hooked with Vault"); 49 | } else { 50 | craftingStore.getLogger().info("There was a problem hooking with Vault"); 51 | this.vaultHook = null; 52 | } 53 | } 54 | } 55 | 56 | @Override 57 | public void onDisable() { 58 | craftingStore.setEnabled(false); 59 | craftingStore.getLogger().debug("Shutdown complete"); 60 | } 61 | 62 | public CraftingStore getCraftingStore() { 63 | return craftingStore; 64 | } 65 | 66 | @Override 67 | public FileConfiguration getConfig() { 68 | return this.config.getConfig(); 69 | } 70 | 71 | public Config getConfigWrapper() { 72 | return this.config; 73 | } 74 | 75 | public String getPrefix() { 76 | return prefix; 77 | } 78 | 79 | public VaultHook getVaultHook() { 80 | return vaultHook; 81 | } 82 | 83 | public boolean isHookedWithVault() { 84 | return vaultHook != null; 85 | } 86 | 87 | public void runSyncTask(Runnable runnable) { 88 | if (VersionUtil.isFoliaSchedulerAvailable()) { 89 | this.getServer().getGlobalRegionScheduler().run(this, (task) -> runnable.run()); 90 | } else { 91 | this.getServer().getScheduler().runTask(this, runnable); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/CraftingStoreBukkitImpl.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit; 2 | 3 | import net.craftingstore.bukkit.events.DonationReceivedEvent; 4 | import net.craftingstore.bukkit.util.VersionUtil; 5 | import net.craftingstore.core.CraftingStorePlugin; 6 | import net.craftingstore.core.PluginConfiguration; 7 | import net.craftingstore.core.logging.CraftingStoreLogger; 8 | import net.craftingstore.core.logging.impl.JavaLogger; 9 | import net.craftingstore.core.models.donation.Donation; 10 | import org.bukkit.Bukkit; 11 | import org.bukkit.Server; 12 | 13 | import java.util.concurrent.TimeUnit; 14 | 15 | 16 | public class CraftingStoreBukkitImpl implements CraftingStorePlugin { 17 | 18 | private CraftingStoreBukkit bukkitPlugin; 19 | private JavaLogger logger; 20 | private PluginConfiguration pluginConfiguration; 21 | 22 | CraftingStoreBukkitImpl(CraftingStoreBukkit bukkitPlugin) { 23 | this.bukkitPlugin = bukkitPlugin; 24 | this.pluginConfiguration = new BukkitPluginConfiguration(bukkitPlugin); 25 | this.logger = new JavaLogger(bukkitPlugin.getLogger()); 26 | this.logger.setDebugging(bukkitPlugin.getConfig().getBoolean("debug", false)); 27 | } 28 | 29 | public boolean executeDonation(Donation donation) { 30 | if (donation.getPlayer().isRequiredOnline()) { 31 | if (Bukkit.getPlayerExact(donation.getPlayer().getUsername()) == null) { 32 | return false; 33 | } 34 | } 35 | Server server = this.bukkitPlugin.getServer(); 36 | 37 | DonationReceivedEvent event = new DonationReceivedEvent(donation); 38 | server.getPluginManager().callEvent(event); 39 | if (event.isCancelled()) { 40 | return false; 41 | } 42 | 43 | this.bukkitPlugin.runSyncTask(() -> server.dispatchCommand(server.getConsoleSender(), donation.getCommand())); 44 | return true; 45 | } 46 | 47 | public CraftingStoreLogger getLogger() { 48 | return this.logger; 49 | } 50 | 51 | public void registerRunnable(Runnable runnable, int delay, int interval) { 52 | if (VersionUtil.isFoliaSchedulerAvailable()) { 53 | this.bukkitPlugin.getServer().getAsyncScheduler().runAtFixedRate(this.bukkitPlugin, task -> runnable.run(), delay, interval, TimeUnit.SECONDS); 54 | } else { 55 | this.bukkitPlugin.getServer().getScheduler().runTaskTimerAsynchronously(this.bukkitPlugin, runnable, delay * 20, interval * 20); 56 | } 57 | } 58 | 59 | public void runAsyncTask(Runnable runnable) { 60 | if (VersionUtil.isFoliaSchedulerAvailable()) { 61 | this.bukkitPlugin.getServer().getAsyncScheduler().runNow(this.bukkitPlugin, task -> runnable.run()); 62 | } else { 63 | this.bukkitPlugin.getServer().getScheduler().runTaskAsynchronously(this.bukkitPlugin, runnable); 64 | } 65 | } 66 | 67 | public String getToken() { 68 | return bukkitPlugin.getConfig().getString("api-key"); 69 | } 70 | 71 | @Override 72 | public PluginConfiguration getConfiguration() { 73 | return this.pluginConfiguration; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/commands/BuyCommand.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.commands; 2 | 3 | import net.craftingstore.bukkit.CraftingStoreBukkit; 4 | import net.craftingstore.bukkit.inventory.InventoryBuilder; 5 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 6 | import net.craftingstore.core.models.api.ApiInventory; 7 | import net.craftingstore.core.models.api.inventory.CraftingStoreInventory; 8 | import org.bukkit.command.Command; 9 | import org.bukkit.command.CommandExecutor; 10 | import org.bukkit.command.CommandSender; 11 | import org.bukkit.entity.Player; 12 | import org.bukkit.inventory.Inventory; 13 | 14 | import java.util.concurrent.ExecutionException; 15 | 16 | public class BuyCommand implements CommandExecutor { 17 | 18 | private CraftingStoreBukkit instance; 19 | 20 | public BuyCommand(CraftingStoreBukkit instance) { 21 | this.instance = instance; 22 | } 23 | 24 | @Override 25 | public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { 26 | if (!(sender instanceof Player)) { 27 | return false; 28 | } 29 | if (!this.instance.getCraftingStore().isEnabled()) { 30 | sender.sendMessage(instance.getPrefix() + "The plugin has not been set-up correctly. Please contact an administrator."); 31 | return false; 32 | } 33 | Player p = (Player) sender; 34 | this.instance.getCraftingStore().getImplementation().runAsyncTask(() -> { 35 | try { 36 | InventoryBuilder builder = new InventoryBuilder(this.instance); 37 | ApiInventory gui = instance.getCraftingStore().getApi().getGUI().get(); 38 | Inventory inventory = builder.buildInventory( 39 | new CraftingStoreInventory(gui.getTitle(), gui.getContent(), gui.getSize()) 40 | ); 41 | this.instance.runSyncTask(() -> { 42 | if (p.isOnline()) { 43 | p.openInventory(inventory); 44 | } 45 | }); 46 | } catch (CraftingStoreApiException | InterruptedException | ExecutionException e) { 47 | e.printStackTrace(); 48 | } 49 | }); 50 | return true; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/commands/CraftingStoreCommand.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.commands; 2 | 3 | import net.craftingstore.bukkit.CraftingStoreBukkit; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.ChatColor; 6 | import org.bukkit.command.Command; 7 | import org.bukkit.command.CommandExecutor; 8 | import org.bukkit.command.CommandSender; 9 | 10 | import java.util.concurrent.ExecutionException; 11 | 12 | public class CraftingStoreCommand implements CommandExecutor { 13 | 14 | private CraftingStoreBukkit instance; 15 | 16 | public CraftingStoreCommand(CraftingStoreBukkit instance) { 17 | this.instance = instance; 18 | } 19 | 20 | @Override 21 | public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { 22 | if (!sender.hasPermission(instance.getCraftingStore().ADMIN_PERMISSION)) { 23 | sender.sendMessage(instance.getPrefix() + "You don't have the required permission!"); 24 | return false; 25 | } 26 | if (args.length == 1 && args[0].equalsIgnoreCase("reload")) { 27 | instance.getCraftingStore().reload(); 28 | sender.sendMessage(instance.getPrefix() + "The plugin is reloading!"); 29 | return true; 30 | } 31 | if (args.length == 2 && args[0].equalsIgnoreCase("key")) { 32 | instance.getConfig().set("api-key", args[1]); 33 | instance.getConfigWrapper().saveConfig(); 34 | instance.getServer().getScheduler().runTaskAsynchronously(instance, () -> { 35 | try { 36 | if (instance.getCraftingStore().reload().get()) { 37 | sender.sendMessage(instance.getPrefix() + "The new API key has been set in the config, and the plugin has been reloaded."); 38 | } else { 39 | sender.sendMessage(instance.getPrefix() + "The API key is invalid. The plugin will not work until you set a valid API key."); 40 | } 41 | } catch (InterruptedException | ExecutionException e) { 42 | e.printStackTrace(); 43 | } 44 | }); 45 | return true; 46 | } 47 | if ((args.length == 1 || args.length == 2) && args[0].equalsIgnoreCase("debug")) { 48 | boolean isDebugging = this.instance.getCraftingStore().getLogger().isDebugging(); 49 | if (args.length == 1) { 50 | sender.sendMessage(String.format( 51 | "%sDebug mode is currently %s.", 52 | this.instance.getPrefix(), 53 | isDebugging ? "enabled" : "disabled" 54 | )); 55 | return true; 56 | } 57 | String debugValue = args[1].toLowerCase(); 58 | if (debugValue.equalsIgnoreCase("true")) { 59 | isDebugging = true; 60 | } else if (debugValue.equalsIgnoreCase("false")) { 61 | isDebugging = false; 62 | } else { 63 | sender.sendMessage(instance.getPrefix() + "Unknown debug value."); 64 | return true; 65 | } 66 | this.instance.getCraftingStore().getLogger().setDebugging(isDebugging); 67 | instance.getConfig().set("debug", isDebugging); 68 | instance.getConfigWrapper().saveConfig(); 69 | sender.sendMessage(String.format( 70 | "%sDebug mode has been %s.", 71 | this.instance.getPrefix(), 72 | isDebugging ? "enabled" : "disabled" 73 | )); 74 | return true; 75 | } 76 | 77 | sender.sendMessage(ChatColor.GRAY + "" +ChatColor.STRIKETHROUGH + "-----------------------"); 78 | sender.sendMessage(ChatColor.DARK_GRAY + ">" + ChatColor.GRAY + " /" + label + " reload" + ChatColor.DARK_GRAY + " -> " + ChatColor.GRAY + "Reload the config."); 79 | sender.sendMessage(ChatColor.DARK_GRAY + ">" + ChatColor.GRAY + " /" + label + " key " + ChatColor.DARK_GRAY + " -> " + ChatColor.GRAY + "Update the key."); 80 | sender.sendMessage(ChatColor.GRAY + "" +ChatColor.STRIKETHROUGH + "-----------------------"); 81 | return true; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/config/Config.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.config; 2 | 3 | import org.bukkit.configuration.file.FileConfiguration; 4 | import org.bukkit.configuration.file.YamlConfiguration; 5 | import org.bukkit.plugin.Plugin; 6 | 7 | import java.io.*; 8 | import java.nio.charset.StandardCharsets; 9 | import java.util.logging.Level; 10 | 11 | public class Config { 12 | 13 | private Plugin instance; 14 | private FileConfiguration config = null; 15 | private File configFile = null; 16 | private String filename; 17 | 18 | /** 19 | * Create a new instance of Config, specifying a file name and Plugin. 20 | * 21 | * @param filename the file name, including .yml 22 | * @param instance the instance 23 | */ 24 | public Config(String filename, Plugin instance) { 25 | this.filename = filename; 26 | this.instance = instance; 27 | 28 | reload(); 29 | 30 | File file = new File(instance.getDataFolder() + File.pathSeparator + filename); 31 | if (!file.exists()) { 32 | if (instance.getResource(filename) != null) { 33 | Reader defaultConfigFile = new InputStreamReader(instance.getResource(filename), StandardCharsets.UTF_8); 34 | YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(defaultConfigFile); 35 | config.setDefaults(defConfig); 36 | config.options().copyDefaults(true); 37 | saveConfig(); 38 | } 39 | } 40 | } 41 | 42 | /** 43 | * Reload the config. 44 | */ 45 | public void reload() { 46 | if (configFile == null) { 47 | configFile = new File(instance.getDataFolder(), filename); 48 | } 49 | config = YamlConfiguration.loadConfiguration(configFile); 50 | } 51 | 52 | /** 53 | * Get the FileConfiguration associated with this Config. 54 | * 55 | * @return the FileConfiguration 56 | */ 57 | public FileConfiguration getConfig() { 58 | if (configFile == null) { 59 | reload(); 60 | } 61 | return config; 62 | } 63 | 64 | /** 65 | * Save all changes to the disk. 66 | */ 67 | public void saveConfig() { 68 | if (config == null || configFile == null) { 69 | return; 70 | } 71 | 72 | try { 73 | getConfig().save(configFile); 74 | } catch (IOException e) { 75 | instance.getLogger().log(Level.SEVERE, "An error occurred while saving the config file " + filename + ".", e); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/events/DonationReceivedEvent.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.events; 2 | 3 | import net.craftingstore.core.models.donation.Donation; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.Event; 6 | import org.bukkit.event.HandlerList; 7 | 8 | import java.util.UUID; 9 | 10 | public class DonationReceivedEvent extends Event implements Cancellable { 11 | 12 | @Deprecated 13 | private String command; 14 | @Deprecated 15 | private String username; 16 | @Deprecated 17 | private UUID uuid; 18 | @Deprecated 19 | private String packageName; 20 | @Deprecated 21 | private int packagePrice; 22 | @Deprecated 23 | private int couponDiscount; 24 | 25 | private Donation donation; 26 | 27 | private boolean cancelled = false; 28 | 29 | @Deprecated 30 | public DonationReceivedEvent(String command, String username, UUID uuid, String packageName, int packagePrice, int couponDiscount) { 31 | super(true); 32 | this.command = command; 33 | this.username = username; 34 | this.uuid = uuid; 35 | this.packageName = packageName; 36 | this.packagePrice = packagePrice; 37 | this.couponDiscount = couponDiscount; 38 | } 39 | 40 | public DonationReceivedEvent(Donation donation) { 41 | super(true); 42 | this.command = donation.getCommand(); 43 | this.username = donation.getPlayer().getUsername(); 44 | this.uuid = donation.getPlayer().getUUID(); 45 | this.packageName = donation.getPackage().getName(); 46 | this.packagePrice = donation.getPackage().getPrice(); 47 | this.couponDiscount = donation.getDiscount(); 48 | this.donation = donation; 49 | } 50 | 51 | public Donation getDonation() { 52 | return this.donation; 53 | } 54 | 55 | @Deprecated 56 | public String getCommand() { 57 | return command; 58 | } 59 | 60 | @Deprecated 61 | public String getUsername() { 62 | return username; 63 | } 64 | 65 | @Deprecated 66 | public UUID getUuid() { 67 | return uuid; 68 | } 69 | 70 | @Deprecated 71 | public String getPackageName() { 72 | return packageName; 73 | } 74 | 75 | @Deprecated 76 | public int getPackagePrice() { 77 | return packagePrice; 78 | } 79 | 80 | @Deprecated 81 | public int getCouponDiscount() { 82 | return couponDiscount; 83 | } 84 | 85 | public boolean isCancelled() { 86 | return cancelled; 87 | } 88 | 89 | public void setCancelled(boolean cancelled) { 90 | this.cancelled = cancelled; 91 | } 92 | 93 | private static final HandlerList handlers = new HandlerList(); 94 | 95 | public HandlerList getHandlers() { 96 | return handlers; 97 | } 98 | 99 | public static HandlerList getHandlerList() { 100 | return handlers; 101 | } 102 | 103 | } -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/hooks/PlaceholderAPIHook.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.hooks; 2 | 3 | import me.clip.placeholderapi.expansion.PlaceholderExpansion; 4 | import net.craftingstore.core.CraftingStore; 5 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 6 | import net.craftingstore.core.models.api.ApiPayment; 7 | import net.craftingstore.core.models.api.ApiTopDonator; 8 | import org.bukkit.OfflinePlayer; 9 | 10 | import java.util.concurrent.ExecutionException; 11 | import java.util.regex.Matcher; 12 | import java.util.regex.Pattern; 13 | 14 | public class PlaceholderAPIHook extends PlaceholderExpansion { 15 | 16 | private CraftingStore instance; 17 | 18 | public PlaceholderAPIHook(CraftingStore instance) { 19 | this.instance = instance; 20 | this.register(); // Documentation is missing so we are using this method. 21 | } 22 | 23 | @Override 24 | public String onRequest(OfflinePlayer player, String s) { 25 | try { 26 | if (s.startsWith("donator")) { 27 | return handleDonators(player, s); 28 | } else if (s.startsWith("payment")) { 29 | return handlePayments(player, s); 30 | } 31 | } catch (CraftingStoreApiException | ExecutionException | InterruptedException e) { 32 | e.printStackTrace(); 33 | } 34 | 35 | return null; 36 | } 37 | 38 | private String handleDonators(OfflinePlayer player, String s) throws CraftingStoreApiException, ExecutionException, InterruptedException { 39 | ApiTopDonator[] topDonators = instance.getApi().getTopDonators().get(); 40 | if (topDonators == null) { 41 | return ""; // Donators are not retrieved yet. 42 | } else if (s.equalsIgnoreCase("donator")) { 43 | StringBuilder builder = new StringBuilder(); 44 | for (ApiTopDonator donator : topDonators) { 45 | builder.append(donator.getUsername()).append(": ").append(donator.getTotal()).append(", "); 46 | } 47 | builder.substring(0, builder.length() - 2); // Remove the last ', ' from the string 48 | return builder.toString(); 49 | } else if (s.startsWith("donator_")) { 50 | Pattern pattern = Pattern.compile("donator_([1-5])"); 51 | Matcher matcher = pattern.matcher(s); 52 | if (matcher.matches()) { 53 | int id = Integer.parseInt(matcher.group(1)); 54 | if (topDonators.length >= id) { 55 | id--; // Zero based array 56 | ApiTopDonator donator = topDonators[id]; 57 | return donator.getUsername() + ": " + donator.getTotal(); 58 | } 59 | } 60 | } 61 | return ""; 62 | } 63 | 64 | private String handlePayments(OfflinePlayer player, String s) throws CraftingStoreApiException, ExecutionException, InterruptedException { 65 | ApiPayment[] payments = instance.getApi().getPayments().get(); 66 | if (payments == null || payments.length == 0) { 67 | return ""; // Recent payments are not retrieved yet or there are no payments. 68 | } else if (s.equalsIgnoreCase("payment")) { 69 | StringBuilder builder = new StringBuilder(); 70 | for (ApiPayment payment : payments) { 71 | builder.append(payment.getUsername()).append(": ").append(payment.getPackageName()).append(", "); 72 | } 73 | builder.substring(0, builder.length() - 2); // Remove the last ', ' from the string 74 | return builder.toString(); 75 | } else if (s.startsWith("payment_")) { 76 | Pattern pattern = Pattern.compile("payment_([1-5])"); 77 | Matcher matcher = pattern.matcher(s); 78 | if (matcher.matches()) { 79 | int id = Integer.parseInt(matcher.group(1)); 80 | if (payments.length >= id) { 81 | id--; // Zero based array 82 | ApiPayment payment = payments[id]; 83 | return payment.getUsername() + ": " + payment.getPackageName(); 84 | } 85 | } 86 | } 87 | return ""; 88 | } 89 | 90 | @Override 91 | public String getIdentifier() { 92 | return "craftingstore"; 93 | } 94 | 95 | @Override 96 | public String getAuthor() { 97 | return "CraftingStore"; 98 | } 99 | 100 | @Override 101 | public String getVersion() { 102 | return this.instance.getImplementation().getConfiguration().getVersion(); 103 | } 104 | 105 | @Override 106 | public boolean persist() { 107 | return true; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/hooks/VaultHook.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.hooks; 2 | 3 | import net.craftingstore.bukkit.CraftingStoreBukkit; 4 | import net.milkbowl.vault.economy.Economy; 5 | import org.bukkit.plugin.RegisteredServiceProvider; 6 | 7 | public class VaultHook { 8 | private final CraftingStoreBukkit instance; 9 | private Economy economy; 10 | 11 | public VaultHook(CraftingStoreBukkit instance) { 12 | this.instance = instance; 13 | } 14 | 15 | public boolean register() { 16 | RegisteredServiceProvider rsp = instance.getServer().getServicesManager().getRegistration(Economy.class); 17 | if (rsp == null) { 18 | return false; 19 | } 20 | this.economy = rsp.getProvider(); 21 | return true; 22 | } 23 | 24 | public Economy getEconomy() { 25 | return economy; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/inventory/BuyInventoryBuilder.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.inventory; 2 | 3 | import net.craftingstore.bukkit.CraftingStoreBukkit; 4 | import net.craftingstore.bukkit.util.ChatColorUtil; 5 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 6 | import net.craftingstore.core.models.api.ApiInventory; 7 | import net.craftingstore.core.models.api.ApiPackageInformation; 8 | import net.craftingstore.core.models.api.inventory.CraftingStoreInventory; 9 | import net.craftingstore.core.models.api.inventory.InventoryItem; 10 | import net.craftingstore.core.models.api.inventory.InventoryItemIcon; 11 | import net.craftingstore.core.models.api.inventory.InventoryItemType; 12 | import net.craftingstore.core.models.api.inventory.types.InventoryItemBuyablePackage; 13 | import org.bukkit.entity.Player; 14 | import org.bukkit.inventory.Inventory; 15 | 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | import java.util.concurrent.ExecutionException; 19 | 20 | public class BuyInventoryBuilder { 21 | 22 | private final CraftingStoreBukkit instance; 23 | private final InventoryBuilder inventoryBuilder; 24 | 25 | public BuyInventoryBuilder(CraftingStoreBukkit instance, InventoryBuilder inventoryBuilder) { 26 | this.instance = instance; 27 | this.inventoryBuilder = inventoryBuilder; 28 | } 29 | 30 | public Inventory build(Player p, InventoryItemBuyablePackage item, CraftingStoreInventoryHolder holder) throws CraftingStoreApiException, ExecutionException, InterruptedException { 31 | ApiInventory buyMenu = this.instance.getCraftingStore().getApi().getGUI().get().getBuyMenu(); 32 | CraftingStoreInventory craftingStoreInventory = new CraftingStoreInventory(buyMenu.getTitle(), buyMenu.getContent(), buyMenu.getSize()); 33 | 34 | String ip = p.getAddress().getAddress().getHostAddress(); 35 | ApiPackageInformation packageInformation = this.instance.getCraftingStore().getApi().getPackageInformation( 36 | p.getName(), 37 | p.getUniqueId(), 38 | ip, 39 | item.getPackageId() 40 | ).get(); 41 | if (!packageInformation.isAllowedToBuy()) { 42 | p.sendMessage(ChatColorUtil.translate(packageInformation.getMessage())); 43 | this.closeInventory(p); 44 | return null; 45 | } 46 | if (packageInformation.getPrice() != item.getPrice()) { 47 | p.sendMessage(this.instance.getPrefix() + "There was a problem with the payment data. Please try again later."); 48 | this.closeInventory(p); 49 | return null; 50 | } 51 | 52 | Map placeholders = new HashMap<>(); 53 | placeholders.put("package_name", item.getName()); 54 | placeholders.put("package_price_ingame", packageInformation.getPrice()); 55 | return this.inventoryBuilder.buildInventory( 56 | craftingStoreInventory, 57 | new BuyMenuInventoryHolder(craftingStoreInventory, holder, item), 58 | placeholders 59 | ); 60 | } 61 | 62 | public Inventory buildLoadInventory() { 63 | InventoryItemIcon icon = new InventoryItemIcon("LIGHT_BLUE_STAINED_GLASS_PANE", 1, 0, null); 64 | InventoryItem[] content = new InventoryItem[9]; 65 | for (int i = 0; i < 9; i++) { 66 | content[i] = new InventoryItem("Loading...", null, InventoryItemType.NULL, icon, i); 67 | } 68 | 69 | CraftingStoreInventory craftingStoreInventory = new CraftingStoreInventory( 70 | "Loading...", 71 | content, 72 | 9 73 | ); 74 | return this.inventoryBuilder.buildInventory( 75 | craftingStoreInventory, 76 | new CraftingStoreInventoryHolder(craftingStoreInventory, null) 77 | ); 78 | } 79 | 80 | private void closeInventory(Player p) { 81 | this.instance.runSyncTask(() -> { 82 | if (p.isOnline()) { 83 | p.closeInventory(); 84 | } 85 | }); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/inventory/BuyMenuInventoryHolder.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.inventory; 2 | 3 | import net.craftingstore.core.models.api.inventory.CraftingStoreInventory; 4 | import net.craftingstore.core.models.api.inventory.types.InventoryItemBuyablePackage; 5 | 6 | public class BuyMenuInventoryHolder extends CraftingStoreInventoryHolder { 7 | 8 | private final InventoryItemBuyablePackage itemBuyablePackage; 9 | 10 | public BuyMenuInventoryHolder( 11 | CraftingStoreInventory csInventory, 12 | CraftingStoreInventoryHolder parentInventory, 13 | InventoryItemBuyablePackage itemBuyablePackage 14 | ) { 15 | super(csInventory, parentInventory); 16 | this.itemBuyablePackage = itemBuyablePackage; 17 | } 18 | 19 | public InventoryItemBuyablePackage getItemBuyablePackage() { 20 | return itemBuyablePackage; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/inventory/CraftingStoreInventoryHolder.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.inventory; 2 | 3 | import net.craftingstore.core.models.api.inventory.CraftingStoreInventory; 4 | import org.bukkit.inventory.Inventory; 5 | import org.bukkit.inventory.InventoryHolder; 6 | 7 | public class CraftingStoreInventoryHolder implements InventoryHolder { 8 | 9 | private CraftingStoreInventory csInventory; 10 | private CraftingStoreInventoryHolder parentInventory; 11 | 12 | public CraftingStoreInventoryHolder(CraftingStoreInventory csInventory, CraftingStoreInventoryHolder parentInventory) { 13 | this.csInventory = csInventory; 14 | this.parentInventory = parentInventory; 15 | } 16 | 17 | @Override 18 | public Inventory getInventory() { 19 | return null; 20 | } 21 | 22 | public CraftingStoreInventory getCsInventory() { 23 | return csInventory; 24 | } 25 | 26 | public CraftingStoreInventoryHolder getParentInventory() { 27 | return parentInventory; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/inventory/InventoryBuilder.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.inventory; 2 | 3 | import net.craftingstore.bukkit.CraftingStoreBukkit; 4 | import net.craftingstore.bukkit.util.ChatColorUtil; 5 | import net.craftingstore.bukkit.util.VersionUtil; 6 | import net.craftingstore.core.models.api.inventory.CraftingStoreInventory; 7 | import net.craftingstore.core.models.api.inventory.InventoryItem; 8 | import org.apache.commons.text.StringSubstitutor; 9 | import org.bukkit.Bukkit; 10 | import org.bukkit.inventory.Inventory; 11 | import org.bukkit.inventory.ItemStack; 12 | import org.bukkit.inventory.meta.ItemMeta; 13 | 14 | import java.util.Arrays; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | import java.util.stream.Collectors; 18 | 19 | public class InventoryBuilder { 20 | 21 | private final CraftingStoreBukkit instance; 22 | private final InventoryItemBuilder inventoryItemBuilder; 23 | 24 | public InventoryBuilder(CraftingStoreBukkit instance) { 25 | this.instance = instance; 26 | this.inventoryItemBuilder = new InventoryItemBuilder(instance); 27 | } 28 | 29 | public Inventory buildInventory(CraftingStoreInventory csInventory) { 30 | return buildInventory(csInventory, new CraftingStoreInventoryHolder(csInventory, null)); 31 | } 32 | 33 | public Inventory buildInventory(CraftingStoreInventory csInventory, CraftingStoreInventoryHolder holder) { 34 | return buildInventory(csInventory, holder, new HashMap<>()); 35 | } 36 | 37 | public Inventory buildInventory(CraftingStoreInventory csInventory, CraftingStoreInventoryHolder holder, Map placeholders) { 38 | String title = csInventory.getTitle(); 39 | if (title == null || title.isEmpty()) { 40 | title = "CraftingStore"; 41 | } 42 | 43 | StringSubstitutor stringSubstitutor = new StringSubstitutor(placeholders, "{", "}"); 44 | title = ChatColorUtil.translate(stringSubstitutor.replace(title)); 45 | Inventory inventory = Bukkit.createInventory(holder, csInventory.getSize(), title); 46 | 47 | for (InventoryItem inventoryItem : csInventory.getContent()) { 48 | ItemStack itemStack = this.inventoryItemBuilder.getItemStack(inventoryItem.getIcon().getMaterial(), inventoryItem.getIcon().getAmount()); 49 | ItemMeta meta = itemStack.getItemMeta(); 50 | if (meta != null) { 51 | meta.setDisplayName(ChatColorUtil.translate(stringSubstitutor.replace(inventoryItem.getName()))); 52 | if (inventoryItem.getDescription() != null && inventoryItem.getDescription().length != 0) { 53 | meta.setLore(Arrays.stream(inventoryItem.getDescription()) 54 | .map(stringSubstitutor::replace) 55 | .map(ChatColorUtil::translate) 56 | .collect(Collectors.toList()) 57 | ); 58 | } 59 | if (VersionUtil.isCustomModalDataAvailable() && inventoryItem.getIcon().getCustomModelData() != null) { 60 | meta.setCustomModelData(inventoryItem.getIcon().getCustomModelData()); 61 | } 62 | itemStack.setItemMeta(meta); 63 | } 64 | inventory.setItem(inventoryItem.getIndex(), itemStack); 65 | } 66 | 67 | return inventory; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/inventory/InventoryItemBuilder.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.inventory; 2 | 3 | import com.cryptomorin.xseries.XMaterial; 4 | import net.craftingstore.bukkit.CraftingStoreBukkit; 5 | import net.craftingstore.bukkit.util.VersionUtil; 6 | import org.bukkit.Material; 7 | import org.bukkit.inventory.ItemStack; 8 | 9 | import java.util.Optional; 10 | 11 | public class InventoryItemBuilder { 12 | 13 | private CraftingStoreBukkit instance; 14 | 15 | public InventoryItemBuilder(CraftingStoreBukkit instance) { 16 | this.instance = instance; 17 | } 18 | 19 | public ItemStack getItemStack(String material, int amount) { 20 | ItemStack itemStack; 21 | if (VersionUtil.isGuavaAvailable()) { 22 | // 1.8+ 23 | com.cryptomorin.xseries.XMaterial xMaterial; 24 | if (material == null) { 25 | xMaterial = com.cryptomorin.xseries.XMaterial.CHEST; 26 | } else { 27 | Optional xMaterialOptional = com.cryptomorin.xseries.XMaterial.matchXMaterial(material); 28 | if (!xMaterialOptional.isPresent()) { 29 | instance.getCraftingStore().getLogger().debug("Material " + material + " not found."); 30 | xMaterial = com.cryptomorin.xseries.XMaterial.CHEST; 31 | } else { 32 | xMaterial = xMaterialOptional.get(); 33 | } 34 | } 35 | itemStack = xMaterial.parseItem(); 36 | if (itemStack == null) { 37 | itemStack = new ItemStack(Material.CHEST); 38 | } 39 | itemStack.setAmount(amount); 40 | } else { 41 | // 1.7 support 42 | net.craftingstore.bukkit.util.XMaterial xMaterial; 43 | if (material == null) { 44 | xMaterial = net.craftingstore.bukkit.util.XMaterial.CHEST; 45 | } else { 46 | xMaterial = net.craftingstore.bukkit.util.XMaterial.fromString(material); 47 | if (xMaterial == null || xMaterial.parseMaterial() == null) { 48 | instance.getCraftingStore().getLogger().debug("Material " + material + " not found."); 49 | xMaterial = net.craftingstore.bukkit.util.XMaterial.CHEST; 50 | } 51 | } 52 | itemStack = xMaterial.parseItem(amount); 53 | } 54 | return itemStack; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/inventory/InventoryItemHandler.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.inventory; 2 | 3 | import net.craftingstore.core.models.api.inventory.InventoryItem; 4 | import org.bukkit.entity.Player; 5 | 6 | public interface InventoryItemHandler { 7 | void handle(Player p, T item, CraftingStoreInventoryHolder holder); 8 | } 9 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/inventory/handlers/BackButtonHandler.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.inventory.handlers; 2 | 3 | import net.craftingstore.bukkit.inventory.CraftingStoreInventoryHolder; 4 | import net.craftingstore.bukkit.inventory.InventoryBuilder; 5 | import net.craftingstore.bukkit.inventory.InventoryItemHandler; 6 | import net.craftingstore.core.models.api.inventory.types.InventoryItemBackButton; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.inventory.Inventory; 9 | 10 | public class BackButtonHandler implements InventoryItemHandler { 11 | 12 | private InventoryBuilder builder; 13 | 14 | public BackButtonHandler(InventoryBuilder builder) { 15 | this.builder = builder; 16 | } 17 | 18 | @Override 19 | public void handle(Player p, InventoryItemBackButton item, CraftingStoreInventoryHolder holder) { 20 | if (holder.getParentInventory() != null) { 21 | CraftingStoreInventoryHolder parentInventory = holder.getParentInventory(); 22 | Inventory inventory = builder.buildInventory( 23 | parentInventory.getCsInventory(), 24 | new CraftingStoreInventoryHolder(parentInventory.getCsInventory(), parentInventory.getParentInventory()) 25 | ); 26 | p.openInventory(inventory); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/inventory/handlers/BuyablePackageHandler.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.inventory.handlers; 2 | 3 | import net.craftingstore.bukkit.CraftingStoreBukkit; 4 | import net.craftingstore.bukkit.inventory.*; 5 | import net.craftingstore.bukkit.util.ChatColorUtil; 6 | import net.craftingstore.core.models.api.inventory.types.InventoryItemBuyablePackage; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.inventory.Inventory; 9 | 10 | public class BuyablePackageHandler implements InventoryItemHandler { 11 | 12 | private final CraftingStoreBukkit instance; 13 | private final BuyInventoryBuilder buyInventoryBuilder; 14 | 15 | public BuyablePackageHandler(CraftingStoreBukkit instance, BuyInventoryBuilder buyInventoryBuilder) { 16 | this.instance = instance; 17 | this.buyInventoryBuilder = buyInventoryBuilder; 18 | } 19 | 20 | @Override 21 | public void handle(Player p, InventoryItemBuyablePackage item, CraftingStoreInventoryHolder holder) { 22 | if (!this.instance.isHookedWithVault()) { 23 | p.sendMessage(instance.getPrefix() + "CraftingStore is not hooked with Vault!"); 24 | p.closeInventory(); 25 | return; 26 | } 27 | 28 | if (!this.instance.getVaultHook().getEconomy().has(p, item.getPrice())) { 29 | p.sendMessage(ChatColorUtil.translate( 30 | this.instance.getCraftingStore().getImplementation().getConfiguration().getNotEnoughBalanceMessage() 31 | )); 32 | for (String message : item.getMessages()) { 33 | p.sendMessage(ChatColorUtil.translate(message)); 34 | } 35 | p.closeInventory(); 36 | return; 37 | } 38 | 39 | Inventory loading = this.buyInventoryBuilder.buildLoadInventory(); 40 | p.openInventory(loading); 41 | this.instance.getCraftingStore().getImplementation().runAsyncTask(() -> { 42 | try { 43 | Inventory inventory = this.buyInventoryBuilder.build(p, item, holder); 44 | if (inventory != null) { 45 | this.instance.runSyncTask(() -> { 46 | if (p.isOnline()) { 47 | p.openInventory(inventory); 48 | } 49 | }); 50 | } 51 | } catch (Exception exception) { 52 | exception.printStackTrace(); 53 | } 54 | }); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/inventory/handlers/CategoryItemHandler.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.inventory.handlers; 2 | 3 | import net.craftingstore.bukkit.inventory.CraftingStoreInventoryHolder; 4 | import net.craftingstore.bukkit.inventory.InventoryBuilder; 5 | import net.craftingstore.bukkit.inventory.InventoryItemHandler; 6 | import net.craftingstore.core.models.api.inventory.CraftingStoreInventory; 7 | import net.craftingstore.core.models.api.inventory.types.InventoryItemCategory; 8 | import org.bukkit.entity.Player; 9 | import org.bukkit.inventory.Inventory; 10 | 11 | public class CategoryItemHandler implements InventoryItemHandler { 12 | 13 | private InventoryBuilder builder; 14 | 15 | public CategoryItemHandler(InventoryBuilder builder) { 16 | this.builder = builder; 17 | } 18 | 19 | @Override 20 | public void handle(Player p, InventoryItemCategory category, CraftingStoreInventoryHolder holder) { 21 | CraftingStoreInventory csInventory = new CraftingStoreInventory(category.getTitle(), category.getContent(), category.getSize()); 22 | Inventory inventory = builder.buildInventory(csInventory, new CraftingStoreInventoryHolder(csInventory, holder)); 23 | p.openInventory(inventory); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/inventory/handlers/CloseButtonHandler.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.inventory.handlers; 2 | 3 | import net.craftingstore.bukkit.inventory.CraftingStoreInventoryHolder; 4 | import net.craftingstore.bukkit.inventory.InventoryItemHandler; 5 | import net.craftingstore.core.models.api.inventory.types.InventoryItemCloseButton; 6 | import org.bukkit.entity.Player; 7 | 8 | public class CloseButtonHandler implements InventoryItemHandler { 9 | @Override 10 | public void handle(Player p, InventoryItemCloseButton item, CraftingStoreInventoryHolder holder) { 11 | p.closeInventory(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/inventory/handlers/MessageButtonHandler.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.inventory.handlers; 2 | 3 | import net.craftingstore.bukkit.inventory.CraftingStoreInventoryHolder; 4 | import net.craftingstore.bukkit.inventory.InventoryItemHandler; 5 | import net.craftingstore.bukkit.util.ChatColorUtil; 6 | import net.craftingstore.core.models.api.inventory.types.InventoryItemMessage; 7 | import org.bukkit.entity.Player; 8 | 9 | public class MessageButtonHandler implements InventoryItemHandler { 10 | @Override 11 | public void handle(Player p, InventoryItemMessage item, CraftingStoreInventoryHolder holder) { 12 | for (String message : item.getMessages()) { 13 | p.sendMessage(ChatColorUtil.translate(message)); 14 | } 15 | if (item.shouldClose()) { 16 | p.closeInventory(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/listeners/AdminJoinListener.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.listeners; 2 | 3 | import net.craftingstore.bukkit.CraftingStoreBukkit; 4 | import net.craftingstore.core.models.api.misc.CraftingStoreInformation; 5 | import net.craftingstore.core.models.api.misc.UpdateInformation; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.Listener; 9 | import org.bukkit.event.player.PlayerJoinEvent; 10 | 11 | public class AdminJoinListener implements Listener { 12 | 13 | private CraftingStoreBukkit instance; 14 | 15 | public AdminJoinListener(CraftingStoreBukkit instance) { 16 | this.instance = instance; 17 | } 18 | 19 | @EventHandler 20 | public void onPlayerJoin(PlayerJoinEvent e) { 21 | Player p = e.getPlayer(); 22 | if (!p.hasPermission(instance.getCraftingStore().ADMIN_PERMISSION)) { 23 | return; 24 | } 25 | CraftingStoreInformation information = instance.getCraftingStore().getInformation(); 26 | UpdateInformation update = null; 27 | if (information != null) { 28 | update = information.getUpdateInformation(); 29 | 30 | // Update notification 31 | if (update != null) { 32 | p.sendMessage(instance.getPrefix() + update.getMessage()); 33 | } 34 | } 35 | 36 | if (!instance.getCraftingStore().isEnabled()) { 37 | if (update != null && update.shouldDisable()) { 38 | p.sendMessage(instance.getPrefix() + "The CraftingStore plugin has been disabled because this is an outdated version. Please update the plugin."); 39 | } else { 40 | p.sendMessage(instance.getPrefix() + "The CraftingStore plugin has not been set-up correctly. Please set your API key using /craftingstore key ."); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/listeners/InventoryListener.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.listeners; 2 | 3 | import net.craftingstore.bukkit.CraftingStoreBukkit; 4 | import net.craftingstore.bukkit.inventory.BuyInventoryBuilder; 5 | import net.craftingstore.bukkit.inventory.CraftingStoreInventoryHolder; 6 | import net.craftingstore.bukkit.inventory.InventoryBuilder; 7 | import net.craftingstore.bukkit.inventory.InventoryItemHandler; 8 | import net.craftingstore.bukkit.inventory.handlers.*; 9 | import net.craftingstore.core.models.api.inventory.*; 10 | import net.craftingstore.core.models.api.inventory.types.*; 11 | import org.bukkit.entity.Player; 12 | import org.bukkit.event.EventHandler; 13 | import org.bukkit.event.Listener; 14 | import org.bukkit.event.inventory.InventoryClickEvent; 15 | 16 | import java.util.HashMap; 17 | 18 | public class InventoryListener implements Listener { 19 | 20 | private final HashMap, InventoryItemHandler> handlers = new HashMap<>(); 21 | 22 | private final CraftingStoreBukkit instance; 23 | private final InventoryBuilder inventoryBuilder; 24 | 25 | public InventoryListener(CraftingStoreBukkit instance) { 26 | this.instance = instance; 27 | this.inventoryBuilder = new InventoryBuilder(instance); 28 | BuyInventoryBuilder buyInventoryBuilder = new BuyInventoryBuilder(instance, this.inventoryBuilder); 29 | this.handlers.put(InventoryItemBackButton.class, new BackButtonHandler(this.inventoryBuilder)); 30 | this.handlers.put(InventoryItemCategory.class, new CategoryItemHandler(this.inventoryBuilder)); 31 | this.handlers.put(InventoryItemCloseButton.class, new CloseButtonHandler()); 32 | this.handlers.put(InventoryItemMessage.class, new MessageButtonHandler()); 33 | this.handlers.put(InventoryItemBuyablePackage.class, new BuyablePackageHandler( 34 | instance, 35 | buyInventoryBuilder 36 | )); 37 | this.handlers.put(InventoryItemBuyButton.class, new BuyButtonHandler(instance, buyInventoryBuilder)); 38 | } 39 | 40 | @EventHandler 41 | public void onClick(InventoryClickEvent e) { 42 | // Fix "Negative, non outside slot -1" error. 43 | if (e.getRawSlot() < 0) { 44 | return; 45 | } 46 | if (e.getInventory() == null 47 | || e.getInventory().getHolder() == null 48 | || !(e.getInventory().getHolder() instanceof CraftingStoreInventoryHolder)) { 49 | return; 50 | } 51 | e.setCancelled(true); 52 | Player p = (Player) e.getWhoClicked(); 53 | CraftingStoreInventoryHolder holder = (CraftingStoreInventoryHolder) e.getInventory().getHolder(); 54 | InventoryItem item = holder.getCsInventory().getByIndex(e.getRawSlot()); 55 | if (item == null) { 56 | return; 57 | } 58 | 59 | if (handlers.containsKey(item.getClass())) { 60 | handlers.get(item.getClass()).handle(p, item, holder); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/listeners/PendingDonationJoinListener.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.listeners; 2 | 3 | import net.craftingstore.bukkit.CraftingStoreBukkit; 4 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 5 | import net.craftingstore.core.jobs.ProcessPendingPaymentsJob; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.Listener; 9 | import org.bukkit.event.player.PlayerJoinEvent; 10 | 11 | public class PendingDonationJoinListener implements Listener { 12 | 13 | private final CraftingStoreBukkit instance; 14 | 15 | public PendingDonationJoinListener(CraftingStoreBukkit instance) { 16 | this.instance = instance; 17 | } 18 | 19 | @EventHandler 20 | public void onJoin(PlayerJoinEvent e) { 21 | Player p = e.getPlayer(); 22 | String username = p.getName(); 23 | 24 | instance.getCraftingStore().getImplementation().runAsyncTask(() -> { 25 | try { 26 | new ProcessPendingPaymentsJob(instance.getCraftingStore(), username); 27 | } catch (CraftingStoreApiException ex) { 28 | ex.printStackTrace(); 29 | } 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/util/ChatColorUtil.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.util; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | public class ChatColorUtil { 7 | private static final Pattern HEX_PATTERN = Pattern.compile("&#(\\w{5}[0-9a-f])", Pattern.CASE_INSENSITIVE); 8 | 9 | public static String translate(String textToTranslate) { 10 | if (VersionUtil.isHexAvailable()) { 11 | return translateHexCodes(textToTranslate); 12 | } 13 | return org.bukkit.ChatColor.translateAlternateColorCodes('&', textToTranslate); 14 | } 15 | 16 | private static String translateHexCodes(String textToTranslate) { 17 | Matcher matcher = HEX_PATTERN.matcher(textToTranslate); 18 | StringBuffer buffer = new StringBuffer(); 19 | 20 | while (matcher.find()) { 21 | matcher.appendReplacement(buffer, net.md_5.bungee.api.ChatColor.of("#" + matcher.group(1)).toString()); 22 | } 23 | 24 | return net.md_5.bungee.api.ChatColor.translateAlternateColorCodes('&', matcher.appendTail(buffer).toString()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bukkit/src/main/java/net/craftingstore/bukkit/util/VersionUtil.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bukkit.util; 2 | 3 | public class VersionUtil { 4 | private static boolean hexAvailable = false; 5 | private static boolean customModalDataAvailable = false; 6 | private static boolean guavaAvailable = false; 7 | private static boolean foliaSchedulerAvailable = false; 8 | 9 | static { 10 | try { 11 | Class.forName("net.md_5.bungee.api.ChatColor").getMethod("of", String.class); 12 | hexAvailable = true; 13 | } catch (NoSuchMethodException | ClassNotFoundException ignored) { 14 | } 15 | try { 16 | Class.forName("org.bukkit.inventory.meta.ItemMeta").getMethod("hasCustomModelData"); 17 | customModalDataAvailable = true; 18 | } catch (NoSuchMethodException | ClassNotFoundException ignored) { 19 | } 20 | try { 21 | Class.forName("com.google.common.cache.CacheBuilder").getMethod("build"); 22 | guavaAvailable = true; 23 | } catch (NoSuchMethodException | ClassNotFoundException ignored) { 24 | } 25 | try { 26 | Class.forName("org.bukkit.Bukkit").getMethod("getAsyncScheduler"); 27 | foliaSchedulerAvailable = true; 28 | } catch (NoSuchMethodException | ClassNotFoundException ignored) { 29 | } 30 | } 31 | 32 | public static boolean isHexAvailable() { 33 | return hexAvailable; 34 | } 35 | 36 | public static boolean isCustomModalDataAvailable() { 37 | return customModalDataAvailable; 38 | } 39 | 40 | public static boolean isGuavaAvailable() { 41 | return guavaAvailable; 42 | } 43 | 44 | public static boolean isFoliaSchedulerAvailable() { 45 | return foliaSchedulerAvailable; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /bukkit/src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | api-key: '' 2 | disable-buy-command: false -------------------------------------------------------------------------------- /bukkit/src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: CraftingStore 2 | main: net.craftingstore.bukkit.CraftingStoreBukkit 3 | version: ${craftingstore-version} 4 | authors: [Tim_kwakman, thijs_a] 5 | prefix: CraftingStore 6 | softdepend: [PlaceholderAPI, Vault] 7 | api-version: "1.13" 8 | folia-supported: true 9 | commands: 10 | craftingstore: 11 | description: CraftingStore command 12 | aliases: [cs] 13 | csbuy: 14 | description: Buy command 15 | aliases: [buy] -------------------------------------------------------------------------------- /bungee/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | net.craftingstore 9 | craftingstore 10 | ${revision} 11 | 12 | 13 | bungee 14 | 15 | 16 | 17 | 18 | org.apache.maven.plugins 19 | maven-compiler-plugin 20 | 21 | 8 22 | 8 23 | 24 | 25 | 26 | 27 | 28 | src/main/resources 29 | true 30 | 31 | 32 | 33 | 34 | 35 | 36 | bungeecord-repo 37 | https://oss.sonatype.org/content/repositories/snapshots 38 | 39 | 40 | 41 | 42 | 43 | net.craftingstore 44 | core 45 | ${project.version} 46 | 47 | 48 | net.md-5 49 | bungeecord-api 50 | 1.10-SNAPSHOT 51 | provided 52 | 53 | 54 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/craftingstore/bungee/BungeePluginConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bungee; 2 | 3 | import net.craftingstore.core.PluginConfiguration; 4 | 5 | public class BungeePluginConfiguration implements PluginConfiguration { 6 | 7 | private CraftingStoreBungee plugin; 8 | 9 | BungeePluginConfiguration(CraftingStoreBungee plugin) { 10 | this.plugin = plugin; 11 | } 12 | 13 | @Override 14 | public String getName() { 15 | return "BungeeCord"; 16 | } 17 | 18 | @Override 19 | public String[] getMainCommands() { 20 | return new String[]{"csb"}; 21 | } 22 | 23 | @Override 24 | public String getVersion() { 25 | return plugin.getDescription().getVersion(); 26 | } 27 | 28 | @Override 29 | public String getPlatform() { 30 | return plugin.getProxy().getVersion(); 31 | } 32 | 33 | @Override 34 | public boolean isBuyCommandEnabled() { 35 | return false; 36 | } 37 | 38 | @Override 39 | public int getTimeBetweenCommands() { 40 | return plugin.getConfig().getInt("time-between-commands", 200); 41 | } 42 | 43 | @Override 44 | public String getNotEnoughBalanceMessage() { 45 | return null; 46 | } 47 | 48 | @Override 49 | public boolean isUsingAlternativeApi() { 50 | return plugin.getConfig().getBoolean("use-alternative-api", false); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/craftingstore/bungee/CraftingStoreBungee.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bungee; 2 | 3 | import net.craftingstore.bungee.commands.CraftingStoreCommand; 4 | import net.craftingstore.bungee.config.Config; 5 | import net.craftingstore.bungee.listeners.AdminJoinListener; 6 | import net.craftingstore.bungee.listeners.PendingDonationJoinListener; 7 | import net.craftingstore.core.CraftingStore; 8 | import net.md_5.bungee.api.ChatColor; 9 | import net.md_5.bungee.api.plugin.Plugin; 10 | import net.md_5.bungee.config.Configuration; 11 | 12 | public class CraftingStoreBungee extends Plugin { 13 | 14 | private Config config; 15 | private CraftingStore craftingStore; 16 | private String prefix = ChatColor.GRAY + "[" + ChatColor.RED + "CraftingStore" + ChatColor.GRAY + "] " + ChatColor.WHITE; 17 | 18 | @Override 19 | public void onEnable() { 20 | config = new Config(this, "config.yml"); 21 | this.craftingStore = new CraftingStore(new CraftingStoreBungeeImpl(this)); 22 | getProxy().getPluginManager().registerCommand(this, new CraftingStoreCommand(this)); 23 | getProxy().getPluginManager().registerListener(this, new AdminJoinListener(this)); 24 | getProxy().getPluginManager().registerListener(this, new PendingDonationJoinListener(this)); 25 | } 26 | 27 | @Override 28 | public void onDisable() { 29 | craftingStore.setEnabled(false); 30 | } 31 | 32 | public Configuration getConfig() { 33 | return config.getConfig(); 34 | } 35 | 36 | public Config getConfigWrapper() { 37 | return config; 38 | } 39 | 40 | public CraftingStore getCraftingStore() { 41 | return craftingStore; 42 | } 43 | 44 | public String getPrefix() { 45 | return prefix; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/craftingstore/bungee/CraftingStoreBungeeImpl.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bungee; 2 | 3 | import net.craftingstore.bungee.events.DonationReceivedEvent; 4 | import net.craftingstore.core.CraftingStorePlugin; 5 | import net.craftingstore.core.PluginConfiguration; 6 | import net.craftingstore.core.logging.CraftingStoreLogger; 7 | import net.craftingstore.core.logging.impl.JavaLogger; 8 | import net.craftingstore.core.models.donation.Donation; 9 | import net.md_5.bungee.api.ProxyServer; 10 | import net.md_5.bungee.api.connection.ProxiedPlayer; 11 | 12 | import java.util.concurrent.TimeUnit; 13 | 14 | public class CraftingStoreBungeeImpl implements CraftingStorePlugin { 15 | 16 | private CraftingStoreBungee bungeePlugin; 17 | private JavaLogger logger; 18 | private BungeePluginConfiguration configuration; 19 | 20 | CraftingStoreBungeeImpl(CraftingStoreBungee bungeePlugin) { 21 | this.bungeePlugin = bungeePlugin; 22 | this.configuration = new BungeePluginConfiguration(bungeePlugin); 23 | this.logger = new JavaLogger(bungeePlugin.getLogger()); 24 | this.logger.setDebugging(bungeePlugin.getConfig().getBoolean("debug", false)); 25 | } 26 | 27 | public boolean executeDonation(final Donation donation) { 28 | ProxyServer proxy = bungeePlugin.getProxy(); 29 | if (donation.getPlayer().isRequiredOnline()) { 30 | ProxiedPlayer player = proxy.getPlayer(donation.getPlayer().getUsername()); 31 | if (player == null || !player.isConnected()) { 32 | return false; 33 | } 34 | } 35 | 36 | DonationReceivedEvent event = new DonationReceivedEvent(donation); 37 | proxy.getPluginManager().callEvent(event); 38 | if (event.isCancelled()) { 39 | return false; 40 | } 41 | 42 | proxy.getScheduler().runAsync(bungeePlugin, () -> proxy.getPluginManager().dispatchCommand(proxy.getConsole(), donation.getCommand())); 43 | return true; 44 | } 45 | 46 | public CraftingStoreLogger getLogger() { 47 | return this.logger; 48 | } 49 | 50 | public void registerRunnable(Runnable runnable, int delay, int interval) { 51 | bungeePlugin.getProxy().getScheduler().schedule(bungeePlugin, runnable, delay, interval, TimeUnit.SECONDS); 52 | } 53 | 54 | public void runAsyncTask(Runnable runnable) { 55 | bungeePlugin.getProxy().getScheduler().runAsync(bungeePlugin, runnable); 56 | } 57 | 58 | public String getToken() { 59 | return bungeePlugin.getConfig().getString("api-key"); 60 | } 61 | 62 | @Override 63 | public PluginConfiguration getConfiguration() { 64 | return this.configuration; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/craftingstore/bungee/commands/CraftingStoreCommand.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bungee.commands; 2 | 3 | import net.craftingstore.bungee.CraftingStoreBungee; 4 | import net.md_5.bungee.api.ChatColor; 5 | import net.md_5.bungee.api.CommandSender; 6 | import net.md_5.bungee.api.chat.TextComponent; 7 | import net.md_5.bungee.api.plugin.Command; 8 | 9 | import java.util.concurrent.ExecutionException; 10 | 11 | public class CraftingStoreCommand extends Command { 12 | 13 | private CraftingStoreBungee instance; 14 | 15 | public CraftingStoreCommand(CraftingStoreBungee instance) { 16 | super("csb", instance.getCraftingStore().ADMIN_PERMISSION); 17 | this.instance = instance; 18 | } 19 | 20 | @Override 21 | public void execute(CommandSender sender, String[] args) { 22 | if (!sender.hasPermission(instance.getCraftingStore().ADMIN_PERMISSION)) { 23 | sender.sendMessage(new TextComponent(instance.getPrefix() + "You don't have the required permission!")); 24 | return; 25 | } 26 | if (args.length == 1 && args[0].equalsIgnoreCase("reload")) { 27 | instance.getCraftingStore().reload(); 28 | sender.sendMessage(new TextComponent(instance.getPrefix() + "The plugin is reloading!")); 29 | return; 30 | } 31 | if (args.length == 2 && args[0].equalsIgnoreCase("key")) { 32 | instance.getConfig().set("api-key", args[1]); 33 | instance.getConfigWrapper().saveConfig(); 34 | instance.getProxy().getScheduler().runAsync(instance, () -> { 35 | try { 36 | if (instance.getCraftingStore().reload().get()) { 37 | sender.sendMessage(new TextComponent(instance.getPrefix() + "The new API key has been set in the config, and the plugin has been reloaded.")); 38 | } else { 39 | sender.sendMessage(new TextComponent(instance.getPrefix() + "The API key is invalid. The plugin will not work until you set a valid API key.")); 40 | } 41 | } catch (InterruptedException | ExecutionException e) { 42 | e.printStackTrace(); 43 | } 44 | }); 45 | return; 46 | } 47 | if ((args.length == 1 || args.length == 2) && args[0].equalsIgnoreCase("debug")) { 48 | boolean isDebugging = this.instance.getCraftingStore().getLogger().isDebugging(); 49 | if (args.length == 1) { 50 | sender.sendMessage(new TextComponent(String.format( 51 | "%sDebug mode is currently %s.", 52 | this.instance.getPrefix(), 53 | isDebugging ? "enabled" : "disabled" 54 | ))); 55 | return; 56 | } 57 | String debugValue = args[1].toLowerCase(); 58 | if (debugValue.equalsIgnoreCase("true")) { 59 | isDebugging = true; 60 | } else if (debugValue.equalsIgnoreCase("false")) { 61 | isDebugging = false; 62 | } else { 63 | sender.sendMessage(new TextComponent(instance.getPrefix() + "Unknown debug value.")); 64 | return; 65 | } 66 | this.instance.getCraftingStore().getLogger().setDebugging(isDebugging); 67 | instance.getConfig().set("debug", isDebugging); 68 | instance.getConfigWrapper().saveConfig(); 69 | sender.sendMessage(new TextComponent(String.format( 70 | "%sDebug mode has been %s.", 71 | this.instance.getPrefix(), 72 | isDebugging ? "enabled" : "disabled" 73 | ))); 74 | return; 75 | } 76 | 77 | sender.sendMessage(new TextComponent(ChatColor.GRAY + "" + ChatColor.STRIKETHROUGH + "-----------------------")); 78 | sender.sendMessage(new TextComponent(ChatColor.DARK_GRAY + ">" + ChatColor.GRAY + " /csb reload" + ChatColor.DARK_GRAY + " -> " + ChatColor.GRAY + "Reload the config.")); 79 | sender.sendMessage(new TextComponent(ChatColor.DARK_GRAY + ">" + ChatColor.GRAY + " /csb key " + ChatColor.DARK_GRAY + " -> " + ChatColor.GRAY + "Update the key.")); 80 | sender.sendMessage(new TextComponent(ChatColor.GRAY + "" + ChatColor.STRIKETHROUGH + "-----------------------")); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/craftingstore/bungee/config/Config.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bungee.config; 2 | 3 | import net.md_5.bungee.api.plugin.Plugin; 4 | import net.md_5.bungee.config.Configuration; 5 | import net.md_5.bungee.config.ConfigurationProvider; 6 | import net.md_5.bungee.config.YamlConfiguration; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.nio.file.Files; 12 | import java.util.logging.Level; 13 | 14 | public class Config { 15 | 16 | private Plugin instance; 17 | private Configuration configuration; 18 | private String filename; 19 | 20 | public Config(Plugin instance, String filename) { 21 | this.instance = instance; 22 | this.filename = filename; 23 | 24 | instance.getDataFolder().mkdir(); 25 | 26 | File file = new File(instance.getDataFolder(), filename); 27 | if (!file.exists()) { 28 | InputStream is = instance.getResourceAsStream(filename); 29 | if (is != null) { 30 | instance.getLogger().info("Copying default config file."); 31 | try { 32 | Files.copy(is, file.toPath()); 33 | } catch (IOException e) { 34 | instance.getLogger().log(Level.SEVERE, "An error occurred while copying the default config file " + filename + ".", e); 35 | } 36 | } else { 37 | try { 38 | file.createNewFile(); 39 | } catch (IOException e) { 40 | instance.getLogger().log(Level.SEVERE, "An error occurred while creating the config file " + filename + ".", e); 41 | } 42 | } 43 | } 44 | 45 | reload(); 46 | } 47 | 48 | public void reload() { 49 | try { 50 | configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(new File(instance.getDataFolder(), filename)); 51 | } catch (IOException e) { 52 | instance.getLogger().log(Level.SEVERE, "An error occurred while loading the config file " + filename + ".", e); 53 | } 54 | } 55 | 56 | public Configuration getConfig() { 57 | if (configuration == null) { 58 | reload(); 59 | } 60 | return configuration; 61 | } 62 | 63 | public void saveConfig() { 64 | try { 65 | ConfigurationProvider.getProvider(YamlConfiguration.class).save(configuration, new File(instance.getDataFolder(), filename)); 66 | } catch (IOException e) { 67 | instance.getLogger().log(Level.SEVERE, "An error occured while saving the config file " + filename + ".", e); 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/craftingstore/bungee/events/DonationReceivedEvent.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bungee.events; 2 | 3 | import net.craftingstore.core.models.donation.Donation; 4 | import net.md_5.bungee.api.plugin.Cancellable; 5 | import net.md_5.bungee.api.plugin.Event; 6 | 7 | import java.util.UUID; 8 | 9 | public class DonationReceivedEvent extends Event implements Cancellable { 10 | 11 | @Deprecated 12 | private String command; 13 | @Deprecated 14 | private String username; 15 | @Deprecated 16 | private UUID uuid; 17 | @Deprecated 18 | private String packageName; 19 | @Deprecated 20 | private int packagePrice; 21 | @Deprecated 22 | private int couponDiscount; 23 | 24 | private Donation donation; 25 | 26 | private boolean cancelled = false; 27 | 28 | @Deprecated 29 | public DonationReceivedEvent(String command, String username, UUID uuid, String packageName, int packagePrice, int couponDiscount) { 30 | this.command = command; 31 | this.username = username; 32 | this.uuid = uuid; 33 | this.packageName = packageName; 34 | this.packagePrice = packagePrice; 35 | this.couponDiscount = couponDiscount; 36 | } 37 | 38 | public DonationReceivedEvent(Donation donation) { 39 | this.command = donation.getCommand(); 40 | this.username = donation.getPlayer().getUsername(); 41 | this.uuid = donation.getPlayer().getUUID(); 42 | this.packageName = donation.getPackage().getName(); 43 | this.packagePrice = donation.getPackage().getPrice(); 44 | this.couponDiscount = donation.getDiscount(); 45 | this.donation = donation; 46 | } 47 | 48 | public Donation getDonation() { 49 | return this.donation; 50 | } 51 | 52 | @Deprecated 53 | public String getCommand() { 54 | return command; 55 | } 56 | 57 | @Deprecated 58 | public String getUsername() { 59 | return username; 60 | } 61 | 62 | @Deprecated 63 | public UUID getUuid() { 64 | return uuid; 65 | } 66 | 67 | @Deprecated 68 | public String getPackageName() { 69 | return packageName; 70 | } 71 | 72 | @Deprecated 73 | public int getPackagePrice() { 74 | return packagePrice; 75 | } 76 | 77 | @Deprecated 78 | public int getCouponDiscount() { 79 | return couponDiscount; 80 | } 81 | 82 | public boolean isCancelled() { 83 | return cancelled; 84 | } 85 | 86 | public void setCancelled(boolean cancelled) { 87 | this.cancelled = cancelled; 88 | } 89 | } -------------------------------------------------------------------------------- /bungee/src/main/java/net/craftingstore/bungee/listeners/AdminJoinListener.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bungee.listeners; 2 | 3 | import net.craftingstore.bungee.CraftingStoreBungee; 4 | import net.craftingstore.core.models.api.misc.CraftingStoreInformation; 5 | import net.craftingstore.core.models.api.misc.UpdateInformation; 6 | import net.md_5.bungee.api.chat.TextComponent; 7 | import net.md_5.bungee.api.connection.ProxiedPlayer; 8 | import net.md_5.bungee.api.event.PostLoginEvent; 9 | import net.md_5.bungee.api.plugin.Listener; 10 | import net.md_5.bungee.event.EventHandler; 11 | 12 | public class AdminJoinListener implements Listener { 13 | 14 | private CraftingStoreBungee instance; 15 | 16 | public AdminJoinListener(CraftingStoreBungee instance) { 17 | this.instance = instance; 18 | } 19 | 20 | @EventHandler 21 | public void onPostLogin(PostLoginEvent e) { 22 | ProxiedPlayer p = e.getPlayer(); 23 | if (!p.hasPermission(instance.getCraftingStore().ADMIN_PERMISSION)) { 24 | return; 25 | } 26 | CraftingStoreInformation information = instance.getCraftingStore().getInformation(); 27 | UpdateInformation update = null; 28 | if (information != null) { 29 | update = information.getUpdateInformation(); 30 | 31 | // Update notification 32 | if (update != null) { 33 | p.sendMessage(new TextComponent(instance.getPrefix() + update.getMessage())); 34 | } 35 | } 36 | 37 | if (!instance.getCraftingStore().isEnabled()) { 38 | if (update != null && update.shouldDisable()) { 39 | p.sendMessage(new TextComponent(instance.getPrefix() + "The CraftingStore plugin has been disabled because this is an outdated version. Please update the plugin.")); 40 | } else { 41 | p.sendMessage(new TextComponent(instance.getPrefix() + "The CraftingStore plugin has not been set-up correctly. Please set your API key using /csb key .")); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /bungee/src/main/java/net/craftingstore/bungee/listeners/PendingDonationJoinListener.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.bungee.listeners; 2 | 3 | import net.craftingstore.bungee.CraftingStoreBungee; 4 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 5 | import net.craftingstore.core.jobs.ProcessPendingPaymentsJob; 6 | import net.md_5.bungee.api.connection.ProxiedPlayer; 7 | import net.md_5.bungee.api.event.PostLoginEvent; 8 | import net.md_5.bungee.api.plugin.Listener; 9 | import net.md_5.bungee.event.EventHandler; 10 | 11 | public class PendingDonationJoinListener implements Listener { 12 | 13 | private final CraftingStoreBungee instance; 14 | 15 | public PendingDonationJoinListener(CraftingStoreBungee instance) { 16 | this.instance = instance; 17 | } 18 | 19 | @EventHandler 20 | public void onPostLogin(PostLoginEvent e) { 21 | ProxiedPlayer p = e.getPlayer(); 22 | String username = p.getName(); 23 | instance.getCraftingStore().getImplementation().runAsyncTask(() -> { 24 | try { 25 | new ProcessPendingPaymentsJob(instance.getCraftingStore(), username); 26 | } catch (CraftingStoreApiException ex) { 27 | ex.printStackTrace(); 28 | } 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /bungee/src/main/resources/bungee.yml: -------------------------------------------------------------------------------- 1 | name: CraftingStore 2 | main: net.craftingstore.bungee.CraftingStoreBungee 3 | version: ${craftingstore-version} 4 | author: thijs_a 5 | prefix: CraftingStore -------------------------------------------------------------------------------- /core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | net.craftingstore 9 | craftingstore 10 | ${revision} 11 | 12 | 13 | core 14 | 15 | 16 | 17 | 18 | org.apache.maven.plugins 19 | maven-compiler-plugin 20 | 21 | 8 22 | 8 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | jitpack.io 31 | https://jitpack.io 32 | 33 | 34 | 35 | 36 | 37 | com.google.code.gson 38 | gson 39 | 2.8.9 40 | provided 41 | 42 | 43 | com.github.thijsa 44 | socket.io-client-java 45 | 1.0.3 46 | 47 | 48 | org.apache.httpcomponents 49 | httpclient 50 | 4.5.13 51 | 52 | 53 | org.apache.commons 54 | commons-lang3 55 | 3.12.0 56 | 57 | 58 | commons-logging 59 | commons-logging 60 | 1.2 61 | 62 | 63 | org.apache.commons 64 | commons-text 65 | 1.10.0 66 | 67 | 68 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/CraftingStore.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core; 2 | 3 | import net.craftingstore.core.http.CraftingStoreCachedAPI; 4 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 5 | import net.craftingstore.core.jobs.ExecuteDonationsJob; 6 | import net.craftingstore.core.logging.CraftingStoreLogger; 7 | import net.craftingstore.core.models.api.Root; 8 | import net.craftingstore.core.models.api.misc.CraftingStoreInformation; 9 | import net.craftingstore.core.models.api.misc.UpdateInformation; 10 | import net.craftingstore.core.models.donation.Donation; 11 | import net.craftingstore.core.provider.ProviderSelector; 12 | import net.craftingstore.core.runner.DonationRunner; 13 | import net.craftingstore.core.scheduler.*; 14 | 15 | import java.util.ArrayList; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | import java.util.concurrent.ExecutionException; 19 | import java.util.concurrent.ExecutorService; 20 | import java.util.concurrent.Executors; 21 | import java.util.concurrent.Future; 22 | 23 | public class CraftingStore { 24 | 25 | private CraftingStorePlugin plugin; 26 | private CraftingStoreAPI api; 27 | private ProviderSelector selector; 28 | private CraftingStoreInformation information; 29 | private DonationRunner donationRunner; 30 | private boolean enabled = false; 31 | public final String ADMIN_PERMISSION = "craftingstore.admin"; 32 | private ExecutorService executor = Executors.newSingleThreadExecutor(); 33 | private Map pendingDonations; 34 | 35 | public CraftingStore(CraftingStorePlugin implementation) { 36 | this.plugin = implementation; 37 | this.pendingDonations = new HashMap<>(); 38 | this.api = new CraftingStoreCachedAPI(this); 39 | this.selector = new ProviderSelector(this); 40 | this.donationRunner = new DonationRunner(this); 41 | this.getImplementation().runAsyncTask(() -> { 42 | try { 43 | if (this.reload().get()) { 44 | // Every 5 minutes 45 | this.plugin.registerRunnable(new DonationChecker(this), 10, 5 * 60); 46 | // Every minute 47 | this.plugin.registerRunnable(new ProviderChecker(this), 60, 60); 48 | // Every 20 minutes 49 | this.plugin.registerRunnable(new InventoryRenewer(this), 20 * 60, 20 * 60); 50 | // Every 25 minutes 51 | this.plugin.registerRunnable(new APICacheRenewer(this), 10, 60 * 25); 52 | // Every 24 hours 53 | this.plugin.registerRunnable(new InformationUpdater(this), 24 * 60 * 60, 24 * 60 * 60); 54 | } 55 | } catch (InterruptedException | ExecutionException e) { 56 | e.printStackTrace(); 57 | } 58 | }); 59 | } 60 | 61 | public CraftingStorePlugin getImplementation() { 62 | return plugin; 63 | } 64 | 65 | public CraftingStoreAPI getApi() { 66 | return api; 67 | } 68 | 69 | public ProviderSelector getProviderSelector() { 70 | return this.selector; 71 | } 72 | 73 | public CraftingStoreLogger getLogger() { 74 | return getImplementation().getLogger(); 75 | } 76 | 77 | public Future reload() { 78 | this.getApi().setToken(this.getImplementation().getToken()); 79 | return executor.submit(() -> { 80 | try { 81 | if (this.getApi().token == null || this.getApi().token.isEmpty()) { 82 | getLogger().error(String.format( 83 | "API key not set in the config. You need to set the correct api key using /%s key .", 84 | this.getImplementation().getConfiguration().getMainCommands()[0] 85 | )); 86 | setEnabled(false); 87 | return false; 88 | } 89 | Root keyResult = this.getApi().checkKey().get(); 90 | if (!keyResult.isSuccess()) { 91 | getLogger().error("API key is invalid. The plugin will not work."); 92 | setEnabled(false); 93 | return false; 94 | } 95 | information = this.getApi().getInformation().get(); 96 | 97 | if (information.getUpdateInformation() != null) { 98 | UpdateInformation update = information.getUpdateInformation(); 99 | getLogger().info(update.getMessage()); 100 | if (update.shouldDisable()) { 101 | getLogger().error("Plugin will be disabled until you install the latest update."); 102 | setEnabled(false); 103 | return false; 104 | } 105 | } 106 | setEnabled(true); 107 | 108 | selector.setProviders(information.getProviders()); 109 | selector.selectProvider(); 110 | 111 | // Renew the inventory on reload / start 112 | new InventoryRenewer(this).run(); 113 | getLogger().debug("Startup complete"); 114 | } catch (CraftingStoreApiException e) { 115 | e.printStackTrace(); 116 | return false; 117 | } 118 | return true; 119 | }); 120 | } 121 | 122 | public void executeQueue() { 123 | this.donationRunner.runDonations(); 124 | } 125 | 126 | public boolean isEnabled() { 127 | return enabled; 128 | } 129 | 130 | public void setEnabled(boolean enabled) { 131 | this.enabled = enabled; 132 | if (!enabled) { 133 | getProviderSelector().disconnect(); 134 | } 135 | } 136 | 137 | public CraftingStoreInformation getInformation() { 138 | return information; 139 | } 140 | 141 | public Map getPendingDonations() { 142 | return pendingDonations; 143 | } 144 | 145 | public DonationRunner getDonationRunner() { 146 | return donationRunner; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/CraftingStoreAPI.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core; 2 | 3 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 4 | import net.craftingstore.core.models.api.*; 5 | import net.craftingstore.core.models.api.misc.CraftingStoreInformation; 6 | import net.craftingstore.core.models.donation.Donation; 7 | 8 | import java.util.UUID; 9 | import java.util.concurrent.ExecutorService; 10 | import java.util.concurrent.Executors; 11 | import java.util.concurrent.Future; 12 | 13 | public abstract class CraftingStoreAPI { 14 | 15 | protected String token; 16 | protected ExecutorService executor = Executors.newSingleThreadExecutor(); 17 | 18 | public abstract Future getInformation() throws CraftingStoreApiException; 19 | 20 | public abstract Future> checkKey() throws CraftingStoreApiException; 21 | 22 | public abstract Future getDonationQueue() throws CraftingStoreApiException; 23 | 24 | public abstract void completeDonations(int[] ids) throws CraftingStoreApiException; 25 | 26 | public abstract Future getPayments() throws CraftingStoreApiException; 27 | 28 | public abstract Future getGUI() throws CraftingStoreApiException; 29 | 30 | public abstract Future getTopDonators() throws CraftingStoreApiException; 31 | 32 | public abstract Future getPackageInformation( 33 | String inGameName, 34 | UUID uuid, 35 | String ip, 36 | int packageId 37 | ) throws CraftingStoreApiException; 38 | 39 | public abstract Future createPayment( 40 | String inGameName, 41 | int price, 42 | int[] packages 43 | ) throws CraftingStoreApiException; 44 | 45 | public String getToken() { 46 | return this.token; 47 | } 48 | 49 | protected void setToken(String token) { 50 | this.token = token; 51 | } 52 | 53 | public void shutdown() { 54 | executor.shutdown(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/CraftingStorePlugin.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core; 2 | 3 | import net.craftingstore.core.logging.CraftingStoreLogger; 4 | import net.craftingstore.core.models.donation.Donation; 5 | 6 | public interface CraftingStorePlugin { 7 | 8 | boolean executeDonation(Donation donation); 9 | 10 | CraftingStoreLogger getLogger(); 11 | 12 | void registerRunnable(Runnable runnable, int delay, int interval); 13 | 14 | void runAsyncTask(Runnable runnable); 15 | 16 | String getToken(); 17 | 18 | PluginConfiguration getConfiguration(); 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/PluginConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core; 2 | 3 | public interface PluginConfiguration { 4 | String getName(); 5 | 6 | String[] getMainCommands(); 7 | 8 | String getVersion(); 9 | 10 | String getPlatform(); 11 | 12 | boolean isBuyCommandEnabled(); 13 | 14 | int getTimeBetweenCommands(); 15 | 16 | String getNotEnoughBalanceMessage(); 17 | 18 | boolean isUsingAlternativeApi(); 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/exceptions/CraftingStoreApiException.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.exceptions; 2 | 3 | import java.io.IOException; 4 | 5 | public class CraftingStoreApiException extends Exception { 6 | 7 | public CraftingStoreApiException(String s, IOException e) { 8 | super(s, e); 9 | } 10 | 11 | @Override 12 | public void printStackTrace() { 13 | super.getCause().printStackTrace(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/http/CraftingStoreCachedAPI.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.http; 2 | 3 | import net.craftingstore.core.CraftingStore; 4 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 5 | import net.craftingstore.core.models.api.ApiInventory; 6 | import net.craftingstore.core.models.api.ApiPayment; 7 | import net.craftingstore.core.models.api.ApiTopDonator; 8 | 9 | import java.util.HashMap; 10 | import java.util.concurrent.ExecutionException; 11 | import java.util.concurrent.Future; 12 | 13 | public class CraftingStoreCachedAPI extends CraftingStoreAPIImpl { 14 | 15 | private final HashMap cache = new HashMap<>(); 16 | 17 | public CraftingStoreCachedAPI(CraftingStore instance) { 18 | super(instance); 19 | } 20 | 21 | @Override 22 | public Future getGUI() throws CraftingStoreApiException { 23 | return executor.submit(() -> { 24 | String key = "plugin/inventory"; 25 | if (!cache.containsKey(key)) { 26 | cache.put(key, super.getGUI().get()); 27 | } 28 | return (ApiInventory) cache.get(key); 29 | }); 30 | } 31 | 32 | @Override 33 | public Future getTopDonators() throws CraftingStoreApiException { 34 | return executor.submit(() -> { 35 | String key = "buyers/top"; 36 | if (cache.containsKey(key)) { 37 | return (ApiTopDonator[]) cache.get(key); 38 | } 39 | return null; 40 | }); 41 | } 42 | 43 | @Override 44 | public Future getPayments() throws CraftingStoreApiException { 45 | return executor.submit(() -> { 46 | String key = "buyers/recent"; 47 | if (cache.containsKey(key)) { 48 | return (ApiPayment[]) cache.get(key); 49 | } 50 | return null; 51 | }); 52 | } 53 | 54 | public void refreshGUICache() throws CraftingStoreApiException, ExecutionException, InterruptedException { 55 | cache.put("plugin/inventory", super.getGUI().get()); 56 | } 57 | 58 | public void refreshTopDonatorsCache() throws CraftingStoreApiException, ExecutionException, InterruptedException { 59 | cache.put("buyers/top", super.getTopDonators().get()); 60 | } 61 | 62 | public void refreshPaymentsCache() throws CraftingStoreApiException, ExecutionException, InterruptedException { 63 | cache.put("buyers/recent", super.getPayments().get()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/http/util/GenericOf.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.http.util; 2 | 3 | import java.lang.reflect.ParameterizedType; 4 | import java.lang.reflect.Type; 5 | 6 | public class GenericOf implements ParameterizedType { 7 | 8 | private final Class container; 9 | private final Class wrapped; 10 | 11 | public GenericOf(Class container, Class wrapped) { 12 | this.container = container; 13 | this.wrapped = wrapped; 14 | } 15 | 16 | public Type[] getActualTypeArguments() { 17 | return new Type[]{wrapped}; 18 | } 19 | 20 | public Type getRawType() { 21 | return container; 22 | } 23 | 24 | public Type getOwnerType() { 25 | return null; 26 | } 27 | } -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/http/util/InformationAdapter.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.http.util; 2 | 3 | import com.google.gson.*; 4 | import net.craftingstore.core.models.api.provider.ProviderInformation; 5 | import net.craftingstore.core.models.api.provider.ProviderType; 6 | 7 | import java.lang.reflect.Type; 8 | 9 | public class InformationAdapter implements JsonDeserializer { 10 | 11 | public ProviderInformation deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException { 12 | JsonObject jsonObject = jsonElement.getAsJsonObject(); 13 | 14 | JsonPrimitive prim = (JsonPrimitive) jsonObject.get("type"); 15 | ProviderType providerType = ProviderType.valueOf(prim.getAsString()); 16 | Class klass = providerType.getActualClass(); 17 | return context.deserialize(jsonObject, klass); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/http/util/InventoryAdapter.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.http.util; 2 | 3 | import com.google.gson.*; 4 | import net.craftingstore.core.models.api.inventory.InventoryItem; 5 | import net.craftingstore.core.models.api.inventory.InventoryItemType; 6 | 7 | import java.lang.reflect.Type; 8 | 9 | public class InventoryAdapter implements JsonDeserializer { 10 | 11 | public InventoryItem deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 12 | JsonObject jsonObject = json.getAsJsonObject(); 13 | 14 | JsonPrimitive prim = (JsonPrimitive) jsonObject.get("type"); 15 | InventoryItemType itemType = InventoryItemType.valueOf(prim.getAsString()); 16 | Class klass = itemType.getActualClass(); 17 | return context.deserialize(jsonObject, klass); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/http/util/JsonResponseHandler.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.http.util; 2 | 3 | import com.google.gson.Gson; 4 | import net.craftingstore.core.models.api.Root; 5 | import org.apache.http.HttpEntity; 6 | import org.apache.http.HttpResponse; 7 | import org.apache.http.StatusLine; 8 | import org.apache.http.client.ClientProtocolException; 9 | import org.apache.http.client.HttpResponseException; 10 | import org.apache.http.client.ResponseHandler; 11 | import org.apache.http.util.EntityUtils; 12 | 13 | import java.io.IOException; 14 | 15 | public class JsonResponseHandler implements ResponseHandler { 16 | 17 | private Gson gson; 18 | private Class aClass; 19 | 20 | public JsonResponseHandler(Gson gson, Class aClass) { 21 | this.gson = gson; 22 | this.aClass = aClass; 23 | } 24 | 25 | public T handleResponse(HttpResponse response) throws IOException { 26 | StatusLine statusLine = response.getStatusLine(); 27 | HttpEntity entity = response.getEntity(); 28 | 29 | if (statusLine.getStatusCode() >= 300) { 30 | throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); 31 | } 32 | 33 | if (entity == null) { 34 | throw new ClientProtocolException("Response contains no content"); 35 | } 36 | 37 | String value = EntityUtils.toString(entity); 38 | 39 | if (aClass == Root.class) { 40 | return gson.fromJson(value, aClass); 41 | } 42 | Root result = gson.fromJson(value, new GenericOf<>(Root.class, aClass)); 43 | return result.getResult(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/http/util/JsonResponseHandlerV7.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.http.util; 2 | 3 | import com.google.gson.Gson; 4 | import net.craftingstore.core.models.api.RootV7; 5 | import org.apache.http.HttpEntity; 6 | import org.apache.http.HttpResponse; 7 | import org.apache.http.StatusLine; 8 | import org.apache.http.client.ClientProtocolException; 9 | import org.apache.http.client.HttpResponseException; 10 | import org.apache.http.client.ResponseHandler; 11 | import org.apache.http.util.EntityUtils; 12 | 13 | import java.io.IOException; 14 | 15 | public class JsonResponseHandlerV7 implements ResponseHandler { 16 | 17 | private Gson gson; 18 | private Class aClass; 19 | 20 | public JsonResponseHandlerV7(Gson gson, Class aClass) { 21 | this.gson = gson; 22 | this.aClass = aClass; 23 | } 24 | 25 | public T handleResponse(HttpResponse response) throws IOException { 26 | StatusLine statusLine = response.getStatusLine(); 27 | HttpEntity entity = response.getEntity(); 28 | 29 | if (statusLine.getStatusCode() >= 300) { 30 | throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); 31 | } 32 | 33 | if (entity == null) { 34 | throw new ClientProtocolException("Response contains no content"); 35 | } 36 | 37 | String value = EntityUtils.toString(entity); 38 | 39 | if (aClass == RootV7.class) { 40 | return gson.fromJson(value, aClass); 41 | } 42 | RootV7 result = gson.fromJson(value, new GenericOf<>(RootV7.class, aClass)); 43 | return result.getData(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/jobs/ExecuteDonationsJob.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.jobs; 2 | 3 | import net.craftingstore.core.CraftingStore; 4 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 5 | import net.craftingstore.core.models.donation.Donation; 6 | 7 | import java.util.*; 8 | import java.util.stream.Stream; 9 | 10 | public class ExecuteDonationsJob { 11 | 12 | public static final int CHUNK_SIZE = 25; 13 | 14 | private CraftingStore instance; 15 | private Donation[] donations; 16 | 17 | public ExecuteDonationsJob(CraftingStore instance, Donation[] donations) throws CraftingStoreApiException { 18 | this.instance = instance; 19 | this.donations = donations; 20 | this.execute(); 21 | } 22 | 23 | private void execute() throws CraftingStoreApiException { 24 | this.instance.getLogger().debug(String.format("Executing ExecuteDonationsJob for %d donations.", this.donations.length)); 25 | 26 | Map donations = new HashMap<>(); 27 | for (int i = 0; i < this.donations.length; i++) { 28 | Donation donation = this.donations[i]; 29 | this.instance.getLogger().debug(String.format("Executing donation #%d with command id #%d", donation.getPaymentId(), donation.getCommandId())); 30 | this.instance.getLogger().debug(String.format("Command is '%s'", donation.getCommand())); 31 | boolean result = instance.getImplementation().executeDonation(donation); 32 | donations.put(donation, result); 33 | this.instance.getLogger().debug(String.format("Result of execution is %s", result)); 34 | 35 | if (i < (this.donations.length - 1)) { 36 | if (!result) { 37 | this.instance.getLogger().debug("Not delaying command execution because last command did not successfully execute."); 38 | continue; 39 | } 40 | 41 | // Wait x ms before executing the next command, so donations with a lot of commands will not create lag 42 | try { 43 | int waitingTime = this.instance.getImplementation().getConfiguration().getTimeBetweenCommands(); 44 | this.instance.getLogger().debug(String.format("Waiting %dms before executing next donation", waitingTime)); 45 | Thread.sleep(waitingTime); 46 | this.instance.getLogger().debug("Waiting done"); 47 | } catch (InterruptedException e) { 48 | e.printStackTrace(); 49 | } 50 | } 51 | } 52 | 53 | int[] completedIds = donations.entrySet().stream() 54 | .filter(Map.Entry::getValue) 55 | .mapToInt(entry -> entry.getKey().getId()) 56 | .toArray(); 57 | 58 | if (completedIds.length > 0) { 59 | this.instance.getLogger().debug("Marking executed donations as complete."); 60 | instance.getApi().completeDonations(completedIds); 61 | } 62 | 63 | for (Map.Entry entry : donations.entrySet()) { 64 | // Check if the donation has been executed and is in the cache 65 | if (entry.getValue() && instance.getPendingDonations().containsKey(entry.getKey().getId())) { 66 | instance.getPendingDonations().remove(entry.getKey().getId()); 67 | } else if (!entry.getValue()) { 68 | // Add the donation to the list of pending donations so it gets executed when the player gets online. 69 | instance.getPendingDonations().put(entry.getKey().getId(), entry.getKey()); 70 | } 71 | } 72 | this.instance.getLogger().debug("Execution of ExecuteDonationsJob finished."); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/jobs/ProcessPendingPaymentsJob.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.jobs; 2 | 3 | import net.craftingstore.core.CraftingStore; 4 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 5 | import net.craftingstore.core.models.donation.Donation; 6 | 7 | import java.util.Map; 8 | 9 | public class ProcessPendingPaymentsJob { 10 | private CraftingStore instance; 11 | private String username; 12 | 13 | public ProcessPendingPaymentsJob(CraftingStore instance, String username) throws CraftingStoreApiException { 14 | this.instance = instance; 15 | this.username = username; 16 | this.execute(); 17 | } 18 | 19 | private void execute() throws CraftingStoreApiException { 20 | instance.getLogger().debug("Executing ProcessPendingPaymentsJob."); 21 | 22 | Donation[] donations = instance.getPendingDonations().values().stream() 23 | .filter(donation -> donation.getPlayer().getUsername().equals(this.username)) 24 | .toArray(Donation[]::new); 25 | if (donations.length == 0) { 26 | return; 27 | } 28 | 29 | instance.getLogger().debug("Executing pending donations for player " + this.username); 30 | new ExecuteDonationsJob(instance, donations); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/logging/CraftingStoreLogger.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.logging; 2 | 3 | public abstract class CraftingStoreLogger { 4 | 5 | private boolean debugging; 6 | 7 | public abstract void info(String message); 8 | 9 | public abstract void error(String message); 10 | 11 | public void debug(String message) { 12 | if (this.debugging) { 13 | this.info(message); 14 | } 15 | } 16 | 17 | public void setDebugging(boolean debugging) { 18 | this.debugging = debugging; 19 | if (debugging) { 20 | this.debug("Debug logging has been enabled!"); 21 | } 22 | } 23 | 24 | public boolean isDebugging() { 25 | return this.debugging; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/logging/impl/JavaLogger.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.logging.impl; 2 | 3 | import net.craftingstore.core.logging.CraftingStoreLogger; 4 | 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | 8 | public class JavaLogger extends CraftingStoreLogger { 9 | 10 | private Logger logger; 11 | 12 | public JavaLogger(Logger logger) { 13 | this.logger = logger; 14 | } 15 | 16 | public void info(String message) { 17 | logger.info(message); 18 | } 19 | 20 | public void error(String message) { 21 | logger.log(Level.SEVERE, message); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/ApiCategory.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api; 2 | 3 | public class ApiCategory { 4 | 5 | private int id; 6 | private String name; 7 | private String description; 8 | private String minecraftIconName; 9 | private String url; 10 | private Boolean subCategory; 11 | private Package packages[]; 12 | 13 | public int getId() { 14 | return id; 15 | } 16 | 17 | public String getName() { 18 | return name; 19 | } 20 | 21 | public String getDescription() { 22 | return description; 23 | } 24 | 25 | public String getMinecraftIconName() { 26 | return minecraftIconName; 27 | } 28 | 29 | public String getUrl() { 30 | return url; 31 | } 32 | 33 | public Boolean isSubCategory() { 34 | return subCategory; 35 | } 36 | 37 | public Package[] getpackages() { 38 | return packages; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/ApiDonation.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class ApiDonation { 6 | @SerializedName("id") 7 | private int commandId; 8 | private int paymentId; 9 | private String command; 10 | @SerializedName("mcName") 11 | private String username; 12 | private String uuid; 13 | private String packageName; 14 | private boolean requireOnline; 15 | private int packagePriceCents; 16 | private int couponDiscount; 17 | 18 | public int getCommandId() { 19 | return commandId; 20 | } 21 | 22 | public int getPaymentId() { 23 | return paymentId; 24 | } 25 | 26 | public String getCommand() { 27 | return command; 28 | } 29 | 30 | public String getMcName() { 31 | return username; 32 | } 33 | 34 | public String getUuid() { 35 | return uuid; 36 | } 37 | 38 | public String getPackageName() { 39 | return packageName; 40 | } 41 | 42 | public boolean getRequireOnline() { 43 | return requireOnline; 44 | } 45 | 46 | public int getPackagePriceCents() { 47 | return packagePriceCents; 48 | } 49 | 50 | public int getCouponDiscount() { 51 | return couponDiscount; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/ApiInventory.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api; 2 | 3 | import net.craftingstore.core.models.api.inventory.InventoryItem; 4 | 5 | public class ApiInventory { 6 | private String title; 7 | private InventoryItem[] content; 8 | private int size; 9 | private ApiInventory buyMenu; 10 | 11 | public String getTitle() { 12 | return title; 13 | } 14 | 15 | public InventoryItem[] getContent() { 16 | return content; 17 | } 18 | 19 | public int getSize() { 20 | return size; 21 | } 22 | 23 | public ApiInventory getBuyMenu() { 24 | return buyMenu; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/ApiPackageInformation.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api; 2 | 3 | public class ApiPackageInformation { 4 | private boolean mayBuy; 5 | private int price; 6 | private String message; 7 | 8 | public boolean isAllowedToBuy() { 9 | return mayBuy; 10 | } 11 | 12 | public int getPrice() { 13 | return price; 14 | } 15 | 16 | public String getMessage() { 17 | return message; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/ApiPayment.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class ApiPayment { 6 | 7 | @SerializedName("playerName") 8 | private String username; 9 | 10 | private String gateway; 11 | private long timestamp; 12 | private String discount; 13 | private String coupon; 14 | private String price; 15 | 16 | private int packageId; 17 | private String packageName; 18 | 19 | public String getUsername() { 20 | return username; 21 | } 22 | 23 | public String getGateway() { 24 | return gateway; 25 | } 26 | 27 | public long getTimestamp() { 28 | return timestamp; 29 | } 30 | 31 | public String getDiscount() { 32 | return discount; 33 | } 34 | 35 | public String getCoupon() { 36 | return coupon; 37 | } 38 | 39 | public String getPrice() { 40 | return price; 41 | } 42 | 43 | public String getPackageName() { 44 | return packageName; 45 | } 46 | 47 | public int getPackageId() { 48 | return packageId; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/ApiTopDonator.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api; 2 | 3 | public class ApiTopDonator { 4 | 5 | private String mcName; 6 | private float total; 7 | private String uuid; 8 | 9 | public String getUsername() { 10 | return mcName; 11 | } 12 | 13 | public float getTotal() { 14 | return total; 15 | } 16 | 17 | public String getUuid() { 18 | return uuid; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/Root.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api; 2 | 3 | public class Root { 4 | 5 | private T result; 6 | private boolean success; 7 | private int error; 8 | private String message; 9 | 10 | public T getResult() { 11 | return result; 12 | } 13 | 14 | public boolean isSuccess() { 15 | return success; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/RootV7.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api; 2 | 3 | public class RootV7 { 4 | 5 | private T data; 6 | private boolean success; 7 | private String message; 8 | 9 | public T getData() { 10 | return data; 11 | } 12 | 13 | public boolean isSuccess() { 14 | return success; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/inventory/CraftingStoreInventory.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.inventory; 2 | 3 | import java.util.Arrays; 4 | 5 | public class CraftingStoreInventory { 6 | private String title; 7 | private InventoryItem[] content; 8 | private int size; 9 | 10 | public CraftingStoreInventory() { 11 | } 12 | 13 | public CraftingStoreInventory(String title, InventoryItem[] content, int size) { 14 | this.title = title; 15 | this.content = content; 16 | this.size = size; 17 | } 18 | 19 | public String getTitle() { 20 | return title; 21 | } 22 | 23 | public InventoryItem[] getContent() { 24 | return content; 25 | } 26 | 27 | public int getSize() { 28 | return size; 29 | } 30 | 31 | public InventoryItem getByIndex(int index) { 32 | return Arrays.stream(content).filter(i -> i.getIndex() == index).findFirst().orElse(null); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/inventory/InventoryItem.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.inventory; 2 | 3 | public class InventoryItem { 4 | protected String name; 5 | protected String[] description; 6 | protected InventoryItemType type; 7 | protected InventoryItemIcon icon; 8 | protected int index; 9 | 10 | public InventoryItem() { 11 | 12 | } 13 | 14 | public InventoryItem(String name, String[] description, InventoryItemType type, InventoryItemIcon icon, int index) { 15 | this.name = name; 16 | this.description = description; 17 | this.type = type; 18 | this.icon = icon; 19 | this.index = index; 20 | } 21 | 22 | public String getName() { 23 | return name; 24 | } 25 | 26 | public String[] getDescription() { 27 | return description; 28 | } 29 | 30 | public InventoryItemType getType() { 31 | return type; 32 | } 33 | 34 | public InventoryItemIcon getIcon() { 35 | return icon; 36 | } 37 | 38 | public int getIndex() { 39 | return index; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/inventory/InventoryItemEnhancement.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.inventory; 2 | 3 | public class InventoryItemEnhancement { 4 | private String key; 5 | private int level; 6 | 7 | public String getKey() { 8 | return key; 9 | } 10 | 11 | public int getLevel() { 12 | return level; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/inventory/InventoryItemIcon.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.inventory; 2 | 3 | public class InventoryItemIcon { 4 | private String material; 5 | private Integer amount; 6 | private int customModelData; 7 | private InventoryItemEnhancement[] enhancements; 8 | 9 | public InventoryItemIcon() { 10 | } 11 | 12 | public InventoryItemIcon(String material, Integer amount, int customModelData, InventoryItemEnhancement[] enhancements) { 13 | this.material = material; 14 | this.amount = amount; 15 | this.customModelData = customModelData; 16 | this.enhancements = enhancements; 17 | } 18 | 19 | public String getMaterial() { 20 | return material; 21 | } 22 | 23 | public int getAmount() { 24 | return amount; 25 | } 26 | 27 | public Integer getCustomModelData() { 28 | return customModelData; 29 | } 30 | 31 | public InventoryItemEnhancement[] getEnhancements() { 32 | return enhancements; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/inventory/InventoryItemType.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.inventory; 2 | 3 | import net.craftingstore.core.models.api.inventory.types.*; 4 | 5 | public enum InventoryItemType { 6 | NULL(null), 7 | CATEGORY(InventoryItemCategory.class), 8 | MESSAGE(InventoryItemMessage.class), 9 | BACK(InventoryItemBackButton.class), 10 | CLOSE(InventoryItemCloseButton.class), 11 | BUYABLE_PACKAGE(InventoryItemBuyablePackage.class), 12 | BUY_DETAILS(InventoryItemBuyDetails.class), 13 | BUY_BUTTON(InventoryItemBuyButton.class); 14 | 15 | private final Class c; 16 | 17 | InventoryItemType(Class c) { 18 | this.c = c; 19 | } 20 | 21 | public Class getActualClass() { 22 | return c; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/inventory/types/InventoryItemBackButton.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.inventory.types; 2 | 3 | import net.craftingstore.core.models.api.inventory.InventoryItem; 4 | import net.craftingstore.core.models.api.inventory.InventoryItemIcon; 5 | import net.craftingstore.core.models.api.inventory.InventoryItemType; 6 | 7 | public class InventoryItemBackButton extends InventoryItem { 8 | 9 | public InventoryItemBackButton() {} 10 | 11 | public InventoryItemBackButton( 12 | String name, 13 | String[] description, 14 | InventoryItemIcon icon, 15 | int index 16 | ) { 17 | super(name, description, InventoryItemType.BACK, icon, index); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/inventory/types/InventoryItemBuyButton.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.inventory.types; 2 | 3 | import net.craftingstore.core.models.api.inventory.InventoryItem; 4 | import net.craftingstore.core.models.api.inventory.InventoryItemIcon; 5 | import net.craftingstore.core.models.api.inventory.InventoryItemType; 6 | 7 | public class InventoryItemBuyButton extends InventoryItem { 8 | private final InventoryItemBuyButtonAction action; 9 | 10 | public InventoryItemBuyButton( 11 | String name, 12 | String[] description, 13 | InventoryItemIcon icon, 14 | int index, 15 | InventoryItemBuyButtonAction action 16 | ) { 17 | super(name, description, InventoryItemType.BUY_BUTTON, icon, index); 18 | this.action = action; 19 | } 20 | 21 | public InventoryItemBuyButtonAction getAction() { 22 | return action; 23 | } 24 | 25 | public enum InventoryItemBuyButtonAction { 26 | IN_GAME, 27 | ONLINE, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/inventory/types/InventoryItemBuyDetails.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.inventory.types; 2 | 3 | import net.craftingstore.core.models.api.inventory.InventoryItem; 4 | import net.craftingstore.core.models.api.inventory.InventoryItemIcon; 5 | import net.craftingstore.core.models.api.inventory.InventoryItemType; 6 | 7 | public class InventoryItemBuyDetails extends InventoryItem { 8 | 9 | public InventoryItemBuyDetails() {} 10 | 11 | public InventoryItemBuyDetails( 12 | String name, 13 | String[] description, 14 | InventoryItemIcon icon, 15 | int index 16 | ) { 17 | super(name, description, InventoryItemType.BUY_DETAILS, icon, index); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/inventory/types/InventoryItemBuyablePackage.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.inventory.types; 2 | 3 | import net.craftingstore.core.models.api.inventory.InventoryItem; 4 | 5 | public class InventoryItemBuyablePackage extends InventoryItem { 6 | private int price; 7 | private int packageId; 8 | private String[] messages; 9 | private String successMessage; 10 | 11 | public InventoryItemBuyablePackage() { 12 | 13 | } 14 | 15 | public int getPrice() { 16 | return price; 17 | } 18 | 19 | public int getPackageId() { 20 | return packageId; 21 | } 22 | 23 | public String[] getMessages() { 24 | return messages; 25 | } 26 | 27 | public String getSuccessMessage() { 28 | return successMessage; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/inventory/types/InventoryItemCategory.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.inventory.types; 2 | 3 | import net.craftingstore.core.models.api.inventory.InventoryItem; 4 | 5 | public class InventoryItemCategory extends InventoryItem { 6 | private String title; 7 | private InventoryItem[] content; 8 | private int size; 9 | 10 | public String getTitle() { 11 | return title; 12 | } 13 | 14 | public InventoryItem[] getContent() { 15 | return content; 16 | } 17 | 18 | public int getSize() { 19 | return size; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/inventory/types/InventoryItemCloseButton.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.inventory.types; 2 | 3 | import net.craftingstore.core.models.api.inventory.InventoryItem; 4 | 5 | public class InventoryItemCloseButton extends InventoryItem { 6 | } 7 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/inventory/types/InventoryItemMessage.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.inventory.types; 2 | 3 | import net.craftingstore.core.models.api.inventory.InventoryItem; 4 | import net.craftingstore.core.models.api.inventory.InventoryItemIcon; 5 | import net.craftingstore.core.models.api.inventory.InventoryItemType; 6 | 7 | public class InventoryItemMessage extends InventoryItem { 8 | private String[] messages; 9 | private boolean close; 10 | 11 | public InventoryItemMessage() { 12 | } 13 | 14 | public InventoryItemMessage( 15 | String name, 16 | String[] description, 17 | InventoryItemIcon icon, 18 | int index, 19 | String[] messages, 20 | boolean close 21 | ) { 22 | super(name, description, InventoryItemType.MESSAGE, icon, index); 23 | this.messages = messages; 24 | this.close = close; 25 | } 26 | 27 | public String[] getMessages() { 28 | return messages; 29 | } 30 | 31 | public boolean shouldClose() { 32 | return close; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/misc/ApiKeyResult.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.misc; 2 | 3 | public class ApiKeyResult { 4 | 5 | private boolean success; 6 | 7 | public boolean isSuccess() { 8 | return success; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/misc/CraftingStoreInformation.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.misc; 2 | 3 | import net.craftingstore.core.models.api.provider.ProviderInformation; 4 | 5 | public class CraftingStoreInformation { 6 | 7 | private UpdateInformation update; 8 | private ProviderInformation[] providers; 9 | 10 | public UpdateInformation getUpdateInformation() { 11 | return update; 12 | } 13 | 14 | public ProviderInformation[] getProviders() { 15 | return providers; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/misc/UpdateInformation.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.misc; 2 | 3 | public class UpdateInformation { 4 | 5 | private String message; 6 | private boolean disable; 7 | 8 | public String getMessage() { 9 | return message; 10 | } 11 | 12 | public boolean shouldDisable() { 13 | return disable; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/provider/ProviderInformation.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.provider; 2 | 3 | public class ProviderInformation { 4 | 5 | private ProviderType type; 6 | private int priority; 7 | 8 | public ProviderType getType() { 9 | return type; 10 | } 11 | 12 | public int getPriority() { 13 | return priority; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/provider/ProviderType.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.provider; 2 | 3 | import net.craftingstore.core.provider.CraftingStoreProvider; 4 | import net.craftingstore.core.provider.SocketProvider; 5 | 6 | public enum ProviderType { 7 | SOCKET(SocketProviderInformation.class, SocketProvider.class); 8 | 9 | private Class c; 10 | private Class implementation; 11 | 12 | ProviderType(Class c, Class implementation) { 13 | this.c = c; 14 | this.implementation = implementation; 15 | } 16 | 17 | public Class getActualClass() { 18 | return c; 19 | } 20 | 21 | public Class getImplementation() { 22 | return implementation; 23 | } 24 | } -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/provider/SocketProviderInformation.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.provider; 2 | 3 | public class SocketProviderInformation extends ProviderInformation { 4 | 5 | private String url; 6 | 7 | public String getUrl() { 8 | return url; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/request/PackageInformationRequest.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.request; 2 | 3 | import java.io.Serializable; 4 | 5 | public class PackageInformationRequest implements Serializable { 6 | String inGameName; 7 | String uuid; 8 | String ip; 9 | int packageId; 10 | 11 | public PackageInformationRequest(String inGameName, String uuid, String ip, int packageId) { 12 | this.inGameName = inGameName; 13 | this.uuid = uuid; 14 | this.ip = ip; 15 | this.packageId = packageId; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/api/request/PaymentCreateRequest.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.api.request; 2 | 3 | public class PaymentCreateRequest { 4 | String inGameName; 5 | String notes; 6 | String gateway; 7 | int inGamePricePaid; 8 | Integer pricePaid; 9 | boolean executeCommands; 10 | int[] packages; 11 | 12 | public PaymentCreateRequest( 13 | String inGameName, 14 | String notes, 15 | String gateway, 16 | int inGamePricePaid, 17 | Integer pricePaid, 18 | boolean executeCommands, 19 | int[] packages 20 | ) { 21 | this.inGameName = inGameName; 22 | this.notes = notes; 23 | this.gateway = gateway; 24 | this.inGamePricePaid = inGamePricePaid; 25 | this.pricePaid = pricePaid; 26 | this.executeCommands = executeCommands; 27 | this.packages = packages; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/donation/Donation.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.donation; 2 | 3 | public class Donation { 4 | 5 | private int commandId; 6 | private int paymentId; 7 | private String command; 8 | private DonationPlayer player; 9 | private DonationPackage donationPackage; 10 | private int discount; 11 | 12 | public Donation(int commandId, int paymentId, String command, DonationPlayer player, DonationPackage donationPackage, int discount) { 13 | this.commandId = commandId; 14 | this.paymentId = paymentId; 15 | this.command = command; 16 | this.player = player; 17 | this.donationPackage = donationPackage; 18 | this.discount = discount; 19 | } 20 | 21 | @Deprecated 22 | public int getId() { 23 | return commandId; 24 | } 25 | 26 | public int getCommandId() { 27 | return commandId; 28 | } 29 | 30 | public int getPaymentId() { 31 | return paymentId; 32 | } 33 | 34 | public String getCommand() { 35 | return command; 36 | } 37 | 38 | public DonationPlayer getPlayer() { 39 | return player; 40 | } 41 | 42 | public DonationPackage getPackage() { 43 | return donationPackage; 44 | } 45 | 46 | public int getDiscount() { 47 | return discount; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/donation/DonationPackage.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.donation; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class DonationPackage { 6 | 7 | private String name; 8 | private int priceInCents; 9 | 10 | public DonationPackage(String name, int priceInCents) { 11 | this.name = name; 12 | this.priceInCents = priceInCents; 13 | } 14 | 15 | public String getName() { 16 | return this.name; 17 | } 18 | 19 | @Deprecated 20 | public int getPrice() { 21 | return (int) Math.round(this.priceInCents / 100d); 22 | } 23 | 24 | public BigDecimal getPriceDecimal() { 25 | return BigDecimal.valueOf(this.priceInCents / 100d); 26 | } 27 | 28 | public int getPriceInCents() { 29 | return this.priceInCents; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/models/donation/DonationPlayer.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.models.donation; 2 | 3 | import java.util.UUID; 4 | 5 | public class DonationPlayer { 6 | 7 | private String username; 8 | private UUID uuid; 9 | private boolean requiredOnline; 10 | 11 | public DonationPlayer(String username, String uuid, boolean requiredOnline) { 12 | this.username = username; 13 | this.requiredOnline = requiredOnline; 14 | if (uuid != null && !uuid.isEmpty()) { 15 | uuid = uuid.replaceFirst("([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)", "$1-$2-$3-$4-$5"); 16 | this.uuid = UUID.fromString(uuid); 17 | } 18 | } 19 | 20 | public String getUsername() { 21 | return username; 22 | } 23 | 24 | public UUID getUUID() { 25 | return uuid; 26 | } 27 | 28 | public boolean isRequiredOnline() { 29 | return requiredOnline; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/provider/CraftingStoreProvider.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.provider; 2 | 3 | import net.craftingstore.core.CraftingStore; 4 | import net.craftingstore.core.models.api.provider.ProviderInformation; 5 | 6 | public abstract class CraftingStoreProvider { 7 | 8 | CraftingStore craftingStore; 9 | ProviderInformation information; 10 | ProviderStatus status; 11 | 12 | public CraftingStoreProvider(CraftingStore craftingStore, ProviderStatus status) { 13 | this.craftingStore = craftingStore; 14 | this.status = status; 15 | this.information = status.getInformation(); 16 | } 17 | 18 | public abstract boolean isConnected(); 19 | 20 | public abstract void disconnect(); 21 | 22 | public void disconnected() { 23 | craftingStore.getLogger().debug("Disconnected from provider " + information.getType()); 24 | if (!craftingStore.isEnabled()) { 25 | return; 26 | } 27 | this.status.setRetries(this.status.getRetries() + 1); 28 | this.status.setLastFailed(System.currentTimeMillis()); 29 | this.craftingStore.getProviderSelector().selectProvider(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/provider/ProviderSelector.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.provider; 2 | 3 | import net.craftingstore.core.CraftingStore; 4 | import net.craftingstore.core.models.api.provider.ProviderInformation; 5 | 6 | import java.lang.reflect.Constructor; 7 | import java.lang.reflect.InvocationTargetException; 8 | import java.util.Arrays; 9 | import java.util.Comparator; 10 | import java.util.List; 11 | import java.util.function.Function; 12 | import java.util.stream.Collectors; 13 | 14 | public class ProviderSelector { 15 | 16 | private CraftingStore instance; 17 | private ProviderStatus[] providers; 18 | private CraftingStoreProvider currentProvider; 19 | 20 | public ProviderSelector(CraftingStore instance) { 21 | this.instance = instance; 22 | } 23 | 24 | public void setProviders(ProviderStatus[] providers) { 25 | this.providers = providers; 26 | } 27 | 28 | public void setProviders(ProviderInformation[] providers) { 29 | this.providers = Arrays.stream(providers) 30 | .map((Function) ProviderStatus::new) 31 | .toArray(ProviderStatus[]::new); 32 | } 33 | 34 | public void selectProvider() { 35 | if (currentProvider != null && currentProvider.isConnected()) { 36 | currentProvider.disconnect(); 37 | return; 38 | } 39 | currentProvider = getAvailableProvider(); 40 | } 41 | 42 | private CraftingStoreProvider getAvailableProvider() { 43 | long disallowedRange = System.currentTimeMillis() - (1000 * 60); // 1 minute 44 | List availableProviders = Arrays.stream(providers) 45 | .filter(p -> p.getLastFailed() < disallowedRange) 46 | .sorted(Comparator.comparingInt(p -> p.getInformation().getPriority())) 47 | .collect(Collectors.toList()); 48 | if (availableProviders.size() == 0) { 49 | instance.getLogger().debug("No providers available"); 50 | return null; 51 | } 52 | ProviderStatus status = availableProviders.get(0); 53 | Class implementation = status.getInformation().getType().getImplementation(); 54 | try { 55 | Constructor ctor = implementation.getConstructor(CraftingStore.class, ProviderStatus.class); 56 | return (CraftingStoreProvider) ctor.newInstance(instance, status); 57 | } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) { 58 | e.printStackTrace(); 59 | } 60 | return null; 61 | } 62 | 63 | public CraftingStoreProvider getCurrentProvider() { 64 | return currentProvider; 65 | } 66 | 67 | public boolean isConnected() { 68 | return getCurrentProvider() != null && getCurrentProvider().isConnected(); 69 | } 70 | 71 | public void disconnect() { 72 | if (isConnected()) { 73 | getCurrentProvider().disconnect(); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/provider/ProviderStatus.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.provider; 2 | 3 | import net.craftingstore.core.models.api.provider.ProviderInformation; 4 | 5 | public class ProviderStatus { 6 | private ProviderInformation information; 7 | private long lastFailed; 8 | private int retries; 9 | 10 | public ProviderStatus(ProviderInformation information) { 11 | this.information = information; 12 | } 13 | 14 | public long getLastFailed() { 15 | return lastFailed; 16 | } 17 | 18 | public void setLastFailed(long lastFailed) { 19 | this.lastFailed = lastFailed; 20 | } 21 | 22 | public int getRetries() { 23 | return retries; 24 | } 25 | 26 | public void setRetries(int retries) { 27 | this.retries = retries; 28 | } 29 | 30 | public ProviderInformation getInformation() { 31 | return information; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/provider/SocketProvider.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.provider; 2 | 3 | import io.socket.client.IO; 4 | import io.socket.client.Socket; 5 | import net.craftingstore.core.CraftingStore; 6 | import net.craftingstore.core.models.api.provider.SocketProviderInformation; 7 | 8 | import java.net.URISyntaxException; 9 | 10 | public class SocketProvider extends CraftingStoreProvider { 11 | 12 | private Socket client; 13 | private static final long DISABLE_TIMEOUT = 5 * 1000; 14 | 15 | public SocketProvider(CraftingStore craftingStore, ProviderStatus status) { 16 | super(craftingStore, status); 17 | this.connect(); 18 | } 19 | 20 | @Override 21 | public boolean isConnected() { 22 | return client != null && client.connected(); 23 | } 24 | 25 | @Override 26 | public void disconnect() { 27 | if (client != null) { 28 | client.disconnect(); 29 | // Let the current thread wait until disconnected, to prevent the server from killing the threads. 30 | try { 31 | long disconnectStart = System.currentTimeMillis(); 32 | while (client.connected()) { 33 | Thread.sleep(5); 34 | if (System.currentTimeMillis() - disconnectStart > DISABLE_TIMEOUT) { 35 | break; 36 | } 37 | } 38 | // Wait some time on SocketIO 39 | Thread.sleep(200); 40 | } catch (InterruptedException e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | } 45 | 46 | private void connect() { 47 | SocketProviderInformation information = (SocketProviderInformation) this.information; 48 | try { 49 | IO.Options options = new IO.Options(); 50 | options.reconnection = false; 51 | this.client = IO.socket(information.getUrl(), options); 52 | 53 | // Authenticate 54 | this.client.on(Socket.EVENT_CONNECT, (Object... args) -> { 55 | craftingStore.getLogger().debug("Socket server connected, sending authentication token"); 56 | this.client.emit("auth-client", this.craftingStore.getApi().getToken()); 57 | }); 58 | this.client.on(Socket.EVENT_DISCONNECT, (Object... args) -> { 59 | craftingStore.getLogger().debug("Socket server disconnected, reason: " + args[0]); 60 | this.disconnected(); 61 | }); 62 | this.client.on(Socket.EVENT_CONNECT_ERROR, (Object... args) -> { 63 | craftingStore.getLogger().debug("Socket server connect error event called"); 64 | this.disconnected(); 65 | if (!craftingStore.getLogger().isDebugging()) { 66 | return; 67 | } 68 | for (Object arg : args) { 69 | if (arg instanceof Exception) { 70 | ((Exception) arg).printStackTrace(); 71 | } 72 | } 73 | }); 74 | this.client.on("authenticated", (Object... args) -> { 75 | craftingStore.getLogger().debug("Socket server authenticated"); 76 | }); 77 | 78 | this.client.on("receive-donation", (Object... args) -> { 79 | craftingStore.getLogger().debug("Received donation from Socket server"); 80 | this.craftingStore.executeQueue(); 81 | }); 82 | this.client.on("reload-plugin", (Object... args) -> this.craftingStore.reload()); 83 | this.client.on("disable-plugin", (Object... args) -> { 84 | if (args.length > 0) { 85 | craftingStore.getLogger().error(args[0].toString()); 86 | } 87 | this.craftingStore.setEnabled(false); 88 | }); 89 | this.client.on(Socket.EVENT_ERROR, (Object... args) -> { 90 | craftingStore.getLogger().debug("Socket error event called"); 91 | if (!craftingStore.getLogger().isDebugging()) { 92 | return; 93 | } 94 | for (Object arg : args) { 95 | if (arg instanceof Exception) { 96 | ((Exception) arg).printStackTrace(); 97 | } 98 | } 99 | }); 100 | this.client.on(Socket.EVENT_RECONNECT, (Object... args) -> { 101 | craftingStore.getLogger().debug("Socket reconnect event called"); 102 | }); 103 | this.client.on(Socket.EVENT_MESSAGE, (Object... args) -> { 104 | craftingStore.getLogger().debug("Socket message event called"); 105 | }); 106 | this.client.connect(); 107 | craftingStore.getLogger().debug("Connecting to CraftingStore websocket at " + information.getUrl()); 108 | } catch (URISyntaxException e) { 109 | e.printStackTrace(); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/runner/DonationRunner.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.runner; 2 | 3 | import net.craftingstore.core.CraftingStore; 4 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 5 | import net.craftingstore.core.jobs.ExecuteDonationsJob; 6 | import net.craftingstore.core.models.donation.Donation; 7 | import net.craftingstore.core.util.ArrayUtil; 8 | 9 | import java.util.Arrays; 10 | import java.util.List; 11 | import java.util.concurrent.ExecutionException; 12 | import java.util.concurrent.ExecutorService; 13 | import java.util.concurrent.Executors; 14 | import java.util.stream.Stream; 15 | 16 | public class DonationRunner { 17 | 18 | protected ExecutorService executor = Executors.newSingleThreadExecutor(); 19 | protected CraftingStore craftingStore; 20 | 21 | public DonationRunner(CraftingStore craftingStore) { 22 | this.craftingStore = craftingStore; 23 | } 24 | 25 | public void runDonations() { 26 | this.craftingStore.getLogger().debug("Scheduling new donation runner job."); 27 | this.executor.submit(() -> { 28 | this.craftingStore.getLogger().debug("Requesting donation queue."); 29 | try { 30 | Donation[] donationQueue = this.craftingStore.getApi().getDonationQueue().get(); 31 | this.craftingStore.getLogger().debug(String.format("Found %d donations in queue.", donationQueue.length)); 32 | Donation[][] chunked = ArrayUtil.splitArray(donationQueue, ExecuteDonationsJob.CHUNK_SIZE); 33 | for (int i = 0; i < chunked.length; i++) { 34 | Donation[] chunk = chunked[i]; 35 | this.craftingStore.getLogger().debug(String.format("Creating ExecuteDonationsJob for chunk %d/%d", i + 1, chunked.length)); 36 | new ExecuteDonationsJob(this.craftingStore, chunk); 37 | } 38 | } catch (CraftingStoreApiException | InterruptedException | ExecutionException e) { 39 | if (craftingStore.getLogger().isDebugging()) { 40 | e.printStackTrace(); 41 | } else { 42 | craftingStore.getLogger().info("Failed to retrieve donation. The plugin will retry every 30 minutes."); 43 | } 44 | } 45 | }); 46 | } 47 | 48 | public ExecutorService getExecutor() { 49 | return executor; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/scheduler/APICacheRenewer.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.scheduler; 2 | 3 | import net.craftingstore.core.CraftingStore; 4 | import net.craftingstore.core.http.CraftingStoreCachedAPI; 5 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 6 | 7 | import java.util.concurrent.ExecutionException; 8 | 9 | public class APICacheRenewer implements Runnable { 10 | 11 | private CraftingStore instance; 12 | 13 | public APICacheRenewer(CraftingStore instance) { 14 | this.instance = instance; 15 | } 16 | 17 | 18 | @Override 19 | public void run() { 20 | if (!instance.isEnabled()) { 21 | return; 22 | } 23 | if (!(instance.getApi() instanceof CraftingStoreCachedAPI)) { 24 | return; 25 | } 26 | CraftingStoreCachedAPI api = (CraftingStoreCachedAPI) instance.getApi(); 27 | this.instance.getLogger().debug("Refreshing API cache."); 28 | try { 29 | api.refreshPaymentsCache(); 30 | api.refreshTopDonatorsCache(); 31 | } catch (CraftingStoreApiException | ExecutionException | InterruptedException e) { 32 | if (this.instance.getLogger().isDebugging()) { 33 | e.printStackTrace(); 34 | } else { 35 | instance.getLogger().error("Failed to renew API cache. If this issue persists, please contact support at https://craftingstore.net."); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/scheduler/DonationChecker.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.scheduler; 2 | 3 | import net.craftingstore.core.CraftingStore; 4 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 5 | import net.craftingstore.core.jobs.ExecuteDonationsJob; 6 | import net.craftingstore.core.models.donation.Donation; 7 | import net.craftingstore.core.util.ArrayUtil; 8 | 9 | import java.util.Arrays; 10 | import java.util.concurrent.ExecutionException; 11 | 12 | public class DonationChecker implements Runnable { 13 | 14 | private CraftingStore instance; 15 | private long lastRun = 0; 16 | 17 | public DonationChecker(CraftingStore instance) { 18 | this.instance = instance; 19 | } 20 | 21 | public void run() { 22 | if (!instance.isEnabled()) { 23 | return; 24 | } 25 | if (instance.getProviderSelector().isConnected()) { 26 | // Only run this runnable every 30 minutes when we are connected to a websocket. 27 | long target = System.currentTimeMillis() - (30 * 60 * 1000); 28 | if (lastRun > target) { 29 | return; 30 | } 31 | } 32 | lastRun = System.currentTimeMillis(); 33 | this.instance.getLogger().debug("Checking for donations by interval."); 34 | this.instance.getDonationRunner().runDonations(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/scheduler/InformationUpdater.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.scheduler; 2 | 3 | import net.craftingstore.core.CraftingStore; 4 | 5 | public class InformationUpdater implements Runnable { 6 | 7 | private CraftingStore instance; 8 | 9 | public InformationUpdater(CraftingStore instance) { 10 | this.instance = instance; 11 | } 12 | 13 | public void run() { 14 | this.instance.getLogger().debug("Reloading plugin"); 15 | instance.reload(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/scheduler/InventoryRenewer.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.scheduler; 2 | 3 | import net.craftingstore.core.CraftingStore; 4 | import net.craftingstore.core.http.CraftingStoreCachedAPI; 5 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 6 | 7 | import java.util.concurrent.ExecutionException; 8 | 9 | public class InventoryRenewer implements Runnable { 10 | 11 | private CraftingStore instance; 12 | 13 | public InventoryRenewer(CraftingStore instance) { 14 | this.instance = instance; 15 | } 16 | 17 | @Override 18 | public void run() { 19 | if (!instance.isEnabled()) { 20 | return; 21 | } 22 | if (!(instance.getApi() instanceof CraftingStoreCachedAPI)) { 23 | return; 24 | } 25 | CraftingStoreCachedAPI api = (CraftingStoreCachedAPI) instance.getApi(); 26 | instance.getLogger().debug("Refreshing GUI cache."); 27 | try { 28 | api.refreshGUICache(); 29 | } catch (CraftingStoreApiException | ExecutionException | InterruptedException e) { 30 | if (instance.getLogger().isDebugging()) { 31 | e.printStackTrace(); 32 | } else { 33 | instance.getLogger().error("Failed to renew GUI cache. If this issue persists, please contact support at https://craftingstore.net."); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/scheduler/ProviderChecker.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.scheduler; 2 | 3 | import net.craftingstore.core.CraftingStore; 4 | 5 | public class ProviderChecker implements Runnable { 6 | 7 | private CraftingStore instance; 8 | 9 | public ProviderChecker(CraftingStore instance) { 10 | this.instance = instance; 11 | } 12 | 13 | @Override 14 | public void run() { 15 | if (!instance.isEnabled()) { 16 | return; 17 | } 18 | if (instance.getProviderSelector().getCurrentProvider() == null || 19 | !instance.getProviderSelector().getCurrentProvider().isConnected()) { 20 | instance.getLogger().debug("Reconnecting to a provider."); 21 | instance.getProviderSelector().selectProvider(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/net/craftingstore/core/util/ArrayUtil.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.core.util; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.Arrays; 5 | 6 | public class ArrayUtil { 7 | 8 | public static T[][] splitArray(T[] arrayToSplit, int chunkSize) { 9 | if (chunkSize <= 0) { 10 | return (T[][]) Array.newInstance(arrayToSplit.getClass(), 0); 11 | } 12 | int rest = arrayToSplit.length % chunkSize; 13 | int chunks = arrayToSplit.length / chunkSize + (rest > 0 ? 1 : 0); 14 | T[][] arrays = (T[][]) Array.newInstance(arrayToSplit.getClass(), chunks); 15 | 16 | for (int i = 0; i < (rest > 0 ? chunks - 1 : chunks); i++) { 17 | arrays[i] = Arrays.copyOfRange(arrayToSplit, i * chunkSize, i * chunkSize + chunkSize); 18 | } 19 | if (rest > 0) { 20 | arrays[chunks - 1] = Arrays.copyOfRange(arrayToSplit, (chunks - 1) * chunkSize, (chunks - 1) * chunkSize + rest); 21 | } 22 | return arrays; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | net.craftingstore 8 | craftingstore 9 | pom 10 | ${revision} 11 | 12 | 13 | ${craftingstore-version}-RELEASE 14 | 2.10.0 15 | 16 | 17 | 18 | 19 | 20 | org.codehaus.mojo 21 | flatten-maven-plugin 22 | 1.1.0 23 | 24 | true 25 | resolveCiFriendliesOnly 26 | 27 | 28 | 29 | flatten 30 | process-resources 31 | 32 | flatten 33 | 34 | 35 | 36 | flatten.clean 37 | clean 38 | 39 | clean 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | core 49 | bukkit 50 | bungee 51 | sponge 52 | assembly 53 | velocity 54 | 55 | -------------------------------------------------------------------------------- /sponge/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | net.craftingstore 9 | craftingstore 10 | ${revision} 11 | 12 | 13 | sponge 14 | 15 | 16 | 17 | 18 | org.apache.maven.plugins 19 | maven-compiler-plugin 20 | 21 | 8 22 | 8 23 | 24 | 25 | 26 | 27 | 28 | src/main/java 29 | true 30 | 31 | 32 | 33 | 34 | 35 | 36 | sponge 37 | https://repo.spongepowered.org/maven 38 | 39 | 40 | 41 | 42 | 43 | net.craftingstore 44 | core 45 | ${project.version} 46 | 47 | 48 | 49 | org.spongepowered 50 | spongeapi 51 | 7.1.0 52 | provided 53 | 54 | 55 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/CraftingStoreSponge.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge; 2 | 3 | import com.google.inject.Inject; 4 | import com.google.inject.Injector; 5 | import net.craftingstore.core.CraftingStore; 6 | import net.craftingstore.sponge.commands.BuyCommand; 7 | import net.craftingstore.sponge.commands.CraftingStoreCommand; 8 | import net.craftingstore.sponge.config.Config; 9 | import net.craftingstore.sponge.listeners.InventoryClickListener; 10 | import net.craftingstore.sponge.listeners.PendingDonationJoinListener; 11 | import net.craftingstore.sponge.module.ConfigModule; 12 | import net.craftingstore.sponge.module.CraftingStoreModule; 13 | import org.spongepowered.api.Game; 14 | import org.spongepowered.api.command.args.GenericArguments; 15 | import org.spongepowered.api.command.spec.CommandSpec; 16 | import org.spongepowered.api.config.DefaultConfig; 17 | import org.spongepowered.api.event.Listener; 18 | import org.spongepowered.api.event.game.state.GameStartedServerEvent; 19 | import org.spongepowered.api.event.game.state.GameStoppedServerEvent; 20 | import org.spongepowered.api.plugin.Plugin; 21 | import org.spongepowered.api.text.LiteralText; 22 | import org.spongepowered.api.text.Text; 23 | import org.spongepowered.api.text.format.TextColors; 24 | 25 | import java.nio.file.Path; 26 | 27 | @Plugin(id = "craftingstore", name = "CraftingStore") 28 | public class CraftingStoreSponge { 29 | private CraftingStore craftingStore; 30 | 31 | @Inject 32 | private Game game; 33 | 34 | @Inject 35 | private Injector injector; 36 | 37 | @Inject 38 | @DefaultConfig(sharedRoot = false) 39 | private Path defaultConfig; 40 | 41 | private Config config; 42 | 43 | private LiteralText prefix = Text.builder("[").color(TextColors.GRAY) 44 | .append(Text.builder("CraftingStore").color(TextColors.RED).build()) 45 | .append(Text.builder("] ").color(TextColors.WHITE).build()).build(); 46 | 47 | @Listener 48 | public void onServerStart(GameStartedServerEvent event) { 49 | config = new Config(defaultConfig.toFile(), "config.yml"); 50 | injector = injector.createChildInjector(new ConfigModule(config)); 51 | 52 | this.craftingStore = new CraftingStore(injector.getInstance(CraftingStoreSpongeImpl.class)); 53 | injector = injector.createChildInjector(new CraftingStoreModule(craftingStore)); 54 | 55 | CommandSpec craftingStoreCommand = CommandSpec.builder() 56 | .description(Text.of("CraftingStore main command")) 57 | .permission(craftingStore.ADMIN_PERMISSION) 58 | .arguments( 59 | GenericArguments.optional(GenericArguments.string(Text.of("action"))), 60 | GenericArguments.optional(GenericArguments.string(Text.of("key"))) 61 | ) 62 | .executor(injector.getInstance(CraftingStoreCommand.class)) 63 | .build(); 64 | 65 | CommandSpec buyCommand = CommandSpec.builder() 66 | .description(Text.of("CraftingStore buy command")) 67 | .executor(injector.getInstance(BuyCommand.class)) 68 | .build(); 69 | game.getCommandManager().register(this, craftingStoreCommand, "craftingstore", "cs"); 70 | if (this.craftingStore.getImplementation().getConfiguration().isBuyCommandEnabled()) { 71 | game.getCommandManager().register(this, buyCommand, "buy"); 72 | } 73 | 74 | game.getEventManager().registerListeners(this, injector.getInstance(InventoryClickListener.class)); 75 | game.getEventManager().registerListeners(this, injector.getInstance(PendingDonationJoinListener.class)); 76 | } 77 | 78 | @Listener 79 | public void onServerStopped(GameStoppedServerEvent event) { 80 | if (this.craftingStore == null) { 81 | return; 82 | } 83 | this.craftingStore.setEnabled(false); 84 | } 85 | 86 | public Config getConfigWrapper() { 87 | return config; 88 | } 89 | 90 | public LiteralText getPrefix() { 91 | return prefix; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/CraftingStoreSpongeImpl.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge; 2 | 3 | import com.google.inject.Inject; 4 | import net.craftingstore.core.CraftingStorePlugin; 5 | import net.craftingstore.core.PluginConfiguration; 6 | import net.craftingstore.core.logging.CraftingStoreLogger; 7 | import net.craftingstore.core.models.donation.Donation; 8 | import net.craftingstore.sponge.config.Config; 9 | import net.craftingstore.sponge.events.DonationReceivedEvent; 10 | import net.craftingstore.sponge.logging.Slf4jLogger; 11 | import org.spongepowered.api.Game; 12 | import org.spongepowered.api.Platform; 13 | import org.spongepowered.api.Sponge; 14 | import org.spongepowered.api.entity.living.player.Player; 15 | import org.spongepowered.api.plugin.PluginContainer; 16 | 17 | import java.util.concurrent.TimeUnit; 18 | 19 | public class CraftingStoreSpongeImpl implements CraftingStorePlugin { 20 | 21 | @Inject 22 | private CraftingStoreSponge spongePlugin; 23 | 24 | @Inject 25 | private Game game; 26 | 27 | @Inject 28 | private Config config; 29 | 30 | @Inject 31 | private SpongePluginConfiguration configuration; 32 | 33 | private Slf4jLogger logger; 34 | 35 | @Inject 36 | private void setLogger(Slf4jLogger logger) { 37 | this.logger = logger; 38 | this.logger.setDebugging(this.config.getConfig().getNode("debug").getBoolean()); 39 | } 40 | 41 | public boolean executeDonation(Donation donation) { 42 | if (donation.getPlayer().isRequiredOnline()) { 43 | Player player = game.getServer().getPlayer(donation.getPlayer().getUsername()).orElse(null); 44 | if (player == null || !player.isOnline()) { 45 | return false; 46 | } 47 | } 48 | 49 | DonationReceivedEvent event = new DonationReceivedEvent(donation); 50 | game.getEventManager().post(event); 51 | if (event.isCancelled()) { 52 | return false; 53 | } 54 | 55 | game.getScheduler().createTaskBuilder() 56 | .execute(() -> game.getCommandManager().process(game.getServer().getConsole(), donation.getCommand())) 57 | .submit(spongePlugin); 58 | return true; 59 | } 60 | 61 | public CraftingStoreLogger getLogger() { 62 | return this.logger; 63 | } 64 | 65 | public void registerRunnable(Runnable runnable, int delay, int interval) { 66 | game.getScheduler().createTaskBuilder() 67 | .execute(runnable) 68 | .async() 69 | .delay(delay, TimeUnit.SECONDS) 70 | .interval(interval, TimeUnit.SECONDS) 71 | .submit(spongePlugin); 72 | } 73 | 74 | public void runAsyncTask(Runnable runnable) { 75 | game.getScheduler().createTaskBuilder() 76 | .execute(runnable) 77 | .async() 78 | .submit(spongePlugin); 79 | } 80 | 81 | public String getToken() { 82 | return config.getConfig().getNode("api-key").getString(); 83 | } 84 | 85 | @Override 86 | public PluginConfiguration getConfiguration() { 87 | return this.configuration; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/SpongePluginConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge; 2 | 3 | import com.google.inject.Inject; 4 | import net.craftingstore.core.PluginConfiguration; 5 | import org.spongepowered.api.Game; 6 | import org.spongepowered.api.Platform; 7 | import org.spongepowered.api.plugin.PluginContainer; 8 | 9 | public class SpongePluginConfiguration implements PluginConfiguration { 10 | 11 | @Inject 12 | private Game game; 13 | 14 | @Inject 15 | private PluginContainer pluginContainer; 16 | 17 | @Inject 18 | private CraftingStoreSponge craftingStoreSponge; 19 | 20 | @Override 21 | public String getName() { 22 | return "Sponge"; 23 | } 24 | 25 | @Override 26 | public String[] getMainCommands() { 27 | return new String[]{"craftingstore", "cs"}; 28 | } 29 | 30 | @Override 31 | public String getVersion() { 32 | return pluginContainer.getVersion().orElse("unknown-version"); 33 | } 34 | 35 | @Override 36 | public String getPlatform() { 37 | return "sponge/" 38 | + game.getPlatform().getContainer(Platform.Component.API).getVersion().orElse("unknown") 39 | + "/" + game.getPlatform().getContainer(Platform.Component.IMPLEMENTATION).getVersion().orElse("unknown"); 40 | } 41 | 42 | @Override 43 | public boolean isBuyCommandEnabled() { 44 | return !craftingStoreSponge.getConfigWrapper().getConfig().getNode("disable-buy-command").getBoolean(false); 45 | } 46 | 47 | @Override 48 | public int getTimeBetweenCommands() { 49 | return craftingStoreSponge.getConfigWrapper().getConfig().getNode("time-between-commands").getInt(200); 50 | } 51 | 52 | @Override 53 | public String getNotEnoughBalanceMessage() { 54 | return null; 55 | } 56 | 57 | @Override 58 | public boolean isUsingAlternativeApi() { 59 | return craftingStoreSponge.getConfigWrapper().getConfig().getNode("use-alternative-api").getBoolean(false); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/commands/BuyCommand.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.commands; 2 | 3 | import com.google.inject.Inject; 4 | import net.craftingstore.core.CraftingStore; 5 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 6 | import net.craftingstore.core.models.api.ApiInventory; 7 | import net.craftingstore.core.models.api.inventory.CraftingStoreInventory; 8 | import net.craftingstore.sponge.CraftingStoreSponge; 9 | import net.craftingstore.sponge.inventory.InventoryBuilder; 10 | import org.spongepowered.api.Game; 11 | import org.spongepowered.api.command.CommandException; 12 | import org.spongepowered.api.command.CommandResult; 13 | import org.spongepowered.api.command.CommandSource; 14 | import org.spongepowered.api.command.args.CommandContext; 15 | import org.spongepowered.api.command.spec.CommandExecutor; 16 | import org.spongepowered.api.entity.living.player.Player; 17 | import org.spongepowered.api.item.inventory.Inventory; 18 | import org.spongepowered.api.text.Text; 19 | 20 | import javax.annotation.Nonnull; 21 | import java.util.concurrent.ExecutionException; 22 | 23 | public class BuyCommand implements CommandExecutor { 24 | 25 | @Inject 26 | private CraftingStore craftingStore; 27 | 28 | @Inject 29 | private CraftingStoreSponge spongePlugin; 30 | 31 | @Inject 32 | private Game game; 33 | 34 | @Inject 35 | private InventoryBuilder inventoryBuilder; 36 | 37 | @Override 38 | public CommandResult execute(@Nonnull CommandSource src, @Nonnull CommandContext args) throws CommandException { 39 | if (!(src instanceof Player)) { 40 | throw new CommandException(Text.of("You can only execute this command as a player")); 41 | } 42 | Player p = (Player) src; 43 | 44 | game.getScheduler().createTaskBuilder() 45 | .execute(() -> { 46 | try { 47 | ApiInventory gui = craftingStore.getApi().getGUI().get(); 48 | CraftingStoreInventory craftingStoreInventory = new CraftingStoreInventory(gui.getTitle(), gui.getContent(), gui.getSize()); 49 | Inventory inventory = this.inventoryBuilder.buildInventory(craftingStoreInventory); 50 | game.getScheduler().createTaskBuilder() 51 | .execute(() -> { 52 | if (p.isOnline()) { 53 | p.openInventory(inventory); 54 | } 55 | }) 56 | .submit(spongePlugin); 57 | } catch (InterruptedException | ExecutionException | CraftingStoreApiException e) { 58 | e.printStackTrace(); 59 | } 60 | }) 61 | .async() 62 | .submit(spongePlugin); 63 | 64 | return CommandResult.success(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/commands/CraftingStoreCommand.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.commands; 2 | 3 | import com.google.inject.Inject; 4 | import net.craftingstore.core.CraftingStore; 5 | import net.craftingstore.sponge.CraftingStoreSponge; 6 | import org.spongepowered.api.Game; 7 | import org.spongepowered.api.command.CommandResult; 8 | import org.spongepowered.api.command.CommandSource; 9 | import org.spongepowered.api.command.args.CommandContext; 10 | import org.spongepowered.api.command.spec.CommandExecutor; 11 | import org.spongepowered.api.text.Text; 12 | import org.spongepowered.api.text.format.TextColors; 13 | import org.spongepowered.api.text.format.TextStyles; 14 | 15 | import javax.annotation.Nonnull; 16 | import java.util.Optional; 17 | import java.util.concurrent.ExecutionException; 18 | 19 | public class CraftingStoreCommand implements CommandExecutor { 20 | 21 | @Inject 22 | private CraftingStore craftingStore; 23 | 24 | @Inject 25 | private CraftingStoreSponge spongePlugin; 26 | 27 | @Inject 28 | private Game game; 29 | 30 | @Override 31 | public CommandResult execute(@Nonnull CommandSource src, @Nonnull CommandContext args) { 32 | Optional action = args.getOne("action"); 33 | Optional key = args.getOne("key"); 34 | 35 | if (action.isPresent() && action.get().equalsIgnoreCase("reload")) { 36 | craftingStore.reload(); 37 | 38 | src.sendMessage(spongePlugin.getPrefix().toBuilder() 39 | .append(Text.builder("The plugin is reloading!").build()) 40 | .build()); 41 | 42 | return CommandResult.success(); 43 | } else if (action.isPresent() && key.isPresent() && action.get().equalsIgnoreCase("key")) { 44 | spongePlugin.getConfigWrapper().getConfig().getNode("api-key").setValue(key.get()); 45 | spongePlugin.getConfigWrapper().saveConfig(); 46 | 47 | game.getScheduler().createTaskBuilder().execute(() -> { 48 | try { 49 | if (craftingStore.reload().get()) { 50 | src.sendMessage(spongePlugin.getPrefix().toBuilder() 51 | .append(Text.builder("The new API key has been set in the config, and the plugin has been reloaded.").build()) 52 | .build()); 53 | } else { 54 | src.sendMessage(spongePlugin.getPrefix().toBuilder() 55 | .append(Text.builder("The API key is invalid. The plugin will not work until you set a valid API key.").build()) 56 | .build()); 57 | } 58 | } catch (InterruptedException | ExecutionException e) { 59 | e.printStackTrace(); 60 | } 61 | }).async().submit(spongePlugin); 62 | return CommandResult.success(); 63 | } 64 | 65 | src.sendMessage(Text.builder("-----------------------").color(TextColors.GRAY).style(TextStyles.STRIKETHROUGH).build()); 66 | src.sendMessage(Text.builder("> ").color(TextColors.DARK_GRAY) 67 | .append(Text.builder("/cs reload").color(TextColors.GRAY).build()) 68 | .append(Text.builder(" -> ").color(TextColors.DARK_GRAY).build()) 69 | .append(Text.builder("Reload the config.").color(TextColors.GRAY).build()) 70 | .build() 71 | ); 72 | 73 | src.sendMessage(Text.builder("> ").color(TextColors.DARK_GRAY) 74 | .append(Text.builder("/cs key ").color(TextColors.GRAY).build()) 75 | .append(Text.builder(" -> ").color(TextColors.DARK_GRAY).build()) 76 | .append(Text.builder("Update the key.").color(TextColors.GRAY).build()) 77 | .build() 78 | ); 79 | src.sendMessage(Text.builder("-----------------------").color(TextColors.GRAY).style(TextStyles.STRIKETHROUGH).build()); 80 | 81 | return CommandResult.success(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/config/Config.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.config; 2 | 3 | import ninja.leaping.configurate.ConfigurationNode; 4 | import ninja.leaping.configurate.yaml.YAMLConfigurationLoader; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.nio.file.Files; 9 | 10 | public class Config extends File { 11 | 12 | private final YAMLConfigurationLoader loader; 13 | private ConfigurationNode config; 14 | 15 | /** 16 | * Create a new instance of Config, specifying a file name and Plugin. 17 | * 18 | * @param name the file name, including .yml 19 | */ 20 | public Config(File dir, String name) { 21 | super(dir, name); 22 | 23 | if (!dir.exists()) { 24 | dir.mkdirs(); 25 | } 26 | 27 | if (!exists()) { 28 | try { 29 | if (getClass().getClassLoader().getResource(name) != null) { 30 | Files.copy(getClass().getClassLoader().getResourceAsStream(name), toPath()); 31 | } else { 32 | createNewFile(); 33 | } 34 | } catch (IOException e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | 39 | loader = YAMLConfigurationLoader.builder().setFile(this).build(); 40 | 41 | try { 42 | config = loader.load(); 43 | } catch (IOException e) { 44 | e.printStackTrace(); 45 | } 46 | } 47 | 48 | public ConfigurationNode getConfig() { 49 | return this.config; 50 | } 51 | 52 | /** 53 | * Save all changes to the disk. 54 | */ 55 | public void saveConfig() { 56 | try { 57 | loader.save(config); 58 | } catch (IOException e) { 59 | e.printStackTrace(); 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/events/DonationReceivedEvent.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.events; 2 | 3 | import net.craftingstore.core.models.donation.Donation; 4 | import org.spongepowered.api.event.Cancellable; 5 | import org.spongepowered.api.event.cause.Cause; 6 | import org.spongepowered.api.event.impl.AbstractEvent; 7 | 8 | import java.util.UUID; 9 | 10 | public class DonationReceivedEvent extends AbstractEvent implements Cancellable { 11 | 12 | @Deprecated 13 | private String command; 14 | @Deprecated 15 | private String username; 16 | @Deprecated 17 | private UUID uuid; 18 | @Deprecated 19 | private String packageName; 20 | @Deprecated 21 | private int packagePrice; 22 | @Deprecated 23 | private int couponDiscount; 24 | 25 | private Donation donation; 26 | 27 | private boolean cancelled = false; 28 | 29 | @Deprecated 30 | public DonationReceivedEvent(String command, String username, UUID uuid, String packageName, int packagePrice, int couponDiscount) { 31 | this.command = command; 32 | this.username = username; 33 | this.uuid = uuid; 34 | this.packageName = packageName; 35 | this.packagePrice = packagePrice; 36 | this.couponDiscount = couponDiscount; 37 | } 38 | 39 | public DonationReceivedEvent(Donation donation) { 40 | this.command = donation.getCommand(); 41 | this.username = donation.getPlayer().getUsername(); 42 | this.uuid = donation.getPlayer().getUUID(); 43 | this.packageName = donation.getPackage().getName(); 44 | this.packagePrice = donation.getPackage().getPrice(); 45 | this.couponDiscount = donation.getDiscount(); 46 | this.donation = donation; 47 | } 48 | 49 | @Deprecated 50 | public String getCommand() { 51 | return command; 52 | } 53 | 54 | @Deprecated 55 | public String getUsername() { 56 | return username; 57 | } 58 | 59 | @Deprecated 60 | public UUID getUuid() { 61 | return uuid; 62 | } 63 | 64 | @Deprecated 65 | public String getPackageName() { 66 | return packageName; 67 | } 68 | 69 | @Deprecated 70 | public int getPackagePrice() { 71 | return packagePrice; 72 | } 73 | 74 | @Deprecated 75 | public int getCouponDiscount() { 76 | return couponDiscount; 77 | } 78 | 79 | public Donation getDonation() { 80 | return donation; 81 | } 82 | 83 | @Override 84 | public boolean isCancelled() { 85 | return this.cancelled; 86 | } 87 | 88 | @Override 89 | public void setCancelled(boolean cancel) { 90 | this.cancelled = cancel; 91 | } 92 | 93 | @Override 94 | public Cause getCause() { 95 | return null; 96 | } 97 | } -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/inventory/CraftingStoreInventoryProperty.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.inventory; 2 | 3 | import org.spongepowered.api.data.Property; 4 | import org.spongepowered.api.item.inventory.property.AbstractInventoryProperty; 5 | 6 | public class CraftingStoreInventoryProperty extends AbstractInventoryProperty { 7 | 8 | public CraftingStoreInventoryProperty(InventoryAttachment inventoryAttachment) { 9 | super(inventoryAttachment); 10 | } 11 | 12 | @Override 13 | public int compareTo(Property o) { 14 | return 0; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/inventory/InventoryAttachment.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.inventory; 2 | 3 | import net.craftingstore.core.models.api.inventory.CraftingStoreInventory; 4 | 5 | public class InventoryAttachment { 6 | 7 | private CraftingStoreInventory csInventory; 8 | private InventoryAttachment parent; 9 | 10 | 11 | public InventoryAttachment(CraftingStoreInventory csInventory, InventoryAttachment parent) { 12 | this.csInventory = csInventory; 13 | this.parent = parent; 14 | } 15 | 16 | public CraftingStoreInventory getCsInventory() { 17 | return csInventory; 18 | } 19 | 20 | public InventoryAttachment getParent() { 21 | return parent; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/inventory/InventoryBuilder.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.inventory; 2 | 3 | import com.google.inject.Inject; 4 | import net.craftingstore.core.models.api.inventory.CraftingStoreInventory; 5 | import net.craftingstore.core.models.api.inventory.InventoryItem; 6 | import net.craftingstore.sponge.CraftingStoreSponge; 7 | import org.spongepowered.api.GameRegistry; 8 | import org.spongepowered.api.data.key.Keys; 9 | import org.spongepowered.api.item.ItemType; 10 | import org.spongepowered.api.item.ItemTypes; 11 | import org.spongepowered.api.item.inventory.Inventory; 12 | import org.spongepowered.api.item.inventory.ItemStack; 13 | import org.spongepowered.api.item.inventory.property.InventoryDimension; 14 | import org.spongepowered.api.item.inventory.property.InventoryTitle; 15 | import org.spongepowered.api.item.inventory.query.QueryOperationTypes; 16 | import org.spongepowered.api.item.inventory.type.GridInventory; 17 | import org.spongepowered.api.text.Text; 18 | import org.spongepowered.api.text.serializer.TextSerializers; 19 | 20 | import java.util.Arrays; 21 | import java.util.Optional; 22 | import java.util.stream.Collectors; 23 | 24 | public class InventoryBuilder { 25 | 26 | @Inject 27 | private CraftingStoreSponge spongePlugin; 28 | 29 | @Inject 30 | private GameRegistry gameRegistry; 31 | 32 | public Inventory buildInventory(CraftingStoreInventory csInventory) { 33 | return buildInventory(csInventory, null); 34 | } 35 | 36 | public Inventory buildInventory(CraftingStoreInventory csInventory, InventoryAttachment parent) { 37 | String title = csInventory.getTitle(); 38 | if (title == null || title.isEmpty()) { 39 | title = "CraftingStore"; 40 | } 41 | Text formattedTitle = TextSerializers.FORMATTING_CODE.deserialize(title).toText(); 42 | 43 | InventoryAttachment attachment = new InventoryAttachment(csInventory, parent); 44 | int width = 9; 45 | int height = csInventory.getSize() / 9; 46 | 47 | Inventory inventory = Inventory.builder() 48 | .property(new CraftingStoreInventoryProperty(attachment)) 49 | .property(InventoryTitle.of(formattedTitle)) 50 | .property(InventoryDimension.of(width, height)) 51 | .build(this.spongePlugin); 52 | 53 | GridInventory grid = inventory.query(QueryOperationTypes.INVENTORY_TYPE.of(GridInventory.class)); 54 | for (InventoryItem inventoryItem : csInventory.getContent()) { 55 | ItemType type = ItemTypes.CHEST; 56 | if (inventoryItem.getIcon().getMaterial() != null) { 57 | Optional oType = gameRegistry.getType(ItemType.class, inventoryItem.getIcon().getMaterial()); 58 | if (oType.isPresent()) { 59 | type = oType.get(); 60 | } 61 | } 62 | ItemStack stack = ItemStack.builder() 63 | .itemType(type) 64 | .quantity(inventoryItem.getIcon().getAmount()) 65 | .build(); 66 | 67 | Text itemName = TextSerializers.FORMATTING_CODE.deserialize(inventoryItem.getName()).toText(); 68 | stack.offer(Keys.DISPLAY_NAME, itemName); 69 | if (inventoryItem.getDescription() != null && inventoryItem.getDescription().length != 0) { 70 | stack.offer(Keys.ITEM_LORE, Arrays.stream(inventoryItem.getDescription()) 71 | .map(d -> TextSerializers.FORMATTING_CODE.deserialize(d).toText()) 72 | .collect(Collectors.toList())); 73 | } 74 | int x = inventoryItem.getIndex() % 9; 75 | int y = inventoryItem.getIndex() / 9; 76 | grid.set(x, y, stack); 77 | } 78 | 79 | return inventory; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/inventory/InventoryItemHandler.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.inventory; 2 | 3 | import net.craftingstore.core.models.api.inventory.InventoryItem; 4 | import org.spongepowered.api.entity.living.player.Player; 5 | 6 | public interface InventoryItemHandler { 7 | void handle(Player p, T item, InventoryAttachment attachment); 8 | } 9 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/inventory/handlers/BackButtonHandler.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.inventory.handlers; 2 | 3 | import com.google.inject.Inject; 4 | import net.craftingstore.core.models.api.inventory.types.InventoryItemBackButton; 5 | import net.craftingstore.sponge.inventory.InventoryAttachment; 6 | import net.craftingstore.sponge.inventory.InventoryBuilder; 7 | import net.craftingstore.sponge.inventory.InventoryItemHandler; 8 | import org.spongepowered.api.entity.living.player.Player; 9 | import org.spongepowered.api.item.inventory.Inventory; 10 | 11 | public class BackButtonHandler implements InventoryItemHandler { 12 | 13 | @Inject 14 | private InventoryBuilder inventoryBuilder; 15 | 16 | @Override 17 | public void handle(Player p, InventoryItemBackButton item, InventoryAttachment attachment) { 18 | if (attachment.getParent() != null) { 19 | Inventory inventory = inventoryBuilder.buildInventory(attachment.getParent().getCsInventory(), attachment.getParent().getParent()); 20 | p.openInventory(inventory); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/inventory/handlers/CategoryItemHandler.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.inventory.handlers; 2 | 3 | import com.google.inject.Inject; 4 | import net.craftingstore.core.models.api.inventory.CraftingStoreInventory; 5 | import net.craftingstore.core.models.api.inventory.types.InventoryItemCategory; 6 | import net.craftingstore.sponge.inventory.InventoryAttachment; 7 | import net.craftingstore.sponge.inventory.InventoryBuilder; 8 | import net.craftingstore.sponge.inventory.InventoryItemHandler; 9 | import org.spongepowered.api.entity.living.player.Player; 10 | import org.spongepowered.api.item.inventory.Inventory; 11 | 12 | public class CategoryItemHandler implements InventoryItemHandler { 13 | 14 | @Inject 15 | private InventoryBuilder inventoryBuilder; 16 | 17 | @Override 18 | public void handle(Player p, InventoryItemCategory item, InventoryAttachment attachment) { 19 | CraftingStoreInventory csInventory = new CraftingStoreInventory(item.getTitle(), item.getContent(), item.getSize()); 20 | Inventory inventory = inventoryBuilder.buildInventory(csInventory, attachment); 21 | p.openInventory(inventory); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/inventory/handlers/CloseButtonHandler.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.inventory.handlers; 2 | 3 | import net.craftingstore.core.models.api.inventory.types.InventoryItemCloseButton; 4 | import net.craftingstore.sponge.inventory.InventoryAttachment; 5 | import net.craftingstore.sponge.inventory.InventoryItemHandler; 6 | import org.spongepowered.api.entity.living.player.Player; 7 | 8 | public class CloseButtonHandler implements InventoryItemHandler { 9 | 10 | @Override 11 | public void handle(Player p, InventoryItemCloseButton item, InventoryAttachment attachment) { 12 | p.closeInventory(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/inventory/handlers/MessageButtonHandler.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.inventory.handlers; 2 | 3 | import net.craftingstore.core.models.api.inventory.types.InventoryItemMessage; 4 | import net.craftingstore.sponge.inventory.InventoryAttachment; 5 | import net.craftingstore.sponge.inventory.InventoryItemHandler; 6 | import org.spongepowered.api.entity.living.player.Player; 7 | import org.spongepowered.api.text.Text; 8 | import org.spongepowered.api.text.action.TextActions; 9 | import org.spongepowered.api.text.serializer.TextSerializers; 10 | 11 | import java.net.MalformedURLException; 12 | import java.net.URL; 13 | 14 | public class MessageButtonHandler implements InventoryItemHandler { 15 | @Override 16 | public void handle(Player p, InventoryItemMessage item, InventoryAttachment attachment) { 17 | for (String message : item.getMessages()) { 18 | Text text = TextSerializers.FORMATTING_CODE.deserialize(message); 19 | String url = null; 20 | if (message.contains("http://")) { 21 | url = message.substring(message.indexOf("http")); 22 | } 23 | if (message.contains("https://")) { 24 | url = message.substring(message.indexOf("https")); 25 | } 26 | if (url != null) { 27 | if (url.contains(" ")) { 28 | url = url.substring(0, url.indexOf(" ")); 29 | } 30 | try { 31 | text = Text.builder() 32 | .append(text) 33 | .onClick(TextActions.openUrl(new URL(url))) 34 | .build(); 35 | } catch (MalformedURLException e) { 36 | // Do nothing when url is invalid 37 | } 38 | } 39 | p.sendMessage(text); 40 | } 41 | if (item.shouldClose()) { 42 | p.closeInventory(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/listeners/InventoryClickListener.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.listeners; 2 | 3 | import com.google.inject.Inject; 4 | import net.craftingstore.core.models.api.inventory.CraftingStoreInventory; 5 | import net.craftingstore.core.models.api.inventory.InventoryItem; 6 | import net.craftingstore.core.models.api.inventory.types.InventoryItemBackButton; 7 | import net.craftingstore.core.models.api.inventory.types.InventoryItemCategory; 8 | import net.craftingstore.core.models.api.inventory.types.InventoryItemCloseButton; 9 | import net.craftingstore.core.models.api.inventory.types.InventoryItemMessage; 10 | import net.craftingstore.sponge.CraftingStoreSponge; 11 | import net.craftingstore.sponge.inventory.CraftingStoreInventoryProperty; 12 | import net.craftingstore.sponge.inventory.InventoryAttachment; 13 | import net.craftingstore.sponge.inventory.InventoryItemHandler; 14 | import net.craftingstore.sponge.inventory.handlers.BackButtonHandler; 15 | import net.craftingstore.sponge.inventory.handlers.CategoryItemHandler; 16 | import net.craftingstore.sponge.inventory.handlers.CloseButtonHandler; 17 | import net.craftingstore.sponge.inventory.handlers.MessageButtonHandler; 18 | import org.spongepowered.api.Game; 19 | import org.spongepowered.api.entity.living.player.Player; 20 | import org.spongepowered.api.event.Listener; 21 | import org.spongepowered.api.event.filter.cause.First; 22 | import org.spongepowered.api.event.item.inventory.ClickInventoryEvent; 23 | import org.spongepowered.api.item.inventory.property.SlotIndex; 24 | import org.spongepowered.api.item.inventory.transaction.SlotTransaction; 25 | 26 | import java.util.Collection; 27 | import java.util.HashMap; 28 | 29 | public class InventoryClickListener { 30 | 31 | private HashMap, InventoryItemHandler> handlers = new HashMap<>(); 32 | 33 | @Inject 34 | private Game game; 35 | 36 | @Inject 37 | private CraftingStoreSponge spongePlugin; 38 | 39 | @Inject 40 | public InventoryClickListener(BackButtonHandler backButtonHandler, CategoryItemHandler categoryItemHandler, 41 | CloseButtonHandler closeButtonHandler, MessageButtonHandler messageButtonHandler) { 42 | handlers.put(InventoryItemBackButton.class, backButtonHandler); 43 | handlers.put(InventoryItemCategory.class, categoryItemHandler); 44 | handlers.put(InventoryItemCloseButton.class, closeButtonHandler); 45 | handlers.put(InventoryItemMessage.class, messageButtonHandler); 46 | } 47 | 48 | @Listener 49 | public void onClick(ClickInventoryEvent e, @First Player p) { 50 | Collection properties = e.getTargetInventory() 51 | .getProperties(CraftingStoreInventoryProperty.class); 52 | if (properties.size() == 0) { 53 | return; 54 | } 55 | e.setCancelled(true); 56 | if (e.getTransactions().size() == 0) { 57 | return; 58 | } 59 | SlotTransaction transaction = e.getTransactions().get(0); 60 | SlotIndex slotIndex = transaction.getSlot().getInventoryProperty(SlotIndex.class).orElse(null); 61 | if (slotIndex == null) { 62 | return; 63 | } 64 | int index = slotIndex.getValue(); 65 | 66 | CraftingStoreInventoryProperty csProperty = properties.iterator().next(); 67 | InventoryAttachment attachment = csProperty.getValue(); 68 | CraftingStoreInventory csInventory = attachment.getCsInventory(); 69 | InventoryItem item = csInventory.getByIndex(index); 70 | if (item == null) { 71 | return; 72 | } 73 | 74 | if (handlers.containsKey(item.getClass())) { 75 | game.getScheduler().createTaskBuilder() 76 | .execute(() -> handlers.get(item.getClass()).handle(p, item, attachment)) 77 | .submit(spongePlugin); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/listeners/PendingDonationJoinListener.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.listeners; 2 | 3 | import com.google.inject.Inject; 4 | import net.craftingstore.core.CraftingStore; 5 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 6 | import net.craftingstore.core.jobs.ProcessPendingPaymentsJob; 7 | import org.spongepowered.api.entity.living.player.Player; 8 | import org.spongepowered.api.event.Listener; 9 | import org.spongepowered.api.event.network.ClientConnectionEvent; 10 | 11 | public class PendingDonationJoinListener { 12 | 13 | @Inject 14 | private CraftingStore craftingStore; 15 | 16 | @Listener 17 | public void onJoin(ClientConnectionEvent.Join e) { 18 | if (!e.getTargetEntity().getPlayer().isPresent()) { 19 | return; 20 | } 21 | Player p = e.getTargetEntity().getPlayer().get(); 22 | String username = p.getName(); 23 | 24 | craftingStore.getImplementation().runAsyncTask(() -> { 25 | try { 26 | new ProcessPendingPaymentsJob(this.craftingStore, username); 27 | } catch (CraftingStoreApiException ex) { 28 | ex.printStackTrace(); 29 | } 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/logging/Slf4jLogger.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.logging; 2 | 3 | import com.google.inject.Inject; 4 | import com.google.inject.Singleton; 5 | import net.craftingstore.core.logging.CraftingStoreLogger; 6 | import org.slf4j.Logger; 7 | 8 | @Singleton 9 | public class Slf4jLogger extends CraftingStoreLogger { 10 | 11 | @Inject 12 | private Logger logger; 13 | 14 | @Override 15 | public void info(String message) { 16 | this.logger.info(message); 17 | } 18 | 19 | @Override 20 | public void error(String message) { 21 | this.logger.error(message); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/module/ConfigModule.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.module; 2 | 3 | import com.google.inject.AbstractModule; 4 | import net.craftingstore.sponge.config.Config; 5 | 6 | public class ConfigModule extends AbstractModule { 7 | 8 | private Config config; 9 | 10 | public ConfigModule(Config config) { 11 | this.config = config; 12 | } 13 | 14 | @Override 15 | protected void configure() { 16 | bind(Config.class).toInstance(config); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sponge/src/main/java/net/craftingstore/sponge/module/CraftingStoreModule.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.sponge.module; 2 | 3 | import com.google.inject.AbstractModule; 4 | import net.craftingstore.core.CraftingStore; 5 | 6 | public class CraftingStoreModule extends AbstractModule { 7 | 8 | private CraftingStore craftingStore; 9 | 10 | public CraftingStoreModule(CraftingStore craftingStore) { 11 | this.craftingStore = craftingStore; 12 | } 13 | 14 | protected void configure() { 15 | bind(CraftingStore.class).toInstance(craftingStore); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /velocity/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | net.craftingstore 9 | craftingstore 10 | ${revision} 11 | 12 | 13 | velocity 14 | 15 | 16 | 17 | 18 | org.apache.maven.plugins 19 | maven-compiler-plugin 20 | 21 | 8 22 | 8 23 | 24 | 25 | 26 | 27 | 28 | src/main/resources 29 | true 30 | 31 | 32 | 33 | 34 | 35 | 36 | velocity 37 | https://repo.velocitypowered.com/snapshots/ 38 | 39 | 40 | sponge 41 | https://repo.spongepowered.org/maven 42 | 43 | 44 | 45 | 46 | 47 | net.craftingstore 48 | core 49 | ${project.version} 50 | 51 | 52 | 53 | com.velocitypowered 54 | velocity-api 55 | 3.0.0 56 | provided 57 | 58 | 59 | 60 | com.googlecode.json-simple 61 | json-simple 62 | 1.1.1 63 | 64 | 65 | junit 66 | junit 67 | 68 | 69 | org.hamcrest 70 | hamcrest-core 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/craftingstore/velocity/CraftingStoreVelocity.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.velocity; 2 | 3 | import com.google.inject.Inject; 4 | import com.google.inject.Injector; 5 | import com.google.inject.Singleton; 6 | import com.velocitypowered.api.command.CommandManager; 7 | import com.velocitypowered.api.event.EventManager; 8 | import com.velocitypowered.api.event.Subscribe; 9 | import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; 10 | import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; 11 | import com.velocitypowered.api.plugin.Plugin; 12 | import com.velocitypowered.api.plugin.annotation.DataDirectory; 13 | import net.craftingstore.core.CraftingStore; 14 | import net.craftingstore.velocity.command.CraftingStoreCommand; 15 | import net.craftingstore.velocity.config.Config; 16 | import net.craftingstore.velocity.listeners.PendingDonationJoinListener; 17 | import net.craftingstore.velocity.module.ConfigModule; 18 | import net.craftingstore.velocity.module.CraftingStoreModule; 19 | 20 | import java.nio.file.Path; 21 | 22 | @Singleton 23 | @Plugin(id = "craftingstore", name = "CraftingStore") 24 | public class CraftingStoreVelocity { 25 | 26 | @Inject 27 | private CommandManager commandManager; 28 | 29 | @Inject 30 | private EventManager eventManager; 31 | 32 | private Config config; 33 | private CraftingStore craftingStore; 34 | private Injector injector; 35 | 36 | @Inject 37 | public CraftingStoreVelocity(@DataDirectory Path configDirectory, Injector injector) { 38 | this.config = new Config(configDirectory.toFile(), "config.json"); 39 | this.injector = injector.createChildInjector(new ConfigModule(config)); 40 | } 41 | 42 | @Subscribe 43 | public void onInitialization(ProxyInitializeEvent event) { 44 | this.craftingStore = new CraftingStore(injector.getInstance(CraftingStoreVelocityImpl.class)); 45 | injector = injector.createChildInjector(new CraftingStoreModule(craftingStore)); 46 | 47 | commandManager.register("csv", injector.getInstance(CraftingStoreCommand.class)); 48 | eventManager.register(this, injector.getInstance(PendingDonationJoinListener.class)); 49 | } 50 | 51 | @Subscribe 52 | public void onShutdown(ProxyShutdownEvent event) { 53 | this.craftingStore.setEnabled(false); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/craftingstore/velocity/CraftingStoreVelocityImpl.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.velocity; 2 | 3 | import com.google.inject.Inject; 4 | import com.velocitypowered.api.proxy.Player; 5 | import com.velocitypowered.api.proxy.ProxyServer; 6 | import net.craftingstore.core.CraftingStorePlugin; 7 | import net.craftingstore.core.PluginConfiguration; 8 | import net.craftingstore.core.logging.CraftingStoreLogger; 9 | import net.craftingstore.core.models.donation.Donation; 10 | import net.craftingstore.velocity.config.Config; 11 | import net.craftingstore.velocity.events.DonationReceivedEvent; 12 | import net.craftingstore.velocity.events.DonationResult; 13 | import net.craftingstore.velocity.logging.Slf4jLogger; 14 | 15 | import java.util.Optional; 16 | import java.util.concurrent.TimeUnit; 17 | 18 | public class CraftingStoreVelocityImpl implements CraftingStorePlugin { 19 | 20 | @Inject 21 | private CraftingStoreVelocity velocityPlugin; 22 | 23 | @Inject 24 | private Config config; 25 | 26 | @Inject 27 | private ProxyServer proxyServer; 28 | 29 | private Slf4jLogger logger; 30 | 31 | @Inject 32 | private VelocityPluginConfiguration configuration; 33 | 34 | @Inject 35 | private void setLogger(Slf4jLogger logger) { 36 | this.logger = logger; 37 | this.logger.setDebugging((Boolean) this.config.getConfig().getOrDefault("debug", false)); 38 | } 39 | 40 | @Override 41 | public boolean executeDonation(Donation donation) { 42 | if (donation.getPlayer().isRequiredOnline()) { 43 | Optional player = proxyServer.getPlayer(donation.getPlayer().getUsername()); 44 | if (!player.isPresent() || !player.get().isActive()) { 45 | return false; 46 | } 47 | } 48 | 49 | DonationReceivedEvent event = new DonationReceivedEvent(donation); 50 | event.setResult(new DonationResult(true)); 51 | proxyServer.getEventManager().fire(event); 52 | if (!event.getResult().isAllowed()) { 53 | return false; 54 | } 55 | 56 | proxyServer.getCommandManager().executeAsync(proxyServer.getConsoleCommandSource(), donation.getCommand()) 57 | .exceptionally(e -> { 58 | logger.error("Command " + donation.getCommand() + " failed"); 59 | return null; 60 | }); 61 | return true; 62 | } 63 | 64 | @Override 65 | public CraftingStoreLogger getLogger() { 66 | return logger; 67 | } 68 | 69 | @Override 70 | public void registerRunnable(Runnable runnable, int delay, int interval) { 71 | proxyServer.getScheduler().buildTask(velocityPlugin, runnable) 72 | .delay(delay, TimeUnit.SECONDS) 73 | .repeat(interval, TimeUnit.SECONDS) 74 | .schedule(); 75 | } 76 | 77 | @Override 78 | public void runAsyncTask(Runnable runnable) { 79 | proxyServer.getScheduler().buildTask(velocityPlugin, runnable).schedule(); 80 | } 81 | 82 | @Override 83 | public String getToken() { 84 | return (String) config.getConfig().get("api-key"); 85 | } 86 | 87 | @Override 88 | public PluginConfiguration getConfiguration() { 89 | return this.configuration; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/craftingstore/velocity/VelocityPluginConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.velocity; 2 | 3 | import com.google.inject.Inject; 4 | import com.velocitypowered.api.plugin.PluginDescription; 5 | import com.velocitypowered.api.proxy.ProxyServer; 6 | import net.craftingstore.core.PluginConfiguration; 7 | import net.craftingstore.velocity.config.Config; 8 | 9 | public class VelocityPluginConfiguration implements PluginConfiguration { 10 | 11 | @Inject 12 | private PluginDescription description; 13 | 14 | @Inject 15 | private ProxyServer proxyServer; 16 | 17 | @Inject 18 | private Config config; 19 | 20 | @Override 21 | public String getName() { 22 | return "Velocity"; 23 | } 24 | 25 | @Override 26 | public String[] getMainCommands() { 27 | return new String[] {"csv"}; 28 | } 29 | 30 | @Override 31 | public String getVersion() { 32 | return description.getVersion().orElse("unknown"); 33 | } 34 | 35 | @Override 36 | public String getPlatform() { 37 | return proxyServer.getVersion().toString(); 38 | } 39 | 40 | @Override 41 | public boolean isBuyCommandEnabled() { 42 | return false; 43 | } 44 | 45 | @Override 46 | public int getTimeBetweenCommands() { 47 | Object value = config.getConfig().getOrDefault("time-between-commands", 200); 48 | if (value instanceof Integer) { 49 | return (int) value; 50 | } 51 | if (value instanceof Long) { 52 | return ((Long) value).intValue(); 53 | } 54 | throw new RuntimeException("Invalid integer value in time-between-commands"); 55 | } 56 | 57 | @Override 58 | public String getNotEnoughBalanceMessage() { 59 | return null; 60 | } 61 | 62 | @Override 63 | public boolean isUsingAlternativeApi() { 64 | Object value = config.getConfig().getOrDefault("use-alternative-api", false); 65 | if (value instanceof Boolean) { 66 | return (boolean) value; 67 | } 68 | throw new RuntimeException("Invalid boolean value in use-alternative-api"); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/craftingstore/velocity/annotation/Prefix.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.velocity.annotation; 2 | 3 | import com.google.inject.BindingAnnotation; 4 | 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @BindingAnnotation 10 | public @interface Prefix { 11 | } 12 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/craftingstore/velocity/command/CraftingStoreCommand.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.velocity.command; 2 | 3 | import com.google.inject.Inject; 4 | import com.velocitypowered.api.command.CommandSource; 5 | import com.velocitypowered.api.command.SimpleCommand; 6 | import com.velocitypowered.api.proxy.ProxyServer; 7 | import net.craftingstore.core.CraftingStore; 8 | import net.craftingstore.velocity.CraftingStoreVelocity; 9 | import net.craftingstore.velocity.annotation.Prefix; 10 | import net.craftingstore.velocity.config.Config; 11 | import net.kyori.adventure.text.Component; 12 | import net.kyori.adventure.text.format.NamedTextColor; 13 | import net.kyori.adventure.text.format.TextDecoration; 14 | 15 | import java.util.concurrent.ExecutionException; 16 | 17 | public class CraftingStoreCommand implements SimpleCommand { 18 | 19 | @Inject 20 | private CraftingStore craftingStore; 21 | 22 | @Inject 23 | @Prefix 24 | private Component prefix; 25 | 26 | @Inject 27 | private CraftingStoreVelocity velocityPlugin; 28 | 29 | @Inject 30 | private Config config; 31 | 32 | @Inject 33 | private ProxyServer proxyServer; 34 | 35 | @Override 36 | public void execute(Invocation invocation) { 37 | String[] args = invocation.arguments(); 38 | CommandSource sender = invocation.source(); 39 | if (args.length == 1 && args[0].equalsIgnoreCase("reload")) { 40 | craftingStore.reload(); 41 | sender.sendMessage(Component.text() 42 | .append(prefix) 43 | .append(Component.text("The plugin is reloading!")) 44 | .build()); 45 | return; 46 | } 47 | if (args.length == 2 && args[0].equalsIgnoreCase("key")) { 48 | config.getConfig().put("api-key", args[1]); 49 | config.saveConfig(); 50 | proxyServer.getScheduler().buildTask(velocityPlugin, () -> { 51 | try { 52 | if (craftingStore.reload().get()) { 53 | sender.sendMessage(Component.text() 54 | .append(prefix) 55 | .append(Component.text("The new API key has been set in the config, and the plugin has been reloaded.")) 56 | .build()); 57 | } else { 58 | sender.sendMessage(Component.text() 59 | .append(prefix) 60 | .append(Component.text("The API key is invalid. The plugin will not work until you set a valid API key.")) 61 | .build()); 62 | } 63 | } catch (InterruptedException | ExecutionException e) { 64 | e.printStackTrace(); 65 | } 66 | }).schedule(); 67 | return; 68 | } 69 | 70 | sender.sendMessage( 71 | Component.text("-----------------------", NamedTextColor.GRAY).decoration(TextDecoration.STRIKETHROUGH, true) 72 | ); 73 | sender.sendMessage(Component.text() 74 | .append(Component.text("> ", NamedTextColor.DARK_GRAY)) 75 | .append(Component.text("/csv reload", NamedTextColor.GRAY)) 76 | .append(Component.text(" -> ", NamedTextColor.DARK_GRAY)) 77 | .append(Component.text("Reload the config.", NamedTextColor.GRAY)) 78 | .build() 79 | ); 80 | sender.sendMessage(Component.text() 81 | .append(Component.text("> ", NamedTextColor.DARK_GRAY)) 82 | .append(Component.text("/csv key ", NamedTextColor.GRAY)) 83 | .append(Component.text(" -> ", NamedTextColor.DARK_GRAY)) 84 | .append(Component.text("Update the key.", NamedTextColor.GRAY)) 85 | .build() 86 | ); 87 | sender.sendMessage( 88 | Component.text("-----------------------", NamedTextColor.GRAY).decoration(TextDecoration.STRIKETHROUGH, true) 89 | ); 90 | } 91 | 92 | @Override 93 | public boolean hasPermission(Invocation invocation) { 94 | return invocation.source().hasPermission("craftingstore.admin"); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/craftingstore/velocity/config/Config.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.velocity.config; 2 | 3 | import org.json.simple.JSONObject; 4 | import org.json.simple.parser.JSONParser; 5 | import org.json.simple.parser.ParseException; 6 | 7 | import java.io.*; 8 | import java.nio.file.Files; 9 | 10 | public class Config extends File { 11 | 12 | private JSONObject config; 13 | 14 | /** 15 | * Create a new instance of Config, specifying a file name and Plugin. 16 | * 17 | * @param name the file name, including .yml 18 | */ 19 | public Config(File dir, String name) { 20 | super(dir, name); 21 | 22 | if (!dir.exists()) { 23 | dir.mkdirs(); 24 | } 25 | 26 | if (!exists()) { 27 | try { 28 | if (getClass().getClassLoader().getResource(name) != null) { 29 | Files.copy(getClass().getClassLoader().getResourceAsStream(name), toPath()); 30 | } else { 31 | createNewFile(); 32 | } 33 | } catch (IOException e) { 34 | e.printStackTrace(); 35 | } 36 | } 37 | 38 | JSONParser parser = new JSONParser(); 39 | try { 40 | this.config = (JSONObject) parser.parse(new FileReader(this)); 41 | } catch (IOException | ParseException e) { 42 | e.printStackTrace(); 43 | } 44 | } 45 | 46 | public JSONObject getConfig() { 47 | return config; 48 | } 49 | 50 | /** 51 | * Save all changes to the disk. 52 | */ 53 | public void saveConfig() { 54 | try { 55 | PrintWriter pw = new PrintWriter(this); 56 | pw.write(this.config.toJSONString()); 57 | pw.flush(); 58 | pw.close(); 59 | } catch (FileNotFoundException e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/craftingstore/velocity/events/DonationReceivedEvent.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.velocity.events; 2 | 3 | import com.velocitypowered.api.event.ResultedEvent; 4 | import net.craftingstore.core.models.donation.Donation; 5 | 6 | public class DonationReceivedEvent implements ResultedEvent { 7 | private Donation donation; 8 | private DonationResult result; 9 | 10 | public DonationReceivedEvent(Donation donation) { 11 | this.donation = donation; 12 | } 13 | 14 | public Donation getDonation() { 15 | return this.donation; 16 | } 17 | 18 | @Override 19 | public DonationResult getResult() { 20 | return this.result; 21 | } 22 | 23 | @Override 24 | public void setResult(DonationResult result) { 25 | this.result = result; 26 | } 27 | } -------------------------------------------------------------------------------- /velocity/src/main/java/net/craftingstore/velocity/events/DonationResult.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.velocity.events; 2 | 3 | import com.velocitypowered.api.event.ResultedEvent; 4 | 5 | public class DonationResult implements ResultedEvent.Result { 6 | 7 | private boolean allowed; 8 | 9 | public DonationResult(boolean allowed) { 10 | this.allowed = allowed; 11 | } 12 | 13 | @Override 14 | public boolean isAllowed() { 15 | return this.allowed; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/craftingstore/velocity/listeners/PendingDonationJoinListener.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.velocity.listeners; 2 | 3 | import com.google.inject.Inject; 4 | import com.velocitypowered.api.event.Subscribe; 5 | import com.velocitypowered.api.event.connection.PostLoginEvent; 6 | import com.velocitypowered.api.proxy.Player; 7 | import net.craftingstore.core.CraftingStore; 8 | import net.craftingstore.core.exceptions.CraftingStoreApiException; 9 | import net.craftingstore.core.jobs.ProcessPendingPaymentsJob; 10 | 11 | public class PendingDonationJoinListener { 12 | 13 | @Inject 14 | private CraftingStore craftingStore; 15 | 16 | @Subscribe 17 | public void onPlayerJoin(PostLoginEvent event) { 18 | Player player = event.getPlayer(); 19 | String username = player.getUsername(); 20 | 21 | craftingStore.getImplementation().runAsyncTask(() -> { 22 | try { 23 | new ProcessPendingPaymentsJob(craftingStore, username); 24 | } catch (CraftingStoreApiException ex) { 25 | ex.printStackTrace(); 26 | } 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/craftingstore/velocity/logging/Slf4jLogger.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.velocity.logging; 2 | 3 | import com.google.inject.Inject; 4 | import com.google.inject.Singleton; 5 | import net.craftingstore.core.logging.CraftingStoreLogger; 6 | import org.slf4j.Logger; 7 | 8 | @Singleton 9 | public class Slf4jLogger extends CraftingStoreLogger { 10 | 11 | @Inject 12 | private Logger logger; 13 | 14 | @Override 15 | public void info(String message) { 16 | this.logger.info(message); 17 | } 18 | 19 | @Override 20 | public void error(String message) { 21 | this.logger.error(message); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/craftingstore/velocity/module/ConfigModule.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.velocity.module; 2 | 3 | import com.google.inject.AbstractModule; 4 | import net.craftingstore.velocity.config.Config; 5 | 6 | public class ConfigModule extends AbstractModule { 7 | 8 | private Config config; 9 | 10 | public ConfigModule(Config config) { 11 | this.config = config; 12 | } 13 | 14 | @Override 15 | protected void configure() { 16 | bind(Config.class).toInstance(config); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /velocity/src/main/java/net/craftingstore/velocity/module/CraftingStoreModule.java: -------------------------------------------------------------------------------- 1 | package net.craftingstore.velocity.module; 2 | 3 | import com.google.inject.AbstractModule; 4 | import net.craftingstore.core.CraftingStore; 5 | import net.craftingstore.velocity.annotation.Prefix; 6 | import net.kyori.adventure.text.Component; 7 | import net.kyori.adventure.text.TextComponent; 8 | import net.kyori.adventure.text.format.NamedTextColor; 9 | 10 | public class CraftingStoreModule extends AbstractModule { 11 | 12 | private CraftingStore craftingStore; 13 | private TextComponent prefix = Component.text() 14 | .append(Component.text("[", NamedTextColor.GRAY)) 15 | .append(Component.text("CraftingStore", NamedTextColor.RED)) 16 | .append(Component.text("] ", NamedTextColor.GRAY)) 17 | .append(Component.text("", NamedTextColor.WHITE)) 18 | .build(); 19 | 20 | public CraftingStoreModule(CraftingStore craftingStore) { 21 | this.craftingStore = craftingStore; 22 | } 23 | 24 | protected void configure() { 25 | bind(CraftingStore.class).toInstance(craftingStore); 26 | bind(Component.class).annotatedWith(Prefix.class).toInstance(prefix); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /velocity/src/main/resources/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "api-key": "" 3 | } --------------------------------------------------------------------------------