Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/main/java/world/bentobox/controlpanel/ControlPanelAddon.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,19 @@ public void onReload()
}
else
{
// Reload the database into cache first so wipe/re-import operate on a
// consistent view of what is currently stored.
this.manager.reload();

// Re-import each active game mode's panels from controlPanelTemplate.yml so
// that admin edits to the template take effect on reload. Without this the
// panels stay pinned to whatever was first seeded into the database.
this.getPlugin().getAddonsManager().getGameModeAddons().forEach(gameModeAddon -> {
if (!this.settings.getDisabledGameModes().contains(gameModeAddon.getDescription().getName()))
{
this.manager.reimportControlPanels(gameModeAddon);
}
});
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,10 @@ public void setup()
@Override
public boolean execute(User user, String label, List<String> args)
{
ControlPanelManager manager = this.<ControlPanelAddon>getAddon().getAddonManager();
ControlPanelAddon addon = this.getAddon();
ControlPanelManager manager = addon.getAddonManager();

String fileName = args.size() == 1 ? args.get(0) : "controlPanelTemplate.yml";
String fileName = args.size() == 1 ? args.get(0) : addon.getSettings().getTemplateFile();

if (manager.hasAnyControlPanel(this.getWorld()))
{
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/world/bentobox/controlpanel/config/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,28 @@ public void setDisabledGameModes(Set<String> disabledGameModes)
}


/**
* This method returns the templateFile value.
*
* @return the value of templateFile.
*/
public String getTemplateFile()
{
return templateFile;
}


/**
* This method sets the templateFile value.
*
* @param templateFile the templateFile new value.
*/
public void setTemplateFile(String templateFile)
{
this.templateFile = templateFile;
}


// ---------------------------------------------------------------------
// Section: Variables
// ---------------------------------------------------------------------
Expand All @@ -64,4 +86,12 @@ public void setDisabledGameModes(Set<String> disabledGameModes)
@ConfigComment(" - BSkyBlock")
@ConfigEntry(path = "disabled-gamemodes")
private Set<String> disabledGameModes = new HashSet<>();

@ConfigComment("")
@ConfigComment("The template file that control panels are imported from.")
@ConfigComment("This file is read when panels are first seeded and re-read on every reload,")
@ConfigComment("so editing it and running 'bbox reload' will apply your changes.")
@ConfigComment("It must exist in the addon folder (addons/ControlPanel).")
@ConfigEntry(path = "template-file")
private String templateFile = "controlPanelTemplate.yml";
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ public ControlPanelManager(ControlPanelAddon addon)
{
this.addon = addon;

// save template file into directory.
// Save the default template file into the directory. The configured template file
// may point elsewhere, but the packaged default is always named controlPanelTemplate.yml.
if (!new File(this.addon.getDataFolder(), "controlPanelTemplate.yml").exists())
{
this.addon.saveResource("controlPanelTemplate.yml", false);
Expand Down Expand Up @@ -128,6 +129,26 @@ public void reload()
}


/**
* This method re-imports the control panels for the given game mode from the
* template file configured via {@code template-file} in config.yml (defaults to
* {@code controlPanelTemplate.yml}), replacing whatever is currently stored in the
* database and cache.
* <p>
* This is what makes edits to the template file take effect on {@code bbox reload}:
* without it, {@link #reload()} only re-reads the database and template changes are
* silently ignored.
*
* @param gameModeAddon Game mode whose panels must be re-imported from the template.
*/
public void reimportControlPanels(@NotNull GameModeAddon gameModeAddon)
{
// Clear existing data so removed/renamed panels do not linger, then re-read the template.
this.wipeData(gameModeAddon, null);
this.importControlPanels(null, gameModeAddon);
}


// ---------------------------------------------------------------------
// Section: Save methods
// ---------------------------------------------------------------------
Expand Down Expand Up @@ -226,7 +247,7 @@ public void importControlPanels(@Nullable User user, @NotNull World world, @NotN
*/
public void importControlPanels(@Nullable User user, @NotNull GameModeAddon addon)
{
this.importControlPanels(user, addon, "controlPanelTemplate");
this.importControlPanels(user, addon, this.addon.getSettings().getTemplateFile());
}


Expand Down
6 changes: 6 additions & 0 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@
# disabled-gamemodes:
# - BSkyBlock
disabled-gamemodes: []
#
# The template file that control panels are imported from.
# This file is read when panels are first seeded and re-read on every reload,
# so editing it and running 'bbox reload' will apply your changes.
# It must exist in the addon folder (addons/ControlPanel).
template-file: controlPanelTemplate.yml
11 changes: 11 additions & 0 deletions src/test/java/world/bentobox/controlpanel/config/SettingsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,15 @@ void testSetDisabledGameModes() {
assertTrue(settings.getDisabledGameModes().contains("BSkyBlock"));
assertTrue(settings.getDisabledGameModes().contains("AcidIsland"));
}

@Test
void testDefaultTemplateFile() {
assertEquals("controlPanelTemplate.yml", settings.getTemplateFile());
}

@Test
void testSetTemplateFile() {
settings.setTemplateFile("myPanels.yml");
assertEquals("myPanels.yml", settings.getTemplateFile());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public void setUp() throws Exception {

when(addon.getPlugin()).thenReturn(plugin);
when(addon.getLogger()).thenReturn(Logger.getAnonymousLogger());
when(addon.getSettings()).thenReturn(new world.bentobox.controlpanel.config.Settings());

File dataFolder = new File("addons/ControlPanel");
dataFolder.mkdirs();
Expand Down Expand Up @@ -260,6 +261,96 @@ void testReload() {
manager.reload();
}

@Test
void testReimportControlPanelsReadsTemplateFile() throws Exception {
// Make import's trailing getAddonManager().save() call resolve to this manager.
when(addon.getAddonManager()).thenReturn(manager);

// Write a template file that reimport should read from disk.
writeTemplate("""
panel-list:
default:
defaultPanel: true
panelName: 'From Template'
permission: 'default'
buttons:
0:
name: 'Island'
material: GRASS_BLOCK
description: 'Go to your island'
command: '[label] go'
""");

GameModeAddon gameModeAddon = mock(GameModeAddon.class);
manager.reimportControlPanels(gameModeAddon);

// Template panel is now in the cache.
assertTrue(manager.hasAnyControlPanel(world));
ControlPanelObject panel = manager.getUserControlPanel(User.getInstance(mockPlayer), world, "bskyblock.");
assertNotNull(panel);
assertEquals("From Template", panel.getPanelName());
}

@Test
void testReimportControlPanelsRemovesDeletedPanels() throws Exception {
when(addon.getAddonManager()).thenReturn(manager);

// Seed the cache with an existing panel, as if previously stored in the database.
when(handler.loadObjects()).thenReturn(Collections.singletonList(createDefaultPanel()));
manager.reload();
assertTrue(manager.hasAnyControlPanel(world));

// A template with no panel-list entries should wipe the stored panel on reimport.
writeTemplate("panel-list: {}\n");

GameModeAddon gameModeAddon = mock(GameModeAddon.class);
manager.reimportControlPanels(gameModeAddon);

assertFalse(manager.hasAnyControlPanel(world));
}

@Test
void testReimportControlPanelsUsesConfiguredTemplateFile() throws Exception {
// Point the config at a custom template file name.
world.bentobox.controlpanel.config.Settings settings =
new world.bentobox.controlpanel.config.Settings();
settings.setTemplateFile("customPanels.yml");
when(addon.getSettings()).thenReturn(settings);
when(addon.getAddonManager()).thenReturn(manager);

// The default template exists but is empty; only the custom file has a panel.
writeTemplate("panel-list: {}\n");
writeNamedTemplate("customPanels.yml", """
panel-list:
default:
defaultPanel: true
panelName: 'From Custom File'
permission: 'default'
buttons:
0:
name: 'Island'
material: GRASS_BLOCK
description: 'Go to your island'
command: '[label] go'
""");

GameModeAddon gameModeAddon = mock(GameModeAddon.class);
manager.reimportControlPanels(gameModeAddon);

ControlPanelObject panel = manager.getUserControlPanel(User.getInstance(mockPlayer), world, "bskyblock.");
assertNotNull(panel);
assertEquals("From Custom File", panel.getPanelName());
}

private void writeTemplate(String content) throws Exception {
writeNamedTemplate("controlPanelTemplate.yml", content);
}

private void writeNamedTemplate(String name, String content) throws Exception {
File templateFile = new File(new File("addons/ControlPanel"), name);
java.nio.file.Files.writeString(templateFile.toPath(), content);
}

private ControlPanelObject createDefaultPanel() {
ControlPanelObject cpo = new ControlPanelObject();
cpo.setUniqueId("BSkyBlock_default");
Expand Down
Loading