Skip to content

Commit a3be0bd

Browse files
tastybentoclaude
andcommitted
Reload re-imports control panels from the template file
Control panels were pinned to the database after the first seed, so editing controlPanelTemplate.yml and running 'bbox reload' had no effect: onReload only re-read the database. The only way to apply template edits was the confirmation-gated admin import command. onReload now wipes and re-imports each active game mode from the template so plain reloads pick up edits. The template file name is configurable via a new 'template-file' entry in config.yml (default controlPanelTemplate.yml), honored by reload, importControlPanels, and the admin import command. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0118vFoM1ejLPLUGdz4sLunb
1 parent 693e6d6 commit a3be0bd

7 files changed

Lines changed: 176 additions & 4 deletions

File tree

src/main/java/world/bentobox/controlpanel/ControlPanelAddon.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,19 @@ public void onReload()
138138
}
139139
else
140140
{
141+
// Reload the database into cache first so wipe/re-import operate on a
142+
// consistent view of what is currently stored.
141143
this.manager.reload();
144+
145+
// Re-import each active game mode's panels from controlPanelTemplate.yml so
146+
// that admin edits to the template take effect on reload. Without this the
147+
// panels stay pinned to whatever was first seeded into the database.
148+
this.getPlugin().getAddonsManager().getGameModeAddons().forEach(gameModeAddon -> {
149+
if (!this.settings.getDisabledGameModes().contains(gameModeAddon.getDescription().getName()))
150+
{
151+
this.manager.reimportControlPanels(gameModeAddon);
152+
}
153+
});
142154
}
143155
}
144156

src/main/java/world/bentobox/controlpanel/commands/admin/AdminCommand.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,10 @@ public void setup()
127127
@Override
128128
public boolean execute(User user, String label, List<String> args)
129129
{
130-
ControlPanelManager manager = this.<ControlPanelAddon>getAddon().getAddonManager();
130+
ControlPanelAddon addon = this.getAddon();
131+
ControlPanelManager manager = addon.getAddonManager();
131132

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

134135
if (manager.hasAnyControlPanel(this.getWorld()))
135136
{

src/main/java/world/bentobox/controlpanel/config/Settings.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,28 @@ public void setDisabledGameModes(Set<String> disabledGameModes)
5252
}
5353

5454

55+
/**
56+
* This method returns the templateFile value.
57+
*
58+
* @return the value of templateFile.
59+
*/
60+
public String getTemplateFile()
61+
{
62+
return templateFile;
63+
}
64+
65+
66+
/**
67+
* This method sets the templateFile value.
68+
*
69+
* @param templateFile the templateFile new value.
70+
*/
71+
public void setTemplateFile(String templateFile)
72+
{
73+
this.templateFile = templateFile;
74+
}
75+
76+
5577
// ---------------------------------------------------------------------
5678
// Section: Variables
5779
// ---------------------------------------------------------------------
@@ -64,4 +86,12 @@ public void setDisabledGameModes(Set<String> disabledGameModes)
6486
@ConfigComment(" - BSkyBlock")
6587
@ConfigEntry(path = "disabled-gamemodes")
6688
private Set<String> disabledGameModes = new HashSet<>();
89+
90+
@ConfigComment("")
91+
@ConfigComment("The template file that control panels are imported from.")
92+
@ConfigComment("This file is read when panels are first seeded and re-read on every reload,")
93+
@ConfigComment("so editing it and running 'bbox reload' will apply your changes.")
94+
@ConfigComment("It must exist in the addon folder (addons/ControlPanel).")
95+
@ConfigEntry(path = "template-file")
96+
private String templateFile = "controlPanelTemplate.yml";
6797
}

