EpicHeads/main/java/com/songoda/epicheads/EpicHeads.java

432 lines
13 KiB
Java

package com.songoda.epicheads;
import com.songoda.epicheads.cache.CacheFile;
import com.songoda.epicheads.cache.CacheHead;
import com.songoda.epicheads.cache.ModsFile;
import com.songoda.epicheads.cache.ModsFileHeader;
import com.songoda.epicheads.cache.legacy.CacheFileConverter;
import com.songoda.epicheads.cache.legacy.LegacyCacheConfig;
import com.songoda.epicheads.command.CommandManager;
import com.songoda.epicheads.config.FileConfigFile;
import com.songoda.epicheads.config.MainConfig;
import com.songoda.epicheads.config.menu.Menus;
import com.songoda.epicheads.config.oldmenu.MenuConfig;
import com.songoda.epicheads.economy.*;
import com.songoda.epicheads.handlers.HeadNamer;
import com.songoda.epicheads.handlers.LegacyIDs;
import com.songoda.epicheads.menu.ui.InventoryMenu;
import com.songoda.epicheads.oldmenu.ClickInventory;
import com.songoda.epicheads.util.Clock;
import com.songoda.epicheads.util.Methods;
import com.songoda.epicheads.volatilecode.injection.ProtocolHackFixer;
import com.songoda.epicheads.volatilecode.reflection.Version;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.function.Consumer;
public class EpicHeads extends JavaPlugin implements Listener {
private static EpicHeads INSTANCE;
private static ConsoleCommandSender console;
private CacheFile cache;
private MenuConfig oldMenuConfig;
private Menus menus;
private MainConfig mainConfig;
private Economy economy;
private LegacyIDs legacyIDs;
private boolean blockStoreAvailable = false;
private References references;
private CommandManager commandManager;
private Locale locale;
@Override
public void onEnable() {
console = this.getServer().getConsoleSender();
INSTANCE = this;
if (Version.isBelow(Version.v1_8)) {
Methods.formatText("&c-------------------------------------------------------------------");
Methods.formatText("&c EpicHeads no longer supports versions below Minecraft 1.8. ");
Methods.formatText("&c Please switch to Heads version 1.15.1 or before. ");
Methods.formatText("&c-------------------------------------------------------------------");
Bukkit.getPluginManager().disablePlugin(this);
return;
}
console.sendMessage(Methods.formatText("&a============================="));
console.sendMessage(Methods.formatText("&7EpicHeads " + this.getDescription().getVersion() + " by &5Brianna <3!"));
console.sendMessage(Methods.formatText("&7Action: &aEnabling&7..."));
Clock timer = Clock.start();
loadCache();
try {
legacyIDs = LegacyIDs.readResource("legacy-ids.txt");
} catch (IOException exception) {
legacyIDs = LegacyIDs.EMPTY;
Methods.formatText("Unable to load legacy IDs to perform conversion from older Spigot versions");
exception.printStackTrace();
}
// Locales
Locale.init(this);
Locale.saveDefaultLocale("en_US");
this.locale = Locale.getLocale(getConfig().getString("Locale", "en_US"));
this.update();
this.references = new References();
this.menus = new Menus();
this.menus.reload();
this.oldMenuConfig = new MenuConfig(getVersionedConfig("menus.yml"));
this.mainConfig = new MainConfig();
this.economy = hookEconomy();
this.commandManager = new CommandManager(this);
ProtocolHackFixer.fix();
tryHookBlockStore();
new HeadNamer(this).registerEvents();
Bukkit.getPluginManager().registerEvents(this, this);
console.sendMessage(Methods.formatText(getDescription().getName() + " has been enabled with " + cache.getHeadCount() + " heads " + timer + "."));
console.sendMessage(Methods.formatText("&a============================="));
}
@Override
public void onDisable() {
INSTANCE = null;
console.sendMessage(Methods.formatText("&a============================="));
console.sendMessage(Methods.formatText("&7EpicHeads " + this.getDescription().getVersion() + " by &5Brianna <3!"));
console.sendMessage(Methods.formatText("&7Action: &cDisabling&7..."));
console.sendMessage(Methods.formatText("&a============================="));
}
public void reloadConfigs() {
this.oldMenuConfig.reload();
this.menus.reload();
this.mainConfig.reload();
this.locale.reloadMessages();
this.economy = hookEconomy();
this.tryHookBlockStore();
}
private void update() {
try {
URL url = new URL("http://update.songoda.com/index.php?plugin=" + getDescription().getName() + "&version=" + getDescription().getVersion());
URLConnection urlConnection = url.openConnection();
InputStream is = urlConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
int numCharsRead;
char[] charArray = new char[1024];
StringBuilder sb = new StringBuilder();
while ((numCharsRead = isr.read(charArray)) > 0) {
sb.append(charArray, 0, numCharsRead);
}
String jsonString = sb.toString();
JSONObject json = (JSONObject) new JSONParser().parse(jsonString);
JSONArray files = (JSONArray) json.get("neededFiles");
for (Object o : files) {
JSONObject file = (JSONObject) o;
if ("locale".equals(file.get("type"))) {
InputStream in = new URL((String) file.get("link")).openStream();
Locale.saveDefaultLocale(in, (String) file.get("name"));
}
}
} catch (Exception e) {
Bukkit.getLogger().warning("Failed to update.");
}
}
public File getCacheFile() {
if (!getDataFolder().exists() && !getDataFolder().mkdirs())
throw new RuntimeException("Unable to create the data folder to save plugin files");
if (!getDataFolder().isDirectory())
throw new RuntimeException("plugins/EpicHeads should be a directory, yet there is a file with the same name");
return new File(getDataFolder(), "heads.cache");
}
private CacheFile loadCache() {
File file = getCacheFile();
FileConfigFile legacyConfig = new FileConfigFile("cache.yml");
boolean requiresWrite = false;
if (!file.exists()) {
requiresWrite = true;
if (legacyConfig.getFile().exists()) {
Clock timer = Clock.start();
LegacyCacheConfig legacy = new LegacyCacheConfig(legacyConfig);
cache = CacheFileConverter.convertToCacheFile("main-cache", legacy);
Methods.formatText("Converted legacy yaml cache file to new binary file " + timer);
} else {
cache = new CacheFile("main-cache");
}
} else {
try {
Clock timer = Clock.start();
cache = CacheFile.read(file);
Methods.formatText("Loaded cache file " + timer);
} catch (IOException e) {
Methods.formatText("Unable to read heads.cache file");
throw new RuntimeException("There was an exception reading the heads.cache file", e);
}
}
if (installAddons() || requiresWrite) {
saveCache();
}
if (legacyConfig.getFile().exists() && !legacyConfig.getFile().delete()) {
Methods.formatText("Unable to delete legacy yaml cache file");
}
return cache;
}
public void saveCache() {
File file = getCacheFile();
try {
Clock timer = Clock.start();
cache.write(file);
Methods.formatText("Saved cache file " + timer);
} catch (IOException e) {
Methods.formatText("Unable to save the cache to heads.cache");
throw new RuntimeException("There was an exception saving the cache", e);
}
}
private ModsFileHeader readModsFileHeader() {
try {
return ModsFileHeader.readResource("cache.mods");
} catch (IOException e) {
Methods.formatText("Unable to read header of cache.mods");
throw new RuntimeException("Unable to read header of cache.mods", e);
}
}
private ModsFile readModsFile() {
try {
return ModsFile.readResource("cache.mods");
} catch (IOException e) {
Methods.formatText("Unable to read mods from cache.mods");
throw new RuntimeException("Unable to read mods from cache.mods", e);
}
}
private boolean installAddons() {
Clock timer = Clock.start();
ModsFileHeader header = readModsFileHeader();
int newMods = header.getUninstalledMods(cache);
if (newMods == 0)
return false;
ModsFile mods = readModsFile();
int newHeads = mods.installMods(cache);
if (newHeads > 0) {
Methods.formatText("Added " + newHeads + " new heads from " + newMods + " addons " + timer);
} else {
Methods.formatText("Installed " + newMods + " addons " + timer);
}
return true;
}
private Economy hookEconomy() {
if (!mainConfig.isEconomyEnabled())
return new NoEconomy();
Economy economy = null;
if (mainConfig.isVaultEconomyEnabled()) {
economy = tryHookEconomy(null, new VaultEconomy());
}
if (mainConfig.isItemEconomyEnabled()) {
economy = tryHookEconomy(economy, new ItemEconomy());
}
if (mainConfig.isPlayerPointsEconomyEnabled()) {
economy = tryHookEconomy(economy, new PlayerPointsEconomy());
}
if (economy == null || economy instanceof NoEconomy) {
Methods.formatText("Economy enabled in config.yml yet Vault, PlayerPoints and Item economies disabled. " + "Player's will not be able to purchase heads.");
economy = (economy != null ? economy : new NoEconomy());
}
return economy;
}
private Economy tryHookEconomy(Economy currentlyHooked, Economy toHook) {
if (currentlyHooked != null) {
Methods.formatText(toHook.getName() + " economy is not the only economy enabled in the config.yml.");
if (!(currentlyHooked instanceof NoEconomy))
return currentlyHooked;
}
if (!toHook.tryHook()) {
Methods.formatText(toHook.getName() + " enabled in config.yml, yet Heads was unable to hook into it.");
return new NoEconomy();
}
Methods.formatText("Loaded " + toHook.getName() + " economy");
return toHook;
}
private void tryHookBlockStore() {
if (mainConfig.shouldUseBlockStore() && Bukkit.getPluginManager().getPlugin("BlockStore") != null) {
blockStoreAvailable = false;
try {
Class<?> apiClass = Class.forName("net.sothatsit.blockstore.BlockStoreApi");
apiClass.getDeclaredMethod("retrieveBlockMeta", Plugin.class, Location.class, Plugin.class, String.class, Consumer.class);
Methods.formatText("Hooked BlockStore");
blockStoreAvailable = true;
} catch (ClassNotFoundException | NoSuchMethodException e) {
Methods.formatText("Unable to hook BlockStore, the version of BlockStore you are " + "using may be outdated. Heads requires BlockStore v1.5.0.");
Methods.formatText("Please update BlockStore and report this to Sothatsit if the problem persists.");
}
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onInventoryClick(InventoryClickEvent e) {
Inventory inventory = e.getInventory();
if (inventory == null)
return;
InventoryHolder holder = inventory.getHolder();
if (holder instanceof ClickInventory) {
((ClickInventory) holder).onClick(e);
} else if (holder instanceof InventoryMenu) {
((InventoryMenu) holder).onClick(e);
}
}
private boolean isExemptFromCost(Player player) {
if (!mainConfig.isEconomyEnabled() || player.hasPermission("EpicHeads.bypasscost"))
return true;
return mainConfig.isFreeInCreative() && player.getGameMode() == GameMode.CREATIVE;
}
public boolean chargeForHead(Player player, CacheHead head) {
if (isExemptFromCost(player))
return true;
double cost = head.getCost();
if (cost <= 0)
return true;
if (!economy.hasBalance(player, cost)) {
player.sendMessage(getLocale().getMessage("interface.get.notenoughmoney", head.getName(), head.getCost()));
return false;
}
if (!economy.takeBalance(player, cost)) {
player.sendMessage(getLocale().getMessage("interface.get.transactionerror", head.getName(), head.getCost()));
return false;
}
player.sendMessage(getLocale().getMessage("interface.get.purchased", head.getName(), head.getCost()));
return true;
}
public String getCategoryPermission(String category) {
return "EpicHeads.category." + category.toLowerCase().replace(' ', '_');
}
//ToDO: these shouldn't be static.
public static EpicHeads getInstance() {
return INSTANCE;
}
public LegacyIDs getLegacyIDs() {
return INSTANCE.legacyIDs;
}
public MainConfig getMainConfig() {
return INSTANCE.mainConfig;
}
public CacheFile getCache() {
return INSTANCE.cache;
}
public Menus getMenus() {
return INSTANCE.menus;
}
public MenuConfig getMenuConfig() {
return INSTANCE.oldMenuConfig;
}
public Economy getEconomy() {
return INSTANCE.economy;
}
public boolean isBlockStoreAvailable() {
return INSTANCE.blockStoreAvailable;
}
public void sync(Runnable task) {
Bukkit.getScheduler().runTask(INSTANCE, task);
}
public FileConfigFile getVersionedConfig(String resource) {
if (Version.isBelow(Version.v1_13))
return new FileConfigFile(resource, "pre1_13/" + resource);
return new FileConfigFile(resource);
}
public CommandManager getCommandManager() {
return commandManager;
}
public Locale getLocale() {
return locale;
}
public References getReferences() {
return references;
}
}