mirror of
https://github.com/BentoBoxWorld/Challenges.git
synced 2024-11-25 03:55:10 +01:00
Implement WebManager that will download Challenges Libraries from GitHub.
Implement GUI for selecting and downloading Challenges Libraries.
This commit is contained in:
parent
29a77147b5
commit
f611727d4e
@ -21,6 +21,7 @@ import world.bentobox.challenges.config.Settings;
|
|||||||
import world.bentobox.challenges.handlers.*;
|
import world.bentobox.challenges.handlers.*;
|
||||||
import world.bentobox.challenges.listeners.ResetListener;
|
import world.bentobox.challenges.listeners.ResetListener;
|
||||||
import world.bentobox.challenges.listeners.SaveListener;
|
import world.bentobox.challenges.listeners.SaveListener;
|
||||||
|
import world.bentobox.challenges.web.WebManager;
|
||||||
import world.bentobox.level.Level;
|
import world.bentobox.level.Level;
|
||||||
|
|
||||||
|
|
||||||
@ -39,6 +40,11 @@ public class ChallengesAddon extends Addon {
|
|||||||
|
|
||||||
private ChallengesImportManager importManager;
|
private ChallengesImportManager importManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class manages web content loading.
|
||||||
|
*/
|
||||||
|
private WebManager webManager;
|
||||||
|
|
||||||
private Settings settings;
|
private Settings settings;
|
||||||
|
|
||||||
private boolean hooked;
|
private boolean hooked;
|
||||||
@ -138,6 +144,9 @@ public class ChallengesAddon extends Addon {
|
|||||||
// Challenge import setup
|
// Challenge import setup
|
||||||
this.importManager = new ChallengesImportManager(this);
|
this.importManager = new ChallengesImportManager(this);
|
||||||
|
|
||||||
|
// Web content loading
|
||||||
|
this.webManager = new WebManager(this);
|
||||||
|
|
||||||
List<GameModeAddon> hookedGameModes = new ArrayList<>();
|
List<GameModeAddon> hookedGameModes = new ArrayList<>();
|
||||||
|
|
||||||
this.getPlugin().getAddonsManager().getGameModeAddons().forEach(gameModeAddon -> {
|
this.getPlugin().getAddonsManager().getGameModeAddons().forEach(gameModeAddon -> {
|
||||||
@ -315,6 +324,14 @@ public class ChallengesAddon extends Addon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the webManager
|
||||||
|
*/
|
||||||
|
public WebManager getWebManager() {
|
||||||
|
return this.webManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the challenge settings.
|
* @return the challenge settings.
|
||||||
*/
|
*/
|
||||||
|
@ -126,6 +126,77 @@ public class ChallengesImportManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method loads downloaded challenges into memory.
|
||||||
|
* @param user User who calls downloaded challenge loading
|
||||||
|
* @param world Target world.
|
||||||
|
* @param downloadString String that need to be loaded via DefaultDataHolder.
|
||||||
|
* @return <code>true</code> if everything was successful, otherwise <code>false</code>.
|
||||||
|
*/
|
||||||
|
public boolean loadDownloadedChallenges(User user, World world, String downloadString)
|
||||||
|
{
|
||||||
|
ChallengesManager manager = this.addon.getChallengesManager();
|
||||||
|
|
||||||
|
// If exist any challenge or level that is bound to current world, then do not load default challenges.
|
||||||
|
if (manager.hasAnyChallengeData(world.getName()))
|
||||||
|
{
|
||||||
|
if (user.isPlayer())
|
||||||
|
{
|
||||||
|
user.sendMessage("challenges.errors.exist-challenges-or-levels");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.addon.logWarning("challenges.errors.exist-challenges-or-levels");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// This prefix will be used to all challenges. That is a unique way how to separate challenged for
|
||||||
|
// each game mode.
|
||||||
|
String uniqueIDPrefix = Utils.getGameMode(world) + "_";
|
||||||
|
DefaultDataHolder downloadedChallenges = new DefaultJSONHandler(this.addon).loadWebObject(downloadString);
|
||||||
|
|
||||||
|
// All new challenges should get correct ID. So we need to map it to loaded challenges.
|
||||||
|
downloadedChallenges.getChallengeList().forEach(challenge -> {
|
||||||
|
// Set correct challenge ID
|
||||||
|
challenge.setUniqueId(uniqueIDPrefix + challenge.getUniqueId());
|
||||||
|
// Set up correct level ID if it is necessary
|
||||||
|
if (!challenge.getLevel().isEmpty())
|
||||||
|
{
|
||||||
|
challenge.setLevel(uniqueIDPrefix + challenge.getLevel());
|
||||||
|
}
|
||||||
|
// Load challenge in memory
|
||||||
|
manager.loadChallenge(challenge, false, user, user == null);
|
||||||
|
});
|
||||||
|
|
||||||
|
downloadedChallenges.getLevelList().forEach(challengeLevel -> {
|
||||||
|
// Set correct level ID
|
||||||
|
challengeLevel.setUniqueId(uniqueIDPrefix + challengeLevel.getUniqueId());
|
||||||
|
// Set correct world name
|
||||||
|
challengeLevel.setWorld(Util.getWorld(world).getName());
|
||||||
|
// Reset names for all challenges.
|
||||||
|
challengeLevel.setChallenges(challengeLevel.getChallenges().stream().
|
||||||
|
map(challenge -> uniqueIDPrefix + challenge).
|
||||||
|
collect(Collectors.toSet()));
|
||||||
|
// Load level in memory
|
||||||
|
manager.loadLevel(challengeLevel, false, user, user == null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addon.getChallengesManager().save();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Section: Default generation
|
// Section: Default generation
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
@ -320,6 +391,16 @@ public class ChallengesImportManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method creates and adds to list all objects from default.json file.
|
||||||
|
* @return List of all objects from default.json that is with T instance.
|
||||||
|
*/
|
||||||
|
DefaultDataHolder loadWebObject(String downloadedObject)
|
||||||
|
{
|
||||||
|
return this.gson.fromJson(downloadedObject, DefaultDataHolder.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Section: Variables
|
// Section: Variables
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
|
@ -53,7 +53,7 @@ public abstract class CommonGUI
|
|||||||
/**
|
/**
|
||||||
* This variable stores parent gui.
|
* This variable stores parent gui.
|
||||||
*/
|
*/
|
||||||
private CommonGUI parentGUI;
|
protected CommonGUI parentGUI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Variable stores Challenges addon.
|
* Variable stores Challenges addon.
|
||||||
@ -136,6 +136,7 @@ public abstract class CommonGUI
|
|||||||
|
|
||||||
protected static final String COMPLETE = "complete";
|
protected static final String COMPLETE = "complete";
|
||||||
|
|
||||||
|
protected static final String DOWNLOAD = "download";
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Section: Constructors
|
// Section: Constructors
|
||||||
@ -205,6 +206,40 @@ public abstract class CommonGUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor that inits panels with minimal requirements.
|
||||||
|
* @param parentGUI Parent panel for current panel.
|
||||||
|
*/
|
||||||
|
public CommonGUI(CommonGUI parentGUI)
|
||||||
|
{
|
||||||
|
this.addon = parentGUI.addon;
|
||||||
|
this.world = parentGUI.world;
|
||||||
|
this.user = parentGUI.user;
|
||||||
|
|
||||||
|
this.topLabel = parentGUI.topLabel;
|
||||||
|
this.permissionPrefix = parentGUI.permissionPrefix;
|
||||||
|
|
||||||
|
this.parentGUI = parentGUI;
|
||||||
|
|
||||||
|
this.pageIndex = 0;
|
||||||
|
|
||||||
|
this.returnButton = new PanelItemBuilder().
|
||||||
|
name(this.user.getTranslation("challenges.gui.buttons.return")).
|
||||||
|
icon(Material.OAK_DOOR).
|
||||||
|
clickHandler((panel, user1, clickType, i) -> {
|
||||||
|
|
||||||
|
if (this.parentGUI == null)
|
||||||
|
{
|
||||||
|
this.user.closeInventory();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parentGUI.build();
|
||||||
|
return true;
|
||||||
|
}).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Section: Common methods
|
// Section: Common methods
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
|
@ -63,7 +63,8 @@ public class AdminGUI extends CommonGUI
|
|||||||
EDIT_SETTINGS,
|
EDIT_SETTINGS,
|
||||||
DEFAULT_IMPORT_CHALLENGES,
|
DEFAULT_IMPORT_CHALLENGES,
|
||||||
DEFAULT_EXPORT_CHALLENGES,
|
DEFAULT_EXPORT_CHALLENGES,
|
||||||
COMPLETE_WIPE
|
COMPLETE_WIPE,
|
||||||
|
LIBRARY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -122,6 +123,8 @@ public class AdminGUI extends CommonGUI
|
|||||||
|
|
||||||
// Import Challenges
|
// Import Challenges
|
||||||
panelBuilder.item(15, this.createButton(Button.DEFAULT_IMPORT_CHALLENGES));
|
panelBuilder.item(15, this.createButton(Button.DEFAULT_IMPORT_CHALLENGES));
|
||||||
|
panelBuilder.item(24, this.createButton(Button.LIBRARY));
|
||||||
|
|
||||||
// Not added as I do not think admins should use it. It still will be able via command.
|
// Not added as I do not think admins should use it. It still will be able via command.
|
||||||
// panelBuilder.item(33, this.createButton(Button.DEFAULT_EXPORT_CHALLENGES));
|
// panelBuilder.item(33, this.createButton(Button.DEFAULT_EXPORT_CHALLENGES));
|
||||||
|
|
||||||
@ -439,6 +442,21 @@ public class AdminGUI extends CommonGUI
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case LIBRARY:
|
||||||
|
{
|
||||||
|
permissionSuffix = DOWNLOAD;
|
||||||
|
|
||||||
|
name = this.user.getTranslation("challenges.gui.buttons.admin.library");
|
||||||
|
description = this.user.getTranslation("challenges.gui.descriptions.admin.library");
|
||||||
|
icon = new ItemStack(Material.COBWEB);
|
||||||
|
clickHandler = (panel, user, clickType, slot) -> {
|
||||||
|
ListLibraryGUI.open(this);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
glow = false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// This should never happen.
|
// This should never happen.
|
||||||
return null;
|
return null;
|
||||||
|
@ -0,0 +1,212 @@
|
|||||||
|
package world.bentobox.challenges.panel.admin;
|
||||||
|
|
||||||
|
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import world.bentobox.bentobox.api.panels.PanelItem;
|
||||||
|
import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
|
||||||
|
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
|
||||||
|
import world.bentobox.bentobox.api.user.User;
|
||||||
|
import world.bentobox.challenges.ChallengesAddon;
|
||||||
|
import world.bentobox.challenges.panel.CommonGUI;
|
||||||
|
import world.bentobox.challenges.utils.GuiUtils;
|
||||||
|
import world.bentobox.challenges.web.object.LibraryEntry;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class contains all necessary elements to create GUI that lists all challenges.
|
||||||
|
* It allows to edit them or remove, depending on given input mode.
|
||||||
|
*/
|
||||||
|
public class ListLibraryGUI extends CommonGUI
|
||||||
|
{
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// Section: Constructor
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param parentGUI ParentGUI object.
|
||||||
|
*/
|
||||||
|
public ListLibraryGUI(CommonGUI parentGUI)
|
||||||
|
{
|
||||||
|
super(parentGUI);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param addon Addon where panel operates.
|
||||||
|
* @param world World from which panel was created.
|
||||||
|
* @param user User who created panel.
|
||||||
|
* @param topLabel Command top label which creates panel (f.e. island or ai)
|
||||||
|
* @param permissionPrefix Command permission prefix (f.e. bskyblock.)
|
||||||
|
*/
|
||||||
|
public ListLibraryGUI(ChallengesAddon addon,
|
||||||
|
World world,
|
||||||
|
User user,
|
||||||
|
String topLabel,
|
||||||
|
String permissionPrefix)
|
||||||
|
{
|
||||||
|
super(addon, world, user, topLabel, permissionPrefix, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This static method allows to easier open Library GUI.
|
||||||
|
* @param parentGui ParentGUI object.
|
||||||
|
*/
|
||||||
|
public static void open(CommonGUI parentGui)
|
||||||
|
{
|
||||||
|
new ListLibraryGUI(parentGui).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// Section: Methods
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void build()
|
||||||
|
{
|
||||||
|
PanelBuilder panelBuilder = new PanelBuilder().user(this.user).name(
|
||||||
|
this.user.getTranslation("challenges.gui.title.admin.library-title"));
|
||||||
|
|
||||||
|
GuiUtils.fillBorder(panelBuilder);
|
||||||
|
|
||||||
|
List<LibraryEntry> libraryEntries = this.addon.getWebManager().getLibraryEntries();
|
||||||
|
|
||||||
|
final int MAX_ELEMENTS = 21;
|
||||||
|
|
||||||
|
if (this.pageIndex < 0)
|
||||||
|
{
|
||||||
|
this.pageIndex = libraryEntries.size() / MAX_ELEMENTS;
|
||||||
|
}
|
||||||
|
else if (this.pageIndex > (libraryEntries.size() / MAX_ELEMENTS))
|
||||||
|
{
|
||||||
|
this.pageIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int entryIndex = MAX_ELEMENTS * this.pageIndex;
|
||||||
|
|
||||||
|
// I want first row to be only for navigation and return button.
|
||||||
|
int index = 10;
|
||||||
|
|
||||||
|
while (entryIndex < ((this.pageIndex + 1) * MAX_ELEMENTS) &&
|
||||||
|
entryIndex < libraryEntries.size() &&
|
||||||
|
index < 36)
|
||||||
|
{
|
||||||
|
if (!panelBuilder.slotOccupied(index))
|
||||||
|
{
|
||||||
|
panelBuilder.item(index, this.createEntryIcon(libraryEntries.get(entryIndex++)));
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigation buttons only if necessary
|
||||||
|
if (libraryEntries.size() > MAX_ELEMENTS)
|
||||||
|
{
|
||||||
|
panelBuilder.item(18, this.getButton(CommonButtons.PREVIOUS));
|
||||||
|
panelBuilder.item(26, this.getButton(CommonButtons.NEXT));
|
||||||
|
}
|
||||||
|
|
||||||
|
panelBuilder.item(44, this.returnButton);
|
||||||
|
|
||||||
|
panelBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method creates button for given library entry.
|
||||||
|
* @param libraryEntry LibraryEntry which button must be created.
|
||||||
|
* @return Entry button.
|
||||||
|
*/
|
||||||
|
private PanelItem createEntryIcon(LibraryEntry libraryEntry)
|
||||||
|
{
|
||||||
|
PanelItemBuilder itemBuilder = new PanelItemBuilder().
|
||||||
|
name(ChatColor.translateAlternateColorCodes('&', libraryEntry.getName())).
|
||||||
|
description(this.generateEntryDescription(libraryEntry)).
|
||||||
|
icon(libraryEntry.getIcon()).
|
||||||
|
glow(false);
|
||||||
|
|
||||||
|
itemBuilder.clickHandler((panel, user1, clickType, i) -> {
|
||||||
|
|
||||||
|
if (!this.blockedForDownland)
|
||||||
|
{
|
||||||
|
this.blockedForDownland = true;
|
||||||
|
|
||||||
|
this.user.sendMessage("challenges.messages.admin.start-downloading");
|
||||||
|
|
||||||
|
// Run download task after 5 ticks.
|
||||||
|
this.addon.getPlugin().getServer().getScheduler().
|
||||||
|
runTaskLaterAsynchronously(
|
||||||
|
this.addon.getPlugin(),
|
||||||
|
() -> this.addon.getWebManager().requestEntryGitHubData(this.user, this.world, libraryEntry),
|
||||||
|
5L);
|
||||||
|
|
||||||
|
if (this.parentGUI != null)
|
||||||
|
{
|
||||||
|
this.parentGUI.build();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.user.closeInventory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return itemBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method generated description for LibraryEntry object.
|
||||||
|
* @param entry LibraryEntry object which description must be generated.
|
||||||
|
* @return List of strings that will be placed in ItemStack lore message.
|
||||||
|
*/
|
||||||
|
private List<String> generateEntryDescription(LibraryEntry entry)
|
||||||
|
{
|
||||||
|
List<String> description = new ArrayList<>();
|
||||||
|
|
||||||
|
description.add(this.user.getTranslation(REFERENCE_DESCRIPTION + "library-author",
|
||||||
|
"[author]",
|
||||||
|
entry.getAuthor()));
|
||||||
|
description.add(entry.getDescription());
|
||||||
|
|
||||||
|
description.add(this.user.getTranslation(REFERENCE_DESCRIPTION + "library-gamemode",
|
||||||
|
"[gamemode]",
|
||||||
|
entry.getForGameMode()));
|
||||||
|
description.add(this.user.getTranslation(REFERENCE_DESCRIPTION + "library-lang",
|
||||||
|
"[lang]",
|
||||||
|
entry.getLanguage()));
|
||||||
|
description.add(this.user.getTranslation(REFERENCE_DESCRIPTION + "library-version",
|
||||||
|
"[version]",
|
||||||
|
entry.getVersion()));
|
||||||
|
|
||||||
|
return GuiUtils.stringSplit(description,
|
||||||
|
this.addon.getChallengesSettings().getLoreLineLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// Section: Instance Variables
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This variable will protect against spam-click.
|
||||||
|
*/
|
||||||
|
private boolean blockedForDownland;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference string to description.
|
||||||
|
*/
|
||||||
|
private static final String REFERENCE_DESCRIPTION = "challenges.gui.descriptions.admin.";
|
||||||
|
}
|
225
src/main/java/world/bentobox/challenges/web/WebManager.java
Normal file
225
src/main/java/world/bentobox/challenges/web/WebManager.java
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
package world.bentobox.challenges.web;
|
||||||
|
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import io.github.TheBusyBiscuit.GitHubWebAPI4Java.GitHubWebAPI;
|
||||||
|
import io.github.TheBusyBiscuit.GitHubWebAPI4Java.objects.repositories.GitHubRepository;
|
||||||
|
import world.bentobox.bentobox.BentoBox;
|
||||||
|
import world.bentobox.bentobox.api.user.User;
|
||||||
|
import world.bentobox.challenges.ChallengesAddon;
|
||||||
|
import world.bentobox.challenges.web.object.LibraryEntry;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class manages content downloading from web repository.
|
||||||
|
*/
|
||||||
|
public class WebManager
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Default constructor
|
||||||
|
* @param addon Challenges Addon object.
|
||||||
|
*/
|
||||||
|
public WebManager(ChallengesAddon addon)
|
||||||
|
{
|
||||||
|
this.addon = addon;
|
||||||
|
this.plugin = addon.getPlugin();
|
||||||
|
|
||||||
|
this.library = new ArrayList<>(0);
|
||||||
|
|
||||||
|
if (this.plugin.getSettings().isGithubDownloadData())
|
||||||
|
{
|
||||||
|
long connectionInterval = this.plugin.getSettings().getGithubConnectionInterval() * 20L * 60L;
|
||||||
|
|
||||||
|
if (connectionInterval <= 0)
|
||||||
|
{
|
||||||
|
// If below 0, it means we shouldn't run this as a repeating task.
|
||||||
|
this.plugin.getServer().getScheduler().runTaskLaterAsynchronously(this.plugin,
|
||||||
|
() -> this.requestCatalogGitHubData(true),
|
||||||
|
20L);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Set connection interval to be at least 60 minutes.
|
||||||
|
connectionInterval = Math.max(connectionInterval, 60 * 20 * 60L);
|
||||||
|
this.plugin.getServer().getScheduler().runTaskTimerAsynchronously(this.plugin,
|
||||||
|
() -> this.requestCatalogGitHubData(true),
|
||||||
|
20L,
|
||||||
|
connectionInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method requests catalog entries from challenges library.
|
||||||
|
* @param clearCache Boolean that indicates if all cached values must be cleared.
|
||||||
|
*/
|
||||||
|
public void requestCatalogGitHubData(boolean clearCache)
|
||||||
|
{
|
||||||
|
this.plugin.getWebManager().getGitHub().ifPresent(gh ->
|
||||||
|
{
|
||||||
|
if (this.plugin.getSettings().isLogGithubDownloadData())
|
||||||
|
{
|
||||||
|
this.plugin.log("Downloading data from GitHub...");
|
||||||
|
}
|
||||||
|
|
||||||
|
GitHubRepository repo = new GitHubRepository(gh, "BentoBoxWorld/weblink");
|
||||||
|
|
||||||
|
String catalogContent = "";
|
||||||
|
|
||||||
|
// Downloading the data
|
||||||
|
try
|
||||||
|
{
|
||||||
|
catalogContent = repo.getContent("challenges/catalog.json").getContent().replaceAll("\\n", "");
|
||||||
|
}
|
||||||
|
catch (IllegalAccessException e)
|
||||||
|
{
|
||||||
|
if (this.plugin.getSettings().isLogGithubDownloadData())
|
||||||
|
{
|
||||||
|
this.plugin.log("Could not connect to GitHub.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
this.plugin.logError("An error occurred when downloading data from GitHub...");
|
||||||
|
this.plugin.logStacktrace(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// People were concerned that the download took ages, so we need to tell them it's over now.
|
||||||
|
if (this.plugin.getSettings().isLogGithubDownloadData())
|
||||||
|
{
|
||||||
|
this.plugin.log("Successfully downloaded data from GitHub.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decoding the Base64 encoded contents
|
||||||
|
catalogContent = new String(Base64.getDecoder().decode(catalogContent),
|
||||||
|
StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
/* Parsing the data */
|
||||||
|
|
||||||
|
// Register the catalog data
|
||||||
|
if (!catalogContent.isEmpty())
|
||||||
|
{
|
||||||
|
if (clearCache)
|
||||||
|
{
|
||||||
|
this.library.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject catalog = new JsonParser().parse(catalogContent).getAsJsonObject();
|
||||||
|
catalog.getAsJsonArray("challenges").forEach(gamemode ->
|
||||||
|
this.library.add(new LibraryEntry(gamemode.getAsJsonObject())));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method requests GitHub data for given LibraryEntry object.
|
||||||
|
* @param user User who inits request.
|
||||||
|
* @param world Target world where challenges should be loaded.
|
||||||
|
* @param entry Entry that contains information about requested object.
|
||||||
|
* @return {@code true} if request was successful, {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
public boolean requestEntryGitHubData(User user, World world, LibraryEntry entry)
|
||||||
|
{
|
||||||
|
Optional<GitHubWebAPI> gitAPI = this.plugin.getWebManager().getGitHub();
|
||||||
|
|
||||||
|
if (gitAPI.isPresent())
|
||||||
|
{
|
||||||
|
if (this.plugin.getSettings().isLogGithubDownloadData())
|
||||||
|
{
|
||||||
|
this.plugin.log("Downloading data from GitHub...");
|
||||||
|
}
|
||||||
|
|
||||||
|
GitHubRepository repo = new GitHubRepository(gitAPI.get(), "BentoBoxWorld/weblink");
|
||||||
|
|
||||||
|
String challengeLibrary = "";
|
||||||
|
|
||||||
|
// Downloading the data
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
challengeLibrary = repo.getContent("challenges/library/" + entry.getRepository() + ".json").
|
||||||
|
getContent().
|
||||||
|
replaceAll("\\n", "");
|
||||||
|
}
|
||||||
|
catch (IllegalAccessException e)
|
||||||
|
{
|
||||||
|
if (this.plugin.getSettings().isLogGithubDownloadData())
|
||||||
|
{
|
||||||
|
this.plugin.log("Could not connect to GitHub.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
this.plugin.logError("An error occurred when downloading data from GitHub...");
|
||||||
|
this.plugin.logStacktrace(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// People were concerned that the download took ages, so we need to tell them it's over now.
|
||||||
|
if (this.plugin.getSettings().isLogGithubDownloadData())
|
||||||
|
{
|
||||||
|
this.plugin.log("Successfully downloaded data from GitHub.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decoding the Base64 encoded contents
|
||||||
|
challengeLibrary = new String(Base64.getDecoder().decode(challengeLibrary),
|
||||||
|
StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
/* Parsing the data */
|
||||||
|
|
||||||
|
// Process downloaded library data
|
||||||
|
if (!challengeLibrary.isEmpty())
|
||||||
|
{
|
||||||
|
this.addon.getImportManager().loadDownloadedChallenges(user, world, challengeLibrary);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// Section: Getters
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns all library entries that are downlaoded.
|
||||||
|
* @return existing Library entries.
|
||||||
|
*/
|
||||||
|
public List<LibraryEntry> getLibraryEntries()
|
||||||
|
{
|
||||||
|
List<LibraryEntry> entries = new ArrayList<>(this.library);
|
||||||
|
entries.sort(Comparator.comparingInt(LibraryEntry::getSlot));
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// Section: Variables
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Challenges Addon variable.
|
||||||
|
*/
|
||||||
|
private ChallengesAddon addon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BentoBox plugin variable.
|
||||||
|
*/
|
||||||
|
private BentoBox plugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This list contains all entries that were downloaded from GitHub.
|
||||||
|
*/
|
||||||
|
private List<LibraryEntry> library;
|
||||||
|
}
|
@ -0,0 +1,186 @@
|
|||||||
|
package world.bentobox.challenges.web.object;
|
||||||
|
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.eclipse.jdt.annotation.NonNull;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This objects allows to load each Challenges Catalog library entry.
|
||||||
|
*/
|
||||||
|
public class LibraryEntry
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
* @param object Json Object that must be translated to LibraryEntry.
|
||||||
|
*/
|
||||||
|
public LibraryEntry(@NonNull JsonObject object)
|
||||||
|
{
|
||||||
|
this.name = object.get("name").getAsString();
|
||||||
|
|
||||||
|
Material material = Material.matchMaterial(object.get("icon").getAsString());
|
||||||
|
this.icon = (material != null) ? material : Material.PAPER;
|
||||||
|
|
||||||
|
this.description = object.get("description").getAsString();
|
||||||
|
this.repository = object.get("repository").getAsString();
|
||||||
|
this.language = object.get("language").getAsString();
|
||||||
|
|
||||||
|
this.slot = object.get("slot").getAsInt();
|
||||||
|
|
||||||
|
this.forGameMode = object.get("for").getAsString();
|
||||||
|
this.author = object.get("author").getAsString();
|
||||||
|
this.version = object.get("version").getAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the name value.
|
||||||
|
* @return the value of name.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the icon value.
|
||||||
|
* @return the value of icon.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Material getIcon()
|
||||||
|
{
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the description value.
|
||||||
|
* @return the value of description.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public String getDescription()
|
||||||
|
{
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the repository value.
|
||||||
|
* @return the value of repository.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public String getRepository()
|
||||||
|
{
|
||||||
|
return repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the language value.
|
||||||
|
* @return the value of language.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public String getLanguage()
|
||||||
|
{
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the slot value.
|
||||||
|
* @return the value of slot.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public int getSlot()
|
||||||
|
{
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the forGameMode value.
|
||||||
|
* @return the value of forGameMode.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public String getForGameMode()
|
||||||
|
{
|
||||||
|
return forGameMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the author value.
|
||||||
|
* @return the value of author.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public String getAuthor()
|
||||||
|
{
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the version value.
|
||||||
|
* @return the value of version.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public String getVersion()
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// Section: Variables
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of entry object
|
||||||
|
*/
|
||||||
|
private @NonNull String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defaults to {@link Material#PAPER}.
|
||||||
|
*/
|
||||||
|
private @NonNull Material icon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description of entry object.
|
||||||
|
*/
|
||||||
|
private @NonNull String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File name in challenges library.
|
||||||
|
*/
|
||||||
|
private @NonNull String repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Language of content.
|
||||||
|
*/
|
||||||
|
private @Nullable String language;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Desired slot number.
|
||||||
|
*/
|
||||||
|
private int slot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main GameMode for which challenges were created.
|
||||||
|
*/
|
||||||
|
private @Nullable String forGameMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Author (-s) who created current configuration.
|
||||||
|
*/
|
||||||
|
private @Nullable String author;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version of Challenges Addon, for which challenges were created.
|
||||||
|
*/
|
||||||
|
private @Nullable String version;
|
||||||
|
}
|
@ -67,6 +67,8 @@ challenges:
|
|||||||
select-entity: '&aSelect Entity'
|
select-entity: '&aSelect Entity'
|
||||||
toggle-environment: '&aToggle Environment'
|
toggle-environment: '&aToggle Environment'
|
||||||
edit-text-fields: '&aEdit Text Fields'
|
edit-text-fields: '&aEdit Text Fields'
|
||||||
|
|
||||||
|
library-title: '&aDownloadable Libraries'
|
||||||
challenges: '&6Challenges'
|
challenges: '&6Challenges'
|
||||||
game-modes: '&6Choose GameMode'
|
game-modes: '&6Choose GameMode'
|
||||||
|
|
||||||
@ -161,6 +163,8 @@ challenges:
|
|||||||
default-import: 'Import Default Challenges'
|
default-import: 'Import Default Challenges'
|
||||||
default-export: 'Export Existing Challenges'
|
default-export: 'Export Existing Challenges'
|
||||||
complete-wipe: 'Wipe Addon Databases'
|
complete-wipe: 'Wipe Addon Databases'
|
||||||
|
|
||||||
|
library: 'Web Library'
|
||||||
next: 'Next'
|
next: 'Next'
|
||||||
previous: 'Previous'
|
previous: 'Previous'
|
||||||
return: 'Return'
|
return: 'Return'
|
||||||
@ -261,6 +265,14 @@ challenges:
|
|||||||
default-import: 'Allows to import default challenges.'
|
default-import: 'Allows to import default challenges.'
|
||||||
default-export: 'Allows to export existing challenges into defaults.json file.'
|
default-export: 'Allows to export existing challenges into defaults.json file.'
|
||||||
complete-wipe: 'Allows to completely clear all challenges addon databases. Includes player data!'
|
complete-wipe: 'Allows to completely clear all challenges addon databases. Includes player data!'
|
||||||
|
|
||||||
|
library: 'Opens GUI that shows all available public Challenges Libraries.'
|
||||||
|
|
||||||
|
library-author: 'by &e[author]'
|
||||||
|
library-version: '&9Made on Challenges [version]'
|
||||||
|
library-lang: '&aLanguage: [lang]'
|
||||||
|
library-gamemode: '&aPrimary for [gamemode]'
|
||||||
|
|
||||||
current-value: '|&6Current value: [value].'
|
current-value: '|&6Current value: [value].'
|
||||||
enabled: 'Active'
|
enabled: 'Active'
|
||||||
disabled: 'Disabled'
|
disabled: 'Disabled'
|
||||||
@ -368,6 +380,8 @@ challenges:
|
|||||||
migrate-start: '&2Start migrating challenges addon data.'
|
migrate-start: '&2Start migrating challenges addon data.'
|
||||||
migrate-end: '&2Challenges addon data is updated to new format.'
|
migrate-end: '&2Challenges addon data is updated to new format.'
|
||||||
migrate-not: '&2All data is valid.'
|
migrate-not: '&2All data is valid.'
|
||||||
|
|
||||||
|
start-downloading: '&5Starting to download and import Challenges Library.'
|
||||||
you-completed-challenge: '&2You completed the [value] &r&2challenge!'
|
you-completed-challenge: '&2You completed the [value] &r&2challenge!'
|
||||||
you-repeated-challenge: '&2You repeated the [value] &r&2challenge!'
|
you-repeated-challenge: '&2You repeated the [value] &r&2challenge!'
|
||||||
you-repeated-challenge-multiple: '&2You repeated the [value] &r&2challenge [count] times!'
|
you-repeated-challenge-multiple: '&2You repeated the [value] &r&2challenge [count] times!'
|
||||||
|
Loading…
Reference in New Issue
Block a user