src/main/java/world/bentobox/controlpanel/managers/ControlPanelManager.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ public ControlPanelManager(ControlPanelAddon addon)
5555
{
5656
this.addon = addon;
5757

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

130131

132+
/**
133+
* This method re-imports the control panels for the given game mode from the
134+
* template file configured via {@code template-file} in config.yml (defaults to
135+
* {@code controlPanelTemplate.yml}), replacing whatever is currently stored in the
136+
* database and cache.
137+
* <p>
138+
* This is what makes edits to the template file take effect on {@code bbox reload}:
139+
* without it, {@link #reload()} only re-reads the database and template changes are
140+
* silently ignored.
141+
*
142+
* @param gameModeAddon Game mode whose panels must be re-imported from the template.
143+
*/
144+
public void reimportControlPanels(@NotNull GameModeAddon gameModeAddon)
145+
{
146+
// Clear existing data so removed/renamed panels do not linger, then re-read the template.
147+
this.wipeData(gameModeAddon, null);
148+
this.importControlPanels(null, gameModeAddon);
149+
}
150+
151+
131152
// ---------------------------------------------------------------------
132153
// Section: Save methods
133154
// ---------------------------------------------------------------------
@@ -226,7 +247,7 @@ public void importControlPanels(@Nullable User user, @NotNull World world, @NotN
226247
*/
227248
public void importControlPanels(@Nullable User user, @NotNull GameModeAddon addon)
228249
{
229-
this.importControlPanels(user, addon, "controlPanelTemplate");
250+
this.importControlPanels(user, addon, this.addon.getSettings().getTemplateFile());
230251
}
231252

232253

src/main/resources/config.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,9 @@
55
# disabled-gamemodes:
66
# - BSkyBlock
77
disabled-gamemodes: []
8+
#
9+
# The template file that control panels are imported from.
10+
# This file is read when panels are first seeded and re-read on every reload,
11+
# so editing it and running 'bbox reload' will apply your changes.
12+
# It must exist in the addon folder (addons/ControlPanel).
13+
template-file: controlPanelTemplate.yml

src/test/java/world/bentobox/controlpanel/config/SettingsTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,15 @@ void testSetDisabledGameModes() {
3535
assertTrue(settings.getDisabledGameModes().contains("BSkyBlock"));
3636
assertTrue(settings.getDisabledGameModes().contains("AcidIsland"));
3737
}
38+
39+
@Test
40+
void testDefaultTemplateFile() {
41+
assertEquals("controlPanelTemplate.yml", settings.getTemplateFile());
42+
}
43+
44+
@Test
45+
void testSetTemplateFile() {
46+
settings.setTemplateFile("myPanels.yml");
47+
assertEquals("myPanels.yml", settings.getTemplateFile());
48+
}
3849
}

src/test/java/world/bentobox/controlpanel/managers/ControlPanelManagerTest.java

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public void setUp() throws Exception {
5757

5858
when(addon.getPlugin()).thenReturn(plugin);
5959
when(addon.getLogger()).thenReturn(Logger.getAnonymousLogger());
60+
when(addon.getSettings()).thenReturn(new world.bentobox.controlpanel.config.Settings());
6061

6162
File dataFolder = new File("addons/ControlPanel");
6263
dataFolder.mkdirs();
@@ -260,6 +261,96 @@ void testReload() {
260261
manager.reload();
261262
}
262263

264+
@Test
265+
void testReimportControlPanelsReadsTemplateFile() throws Exception {
266+
// Make import's trailing getAddonManager().save() call resolve to this manager.
267+
when(addon.getAddonManager()).thenReturn(manager);
268+
269+
// Write a template file that reimport should read from disk.
270+
writeTemplate("""
271+
panel-list:
272+
default:
273+
defaultPanel: true
274+
panelName: 'From Template'
275+
permission: 'default'
276+
buttons:
277+
0:
278+
name: 'Island'
279+
material: GRASS_BLOCK
280+
description: 'Go to your island'
281+
command: '[label] go'
282+
""");
283+
284+
GameModeAddon gameModeAddon = mock(GameModeAddon.class);
285+
manager.reimportControlPanels(gameModeAddon);
286+
287+
// Template panel is now in the cache.
288+
assertTrue(manager.hasAnyControlPanel(world));
289+
ControlPanelObject panel = manager.getUserControlPanel(User.getInstance(mockPlayer), world, "bskyblock.");
290+
assertNotNull(panel);
291+
assertEquals("From Template", panel.getPanelName());
292+
}
293+
294+
@Test
295+
void testReimportControlPanelsRemovesDeletedPanels() throws Exception {
296+
when(addon.getAddonManager()).thenReturn(manager);
297+
298+
// Seed the cache with an existing panel, as if previously stored in the database.
299+
when(handler.loadObjects()).thenReturn(Collections.singletonList(createDefaultPanel()));
300+
manager.reload();
301+
assertTrue(manager.hasAnyControlPanel(world));
302+
303+
// A template with no panel-list entries should wipe the stored panel on reimport.
304+
writeTemplate("panel-list: {}\n");
305+
306+
GameModeAddon gameModeAddon = mock(GameModeAddon.class);
307+
manager.reimportControlPanels(gameModeAddon);
308+
309+
assertFalse(manager.hasAnyControlPanel(world));
310+
}
311+
312+
@Test
313+
void testReimportControlPanelsUsesConfiguredTemplateFile() throws Exception {
314+
// Point the config at a custom template file name.
315+
world.bentobox.controlpanel.config.Settings settings =
316+
new world.bentobox.controlpanel.config.Settings();
317+
settings.setTemplateFile("customPanels.yml");
318+
when(addon.getSettings()).thenReturn(settings);
319+
when(addon.getAddonManager()).thenReturn(manager);
320+
321+
// The default template exists but is empty; only the custom file has a panel.
322+
writeTemplate("panel-list: {}\n");
323+
writeNamedTemplate("customPanels.yml", """
324+
panel-list:
325+
default:
326+
defaultPanel: true
327+
panelName: 'From Custom File'
328+
permission: 'default'
329+
buttons:
330+
0:
331+
name: 'Island'
332+
material: GRASS_BLOCK
333+
description: 'Go to your island'
334+
command: '[label] go'
335+
""");
336+
337+
GameModeAddon gameModeAddon = mock(GameModeAddon.class);
338+
manager.reimportControlPanels(gameModeAddon);
339+
340+
ControlPanelObject panel = manager.getUserControlPanel(User.getInstance(mockPlayer), world, "bskyblock.");
341+
assertNotNull(panel);
342+
assertEquals("From Custom File", panel.getPanelName());
343+
}
344+
345+
private void writeTemplate(String content) throws Exception {
346+
writeNamedTemplate("controlPanelTemplate.yml", content);
347+
}
348+
349+
private void writeNamedTemplate(String name, String content) throws Exception {
350+
File templateFile = new File(new File("addons/ControlPanel"), name);
351+
java.nio.file.Files.writeString(templateFile.toPath(), content);
352+
}
353+
263354
private ControlPanelObject createDefaultPanel() {
264355
ControlPanelObject cpo = new ControlPanelObject();
265356
cpo.setUniqueId("BSkyBlock_default");

0 commit comments

Comments
 (0)