add newest core preference, fix paged gui + list editor

This commit is contained in:
jascotty2 2019-09-01 13:14:57 -05:00
parent 927aee51bf
commit fcdb9d2d50
11 changed files with 160 additions and 69 deletions

View File

@ -12,6 +12,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
@ -23,6 +24,7 @@ import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
@ -31,6 +33,7 @@ import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
@ -39,13 +42,18 @@ public class SongodaCore {
private final static String prefix = "[SongodaCore]";
/**
* Whenever we make a major change to the core GUI, updater,
* or other function used by the core, increment this number
*/
private final static int coreRevision = 2;
private final static int updaterVersion = 1;
private final static Set<PluginInfo> registeredPlugins = new HashSet<>();
private static SongodaCore INSTANCE = null;
private JavaPlugin piggybackedPlugin;
private final CommandManager commandManager;
private CommandManager commandManager;
private EventListener loginListener;
private ShadedEventListener shadingListener;
@ -64,13 +72,45 @@ public class SongodaCore {
for (Class<?> clazz : Bukkit.getServicesManager().getKnownServices()) {
if(clazz.getSimpleName().equals("SongodaCore")) {
try {
// use the active service
clazz.getMethod("registerPlugin", JavaPlugin.class, int.class, String.class).invoke(null, plugin, pluginID, icon);
// test to see if we're up to date
int otherVersion = (int) clazz.getMethod("getCoreVersion").invoke(null);
if(otherVersion >= getCoreVersion()) {
// use the active service
clazz.getMethod("registerPlugin", JavaPlugin.class, int.class, String.class).invoke(null, plugin, pluginID, icon);
if(hasShading()) {
(INSTANCE = new SongodaCore()).piggybackedPlugin = plugin;
INSTANCE.shadingListener = new ShadedEventListener();
Bukkit.getPluginManager().registerEvents(INSTANCE.shadingListener, plugin);
if(hasShading()) {
(INSTANCE = new SongodaCore()).piggybackedPlugin = plugin;
INSTANCE.shadingListener = new ShadedEventListener();
Bukkit.getPluginManager().registerEvents(INSTANCE.shadingListener, plugin);
}
} else {
// we are newer than the registered service: steal all of its registrations
// grab the old core's registrations
List otherPlugins = (List) clazz.getMethod("getPlugins").invoke(null);
// destroy the old core
Object oldCore = clazz.getMethod("getInstance").invoke(null);
Method destruct = clazz.getDeclaredMethod("destroy");
destruct.setAccessible(true);
destruct.invoke(oldCore);
// register ourselves as the SongodaCore service!
INSTANCE = new SongodaCore(plugin);
INSTANCE.init();
INSTANCE.register(plugin, pluginID, icon);
Bukkit.getServicesManager().register(SongodaCore.class, INSTANCE, plugin, ServicePriority.Normal);
// we need (JavaPlugin plugin, int pluginID, String icon) for our object
if(!otherPlugins.isEmpty()) {
Object testSubject = otherPlugins.get(0);
Class otherPluginInfo = testSubject.getClass();
Method otherPluginInfo_getJavaPlugin = otherPluginInfo.getMethod("getJavaPlugin");
Method otherPluginInfo_getSongodaId = otherPluginInfo.getMethod("getSongodaId");
Method otherPluginInfo_getCoreIcon = otherPluginInfo.getMethod("getCoreIcon");
for(Object other : otherPlugins) {
INSTANCE.register(
(JavaPlugin) otherPluginInfo_getJavaPlugin.invoke(other),
(int) otherPluginInfo_getSongodaId.invoke(other),
(String) otherPluginInfo_getCoreIcon.invoke(other));
}
}
}
return;
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ignored) {
@ -80,9 +120,9 @@ public class SongodaCore {
// register ourselves as the SongodaCore service!
INSTANCE = new SongodaCore(plugin);
INSTANCE.init();
INSTANCE.register(plugin, pluginID, icon);
Bukkit.getServicesManager().register(SongodaCore.class, INSTANCE, plugin, ServicePriority.Normal);
}
INSTANCE.register(plugin, pluginID, icon);
}
SongodaCore() {
@ -97,17 +137,35 @@ public class SongodaCore {
private void init() {
shadingListener = new ShadedEventListener();
commandManager.registerCommandDynamically(new SongodaCoreCommand(this))
.addSubCommand(new SongodaCoreDiagCommand(this));
commandManager.registerCommandDynamically(new SongodaCoreCommand())
.addSubCommand(new SongodaCoreDiagCommand());
Bukkit.getPluginManager().registerEvents(loginListener, piggybackedPlugin);
Bukkit.getPluginManager().registerEvents(shadingListener, piggybackedPlugin);
// we aggressevely want to own this command
Bukkit.getScheduler().runTaskLaterAsynchronously(piggybackedPlugin, ()->{CommandManager.registerCommandDynamically(piggybackedPlugin, "songoda", commandManager, commandManager);}, 10 * 60 * 1);
Bukkit.getScheduler().runTaskLaterAsynchronously(piggybackedPlugin, ()->{CommandManager.registerCommandDynamically(piggybackedPlugin, "songoda", commandManager, commandManager);}, 20 * 60 * 1);
Bukkit.getScheduler().runTaskLaterAsynchronously(piggybackedPlugin, ()->{CommandManager.registerCommandDynamically(piggybackedPlugin, "songoda", commandManager, commandManager);}, 20 * 60 * 2);
Bukkit.getScheduler().runTaskLaterAsynchronously(piggybackedPlugin, ()->registerAllPlugins(), 20 * 60 * 2);
tasks.add(Bukkit.getScheduler().runTaskLaterAsynchronously(piggybackedPlugin, ()->{CommandManager.registerCommandDynamically(piggybackedPlugin, "songoda", commandManager, commandManager);}, 10 * 60 * 1));
tasks.add(Bukkit.getScheduler().runTaskLaterAsynchronously(piggybackedPlugin, ()->{CommandManager.registerCommandDynamically(piggybackedPlugin, "songoda", commandManager, commandManager);}, 20 * 60 * 1));
tasks.add(Bukkit.getScheduler().runTaskLaterAsynchronously(piggybackedPlugin, ()->{CommandManager.registerCommandDynamically(piggybackedPlugin, "songoda", commandManager, commandManager);}, 20 * 60 * 2));
tasks.add(Bukkit.getScheduler().runTaskLaterAsynchronously(piggybackedPlugin, ()->registerAllPlugins(), 20 * 60 * 2));
}
/**
* Used to yield this core to a newer core
*/
private void destroy() {
Bukkit.getServicesManager().unregister(SongodaCore.class, INSTANCE);
tasks.stream().filter(task -> task != null && !task.isCancelled())
.forEach(task -> Bukkit.getScheduler().cancelTask(task.getTaskId()));
HandlerList.unregisterAll(loginListener);
if(!hasShading()) {
HandlerList.unregisterAll(shadingListener);
}
registeredPlugins.clear();
piggybackedPlugin = null;
commandManager = null;
loginListener = null;
}
private ArrayList<BukkitTask> tasks = new ArrayList();
/**
* Register plugins that may not have been updated yet
*/
@ -179,7 +237,7 @@ public class SongodaCore {
// don't forget to check for language pack updates ;)
info.addModule(new LocaleModule());
registeredPlugins.add(info);
Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> update(info), 20L);
tasks.add(Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> update(info), 60L));
}
private void update(PluginInfo plugin) {
@ -223,11 +281,15 @@ public class SongodaCore {
}
}
public List<PluginInfo> getPlugins() {
public static List<PluginInfo> getPlugins() {
return new ArrayList<>(registeredPlugins);
}
public static int getVersion() {
public static int getCoreVersion() {
return coreRevision;
}
public static int getUpdaterVersion() {
return updaterVersion;
}

View File

@ -45,7 +45,6 @@ public abstract class SongodaPlugin extends JavaPlugin {
@Override
public ConfigFileConfigurationAdapter getConfig() {
System.out.println("Plugin config adapter!");
return config.getFileConfig();
}

View File

@ -7,7 +7,6 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

View File

@ -62,7 +62,7 @@ public class ConfigEditorGui extends SimplePagedGui {
this.setUseHeader(true);
headerBackItem = footerBackItem = GuiUtils.getBorderItem(LegacyMaterials.GRAY_STAINED_GLASS_PANE.getItem());
final String path = node.getCurrentPath();
this.setItem(4, configItem(LegacyMaterials.FILLED_MAP, !path.isEmpty() ? path : file , config, !path.isEmpty() ? path : null, null));
this.setItem(4, configItem(LegacyMaterials.FILLED_MAP, !path.isEmpty() ? path : file , config, !path.isEmpty() ? path : null, ChatColor.BLACK.toString()));
this.setButton(8, GuiUtils.createButtonItem(LegacyMaterials.OAK_DOOR, "Exit"), (event) -> event.player.closeInventory());
// compile list of settings
@ -77,21 +77,20 @@ public class ConfigEditorGui extends SimplePagedGui {
// next we need to display the config settings
int index = 9;
for (final String sectionKey : sections) {
this.setButton(index++, configItem(LegacyMaterials.WRITABLE_BOOK, ChatColor.YELLOW + sectionKey, node, sectionKey, "Click to open this section"),
setButton(index++, configItem(LegacyMaterials.WRITABLE_BOOK, ChatColor.YELLOW + sectionKey, node, sectionKey, "Click to open this section"),
(event) -> event.manager.showGUI(event.player, new ConfigEditorGui(plugin, this, file, config, node.getConfigurationSection(sectionKey))));
}
// todo: display values of settings in gui, too
// now display individual settings
for (final String settingKey : settings) {
final Object val = node.get(settingKey);
if(val == null) continue;
else if(val instanceof Boolean) {
else if (val instanceof Boolean) {
// toggle switch
this.setButton(index, configItem(LegacyMaterials.LEVER, ChatColor.YELLOW + settingKey, node, settingKey, String.valueOf((Boolean) val), "Click to toggle this setting"),
(event) -> this.toggle(event.slot, settingKey));
if((Boolean) val) {
this.highlightItem(index);
setButton(index, configItem(LegacyMaterials.LEVER, ChatColor.YELLOW + settingKey, node, settingKey, String.valueOf((Boolean) val), "Click to toggle this setting"),
(event) -> this.toggle(event.slot, settingKey));
if ((Boolean) val) {
highlightItem(index);
}
} else if (isNumber(val)) {
// number dial
@ -108,7 +107,7 @@ public class ConfigEditorGui extends SimplePagedGui {
} else if (isMaterial(val)) {
// changing a block
// isMaterial is more of a guess, to be honest.
this.setButton(index, configItem(LegacyMaterials.STONE, ChatColor.YELLOW + settingKey, node, settingKey, val.toString(), "Click to edit this setting"),
setButton(index, configItem(LegacyMaterials.STONE, ChatColor.YELLOW + settingKey, node, settingKey, val.toString(), "Click to edit this setting"),
(event) -> {
SimplePagedGui paged = new SimplePagedGui(this);
paged.setTitle(ChatColor.BLUE + settingKey);
@ -126,7 +125,7 @@ public class ConfigEditorGui extends SimplePagedGui {
} else if (val instanceof String) {
// changing a "string" value (or change to a feather for writing quill)
this.setButton(index, configItem(LegacyMaterials.STRING, ChatColor.YELLOW + settingKey, node, settingKey, val.toString(), "Click to edit this setting"),
setButton(index, configItem(LegacyMaterials.STRING, ChatColor.YELLOW + settingKey, node, settingKey, val.toString(), "Click to edit this setting"),
(event) -> {
event.gui.exit();
ChatPrompt.showPrompt(plugin, event.player, "Enter a new value for " + settingKey + ":", response -> {
@ -136,11 +135,11 @@ public class ConfigEditorGui extends SimplePagedGui {
.setOnCancel(() -> {event.player.sendMessage(ChatColor.RED + "Edit canceled"); event.manager.showGUI(event.player, this);});
});
} else if (val instanceof List) {
this.setButton(index, configItem(LegacyMaterials.WRITABLE_BOOK, ChatColor.YELLOW + settingKey, node, settingKey, String.format("(%d values)", ((List) val).size()), "Click to edit this setting"),
setButton(index, configItem(LegacyMaterials.WRITABLE_BOOK, ChatColor.YELLOW + settingKey, node, settingKey, String.format("(%d values)", ((List) val).size()), "Click to edit this setting"),
(event) -> {
event.manager.showGUI(event.player, (new ConfigEditorListEditorGui(this, settingKey, (List) val)).setOnClose((gui) -> {
if(((ConfigEditorListEditorGui) gui.gui).saveChanges) {
setList(event.slot, settingKey, ((ConfigEditorListEditorGui) gui.gui).value);
setList(event.slot, settingKey, ((ConfigEditorListEditorGui) gui.gui).values);
}
}));
});

View File

@ -6,6 +6,7 @@ import com.songoda.core.gui.SimplePagedGui;
import com.songoda.core.input.ChatPrompt;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.bukkit.ChatColor;
import org.bukkit.event.inventory.ClickType;
@ -20,9 +21,10 @@ public class ConfigEditorListEditorGui extends SimplePagedGui {
final ConfigEditorGui current;
public boolean saveChanges = false;
public List<String> value;
public List<String> values;
public ConfigEditorListEditorGui(ConfigEditorGui current, String key, List<String> value) {
public ConfigEditorListEditorGui(ConfigEditorGui current, String key, List<String> val) {
super(current);
this.current = current;
this.blankItem = current.getDefaultItem();
headerBackItem = footerBackItem = current.getHeaderBackItem();
@ -30,7 +32,7 @@ public class ConfigEditorListEditorGui extends SimplePagedGui {
this.setUseHeader(true);
this.setItem(4, current.configItem(LegacyMaterials.FILLED_MAP, key, current.getCurrentNode(), key, null));
this.setButton(8, GuiUtils.createButtonItem(LegacyMaterials.OAK_DOOR, "Exit"), (event) -> event.player.closeInventory());
this.value = new ArrayList(value);
this.values = new ArrayList(val);
this.setButton(8, GuiUtils.createButtonItem(LegacyMaterials.LAVA_BUCKET, ChatColor.RED + "Discard Changes"), (event) -> event.player.closeInventory());
this.setButton(0, GuiUtils.createButtonItem(LegacyMaterials.REDSTONE, ChatColor.GREEN + "Save"), (event) -> {
@ -39,34 +41,40 @@ public class ConfigEditorListEditorGui extends SimplePagedGui {
});
this.setButton(1, GuiUtils.createButtonItem(LegacyMaterials.CHEST, ChatColor.BLUE + "Add Item"),
(event) -> {
event.gui.exit();
ChatPrompt.showPrompt(event.manager.getPlugin(), event.player, "Enter a new value to add:", response -> {
value.add(response.getMessage().trim());
values.add(response.getMessage().trim());
redraw();
}).setOnClose(() -> event.manager.showGUI(event.player, this))
}).setOnClose(() -> {event.manager.showGUI(event.player, this); })
.setOnCancel(() -> {event.player.sendMessage(ChatColor.RED + "Edit canceled"); event.manager.showGUI(event.player, this);});
});
redraw();
}
void redraw() {
page = 1;
// clear old display
for (Integer oldI : (Integer[]) cellItems.keySet().toArray()) {
if (oldI > 8) {
cellItems.remove(oldI);
if(inventory != null) {
for(Integer i : cellItems.keySet().toArray(new Integer[0])) {
if(i > 8) {
cellItems.remove(i);
conditionalButtons.remove(i);
}
}
}
// update items
int i = 9;
for (String item : value) {
for (String item : values) {
final int index = i - 9;
setButton(i++, GuiUtils.createButtonItem(LegacyMaterials.PAPER, item, "Right-click to remove"), ClickType.RIGHT, (event) -> {
value.remove(index);
values.remove(index);
redraw();
});
}
// update display
showPage();
update();
}
}

View File

@ -94,4 +94,8 @@ public final class PluginInfo {
public int getSongodaId() {
return songodaId;
}
public String getCoreIcon() {
return coreIcon;
}
}

View File

@ -9,12 +9,10 @@ import org.bukkit.entity.Player;
public class SongodaCoreCommand extends AbstractCommand {
final SongodaCore instance;
protected GuiManager guiManager;
public SongodaCoreCommand(SongodaCore instance) {
public SongodaCoreCommand() {
super(false, "songoda");
this.instance = instance;
}
@Override
@ -23,7 +21,7 @@ public class SongodaCoreCommand extends AbstractCommand {
if(guiManager == null || guiManager.isClosed()) {
guiManager = new GuiManager(SongodaCore.getHijackedPlugin());
}
guiManager.showGUI((Player) sender, new SongodaCoreOverviewGUI(instance));
guiManager.showGUI((Player) sender, new SongodaCoreOverviewGUI());
} else {
sender.sendMessage("/songoda diag");
}

View File

@ -15,16 +15,13 @@ import java.util.List;
public class SongodaCoreDiagCommand extends AbstractCommand {
final SongodaCore instance;
private final DecimalFormat format = new DecimalFormat("##.##");
private Object serverInstance;
private Field tpsField;
public SongodaCoreDiagCommand(SongodaCore instance) {
public SongodaCoreDiagCommand() {
super(false, "diag");
this.instance = instance;
try {
serverInstance = NMSUtils.getNMSClass("MinecraftServer").getMethod("getServer").invoke(null);
@ -42,7 +39,7 @@ public class SongodaCoreDiagCommand extends AbstractCommand {
sender.sendMessage("Songoda Diagnostics Information");
sender.sendMessage("");
sender.sendMessage("Plugins:");
for (PluginInfo plugin : instance.getPlugins()) {
for (PluginInfo plugin : SongodaCore.getPlugins()) {
sender.sendMessage(plugin.getJavaPlugin().getName()
+ " (" + plugin.getJavaPlugin().getDescription().getVersion() + ")");
}

View File

@ -11,11 +11,8 @@ import org.bukkit.event.inventory.ClickType;
final class SongodaCoreOverviewGUI extends Gui {
private final SongodaCore update;
protected SongodaCoreOverviewGUI(SongodaCore update) {
this.update = update;
List<PluginInfo> plugins = update.getPlugins();
protected SongodaCoreOverviewGUI() {
List<PluginInfo> plugins = SongodaCore.getPlugins();
// could do pages, too, but don't think we'll have that many at a time for a while
int max = (int) Math.ceil(plugins.size() / 9.);
setRows(max);

View File

@ -140,36 +140,63 @@ public class SimplePagedGui extends Gui {
protected Inventory generateInventory(GuiManager manager) {
// calculate pages here
rowsPerPage = useHeader ? 4 : 5;
maxCellSlot = this.cellItems.isEmpty() ? 0 : this.cellItems.keySet().stream().max(Integer::compare).get();
maxCellSlot = (this.cellItems.isEmpty() ? 0 : this.cellItems.keySet().stream().max(Integer::compare).get()) + 1;
int maxRows = (int) Math.ceil(maxCellSlot / 9.);
pages = (int) Math.ceil(maxRows / rowsPerPage);
page = 1;
this.setRows(maxRows + (useHeader ? 2 : 1));
this.setRows(maxRows + (useHeader ? 1 : 0));
// create inventory view
final int cells = rows * 9;
inventory = Bukkit.getServer().createInventory(new GuiHolder(manager, this), cells,
title == null ? "" : trimTitle(ChatColor.translateAlternateColorCodes('&', title)));
// populate initial inventory
// populate and return the display inventory
page = 1;
update();
return inventory;
}
@Override
public void update() {
if (inventory == null) {
return;
}
// calculate pages here
rowsPerPage = useHeader ? 4 : 5;
maxCellSlot = (this.cellItems.isEmpty() ? 0 : this.cellItems.keySet().stream().max(Integer::compare).get()) + 1;
int maxRows = Math.max((useHeader ? 1 : 0), (int) Math.ceil(maxCellSlot / 9.));
pages = (int) Math.ceil(maxRows / rowsPerPage);
// create a new inventory if needed
final int cells = rows * 9;
boolean isNew = false;
if (cells != inventory.getSize()) {
this.setRows(maxRows + (useHeader ? 2 : 1));
inventory = Bukkit.getServer().createInventory(inventory.getHolder(), cells,
title == null ? "" : trimTitle(ChatColor.translateAlternateColorCodes('&', title)));
isNew = true;
}
// populate header
if (useHeader) {
for (int i = 0; i < 9; ++i) {
final ItemStack item = cellItems.get(i);
inventory.setItem(i, item != null ? item : (headerBackItem != null ? headerBackItem : blankItem));
}
}
for (int i = useHeader ? 9 : 0; i < cells - 9; ++i) {
final ItemStack item = cellItems.get(i);
inventory.setItem(i, item != null ? item : blankItem);
}
// last row is dedicated to pagation
for (int i = cells - 9; i < cells; ++i) {
inventory.setItem(i, footerBackItem != null ? footerBackItem : blankItem);
}
updatePageNavigation();
// fill out the rest of the page
showPage();
return inventory;
if(isNew) {
// whoopsie!
exit();
getPlayers().forEach(player -> ((GuiHolder) inventory.getHolder()).manager.showGUI(player, this));
}
}
@Override

View File

@ -74,6 +74,7 @@ public class ChatPrompt implements Listener {
ChatConfirmEvent chatConfirmEvent = new ChatConfirmEvent(player, event.getMessage());
player.sendMessage("\u00BB " + event.getMessage());
try {
handler.onChat(chatConfirmEvent);
} catch (Throwable t) {