Skip to content

Commit 59bc6c2

Browse files
authored
Merge pull request #16 from NighterDevelopment/copilot/fix-2bd027ed-8f95-407d-a11f-bec55933ed0b
Implement and integrate SpawnerMenuFormUI for Bedrock players with configurable language support
2 parents 6ad045c + 8d6af4a commit 59bc6c2

6 files changed

Lines changed: 192 additions & 35 deletions

File tree

core/src/main/java/github/nighter/smartspawner/SmartSpawner.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import github.nighter.smartspawner.spawner.gui.main.ItemCache;
2525
import github.nighter.smartspawner.spawner.gui.main.SpawnerMenuAction;
2626
import github.nighter.smartspawner.spawner.gui.main.SpawnerMenuUI;
27+
import github.nighter.smartspawner.spawner.gui.main.SpawnerMenuFormUI;
2728
import github.nighter.smartspawner.spawner.gui.stacker.SpawnerStackerHandler;
2829
import github.nighter.smartspawner.spawner.gui.storage.filter.FilterConfigUI;
2930
import github.nighter.smartspawner.spawner.gui.synchronization.SpawnerGuiViewManager;
@@ -86,6 +87,7 @@ public class SmartSpawner extends JavaPlugin implements SmartSpawnerPlugin {
8687
private GuiLayoutConfig guiLayoutConfig;
8788
private final ItemCache itemCache = new ItemCache(500, 30);
8889
private SpawnerMenuUI spawnerMenuUI;
90+
private SpawnerMenuFormUI spawnerMenuFormUI;
8991
private SpawnerStorageUI spawnerStorageUI;
9092
private FilterConfigUI filterConfigUI;
9193
private SpawnerStackerUI spawnerStackerUI;
@@ -236,6 +238,7 @@ private void initializeCoreComponents() {
236238
this.spawnerStorageUI = new SpawnerStorageUI(this);
237239
this.filterConfigUI = new FilterConfigUI(this);
238240
this.spawnerMenuUI = new SpawnerMenuUI(this);
241+
this.spawnerMenuFormUI = new SpawnerMenuFormUI(this);
239242
this.spawnerGuiViewManager = new SpawnerGuiViewManager(this);
240243
this.spawnerLootGenerator = new SpawnerLootGenerator(this);
241244
this.spawnerSellManager = new SpawnerSellManager(this);
@@ -426,4 +429,8 @@ public void debug(String message) {
426429
getLogger().info("[DEBUG] " + message);
427430
}
428431
}
432+
433+
public SpawnerMenuFormUI getSpawnerMenuFormUI() {
434+
return spawnerMenuFormUI;
435+
}
429436
}

core/src/main/java/github/nighter/smartspawner/spawner/gui/main/SpawnerMenuFormUI.java

Lines changed: 67 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,16 @@ public void openSpawnerForm(Player player, SpawnerData spawner) {
5050
title = languageManager.getGuiTitle("gui_title_main.single_spawner", placeholders);
5151
}
5252

53-
// Directly set button text with Bedrock-compatible colors
54-
String lootButtonText = "Open Storage";
55-
String infoButtonText = "Open Stack Menu";
56-
String expButtonText = "Collect Experience";
53+
// Get button texts from language configuration
54+
String lootButtonText = languageManager.getGuiItemName("bedrock_gui.buttons.storage", placeholders);
55+
String infoButtonText = languageManager.getGuiItemName("bedrock_gui.buttons.stack_info", placeholders);
56+
String expButtonText = languageManager.getGuiItemName("bedrock_gui.buttons.experience", placeholders);
5757

5858
// Create a simple form with buttons for each action
5959
SimpleForm form = SimpleForm.builder()
6060
.title(title)
6161
.content(createInfoContent(player, spawner))
62-
// Add buttons with hardcoded text
62+
// Add buttons with configurable text from language files
6363
.button(lootButtonText, FormImage.Type.URL, "https://img.icons8.com/?size=100&id=e78DnJp8bhmX&format=png&color=000000")
6464
.button(infoButtonText, FormImage.Type.URL, "https://static.wikia.nocookie.net/minecraft_gamepedia/images/c/cf/Spawner_with_fire.png/revision/latest?cb=20190925003048")
6565
.button(expButtonText, FormImage.Type.URL, "https://static.wikia.nocookie.net/minecraft_gamepedia/images/1/10/Bottle_o%27_Enchanting.gif/revision/latest?cb=20200428012753")
@@ -97,50 +97,84 @@ public void openSpawnerForm(Player player, SpawnerData spawner) {
9797
private String createInfoContent(Player player, SpawnerData spawner) {
9898
StringBuilder content = new StringBuilder();
9999

100-
// Spawner Info Section
100+
// Get entity names with proper formatting
101101
String entityName = languageManager.getFormattedMobName(spawner.getEntityType());
102-
content.append("§l§b»»» Spawner Information «««§r\n\n");
103-
content.append("§8▪ §b Entity: §f").append(entityName).append("\n");
104-
content.append("§8▪ §b Stack Size: §f").append(spawner.getStackSize()).append("\n");
105-
content.append("§8▪ §b Range: §f").append(spawner.getSpawnerRange()).append(" §7blocks\n");
106-
content.append("§8▪ §b Delay: §f").append(spawner.getSpawnDelay() / 20).append(" §7seconds\n");
107-
content.append("§8▪ §b Mob Rate: §f").append(spawner.getMinMobs()).append(" §7- §f").append(spawner.getMaxMobs()).append("\n\n");
108-
109-
// Storage Info Section
102+
String entityNameSmallCaps = languageManager.getSmallCaps(languageManager.getFormattedMobName(spawner.getEntityType()));
103+
104+
// Prepare placeholders for consistent formatting
105+
Map<String, String> placeholders = new HashMap<>();
106+
placeholders.put("entity", entityName);
107+
placeholders.put("ᴇɴᴛɪᴛʏ", entityNameSmallCaps);
108+
placeholders.put("stack_size", String.valueOf(spawner.getStackSize()));
109+
placeholders.put("range", String.valueOf(spawner.getSpawnerRange()));
110+
placeholders.put("min_mobs", String.valueOf(spawner.getMinMobs()));
111+
placeholders.put("max_mobs", String.valueOf(spawner.getMaxMobs()));
112+
placeholders.put("delay", String.valueOf(spawner.getSpawnDelay() / 20));
113+
114+
// Storage information
110115
int currentItems = spawner.getVirtualInventory().getUsedSlots();
111116
int maxSlots = spawner.getMaxSpawnerLootSlots();
112-
content.append("§l§6»»» Storage «««§r\n\n");
113-
content.append("§8▪ §6 Slots: §f").append(currentItems).append("§7/§f").append(maxSlots).append("\n");
114-
content.append("§8▪ §6 Status: §f").append(getStorageStatus(currentItems, maxSlots)).append("\n\n");
115-
116-
// XP Info Section
117+
double percentStorageDecimal = maxSlots > 0 ? ((double) currentItems / maxSlots) * 100 : 0;
118+
String formattedPercentStorage = String.format("%.1f", percentStorageDecimal);
119+
120+
placeholders.put("current_items", String.valueOf(currentItems));
121+
placeholders.put("max_items", languageManager.formatNumber(maxSlots));
122+
placeholders.put("formatted_storage", formattedPercentStorage);
123+
124+
// Experience information
117125
long currentExp = spawner.getSpawnerExp();
118126
long maxExp = spawner.getMaxStoredExp();
119-
String formattedExp = languageManager.formatNumber(currentExp);
127+
double percentExpDecimal = maxExp > 0 ? ((double) currentExp / maxExp) * 100 : 0;
128+
String formattedPercentExp = String.format("%.1f", percentExpDecimal);
129+
String formattedCurrentExp = languageManager.formatNumber(currentExp);
120130
String formattedMaxExp = languageManager.formatNumber(maxExp);
121-
content.append("§l§a»»» Experience «««§r\n\n");
122-
content.append("§8▪ §a Current: §e").append(formattedExp).append("§7/§e").append(formattedMaxExp).append(" §7XP\n");
123-
content.append("§8▪ §a Status: §e").append(getExpStatus(currentExp, maxExp)).append("\n\n");
131+
132+
placeholders.put("current_exp", formattedCurrentExp);
133+
placeholders.put("max_exp", formattedMaxExp);
134+
placeholders.put("formatted_exp", formattedPercentExp);
135+
136+
// Build content using the same style as the main GUI
137+
138+
// Spawner Information Section - matching spawner_info_item style
139+
content.append("&#7b68ee◈ &#8a2be2ɪɴꜰᴏʀᴍᴀᴛɪᴏɴ:\n");
140+
content.append(" &#e6e6fa• ꜱᴛᴀᴄᴋ: &#c2a8fc").append(spawner.getStackSize()).append("\n");
141+
content.append(" &#e6e6fa• ʀᴀɴɢᴇ: &#c2a8fc").append(spawner.getSpawnerRange()).append("&#e6e6fa ʙʟᴏᴄᴋꜱ\n");
142+
content.append(" &#e6e6fa• ᴍᴏʙꜱ: &#c2a8fc").append(spawner.getMinMobs()).append("&#e6e6fa - &#c2a8fc").append(spawner.getMaxMobs()).append("\n");
143+
content.append(" &#e6e6fa• ᴅᴇʟᴀʏ: &#c2a8fc").append(spawner.getSpawnDelay() / 20).append("&#e6e6faꜱ\n\n");
144+
145+
// Storage Section - matching spawner_storage_item style
146+
content.append("&#d9b50c◈ &#fce96aꜱᴛᴏʀᴀɢᴇ:\n");
147+
content.append(" &#f8f8ff• ꜱʟᴏᴛꜱ: &#f9cf51").append(currentItems).append("&#d9b50c/&#f9cf51").append(languageManager.formatNumber(maxSlots)).append("\n");
148+
content.append(" &#f8f8ff• ꜱᴛᴀᴛᴜꜱ: ").append(getStorageStatus(currentItems, maxSlots)).append("\n\n");
149+
150+
// Experience Section - matching exp_info_item style
151+
content.append("&#2cc483◈ &#48e89bᴇxᴘᴇʀɪᴇɴᴄᴇ:\n");
152+
content.append(" &#f8f8ff• ᴄᴜʀʀᴇɴᴛ: &#37eb9a").append(formattedCurrentExp).append("&#2cc483/&#37eb9a").append(formattedMaxExp).append(" &#2cc483xᴘ\n");
153+
content.append(" &#f8f8ff• ꜱᴛᴀᴛᴜꜱ: ").append(getExpStatus(currentExp, maxExp)).append("\n");
124154

125155
return content.toString();
126156
}
127157

128158
private String getStorageStatus(int current, int max) {
129159
double ratio = (double) current / max;
130-
if (ratio >= 0.9) return "§cNearly Full";
131-
if (ratio >= 0.7) return "§6Filling Up";
132-
if (ratio >= 0.4) return "§eHalf Full";
133-
if (ratio > 0) return "§aPlenty of Space";
134-
return "§aEmpty";
160+
Map<String, String> placeholders = new HashMap<>();
161+
162+
if (ratio >= 0.9) return languageManager.getGuiItemName("bedrock_gui.status.storage.nearly_full", placeholders);
163+
if (ratio >= 0.7) return languageManager.getGuiItemName("bedrock_gui.status.storage.filling_up", placeholders);
164+
if (ratio >= 0.4) return languageManager.getGuiItemName("bedrock_gui.status.storage.half_full", placeholders);
165+
if (ratio > 0) return languageManager.getGuiItemName("bedrock_gui.status.storage.plenty_space", placeholders);
166+
return languageManager.getGuiItemName("bedrock_gui.status.storage.empty", placeholders);
135167
}
136168

137169
private String getExpStatus(long current, long max) {
138170
double ratio = (double) current / max;
139-
if (ratio >= 0.9) return "§cAlmost Full";
140-
if (ratio >= 0.7) return "§6Large Amount";
141-
if (ratio >= 0.4) return "§eMedium Amount";
142-
if (ratio > 0) return "§aSmall Amount";
143-
return "§aEmpty";
171+
Map<String, String> placeholders = new HashMap<>();
172+
173+
if (ratio >= 0.9) return languageManager.getGuiItemName("bedrock_gui.status.experience.almost_full", placeholders);
174+
if (ratio >= 0.7) return languageManager.getGuiItemName("bedrock_gui.status.experience.large_amount", placeholders);
175+
if (ratio >= 0.4) return languageManager.getGuiItemName("bedrock_gui.status.experience.medium_amount", placeholders);
176+
if (ratio > 0) return languageManager.getGuiItemName("bedrock_gui.status.experience.small_amount", placeholders);
177+
return languageManager.getGuiItemName("bedrock_gui.status.experience.empty", placeholders);
144178
}
145179

146180
/**

core/src/main/java/github/nighter/smartspawner/spawner/interactions/click/SpawnerClickManager.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import github.nighter.smartspawner.language.MessageService;
66
import github.nighter.smartspawner.nms.ParticleWrapper;
77
import github.nighter.smartspawner.spawner.gui.main.SpawnerMenuUI;
8+
import github.nighter.smartspawner.spawner.gui.main.SpawnerMenuFormUI;
89
import github.nighter.smartspawner.spawner.interactions.stack.SpawnerStackHandler;
910
import github.nighter.smartspawner.spawner.interactions.type.SpawnEggHandler;
1011
import github.nighter.smartspawner.spawner.properties.SpawnerData;
@@ -39,6 +40,7 @@ public class SpawnerClickManager implements Listener {
3940
private final SpawnEggHandler spawnEggHandler;
4041
private final SpawnerStackHandler spawnerStackHandler;
4142
private final SpawnerMenuUI spawnerMenuUI;
43+
private final SpawnerMenuFormUI spawnerMenuFormUI;
4244

4345
// Use ConcurrentHashMap for thread safety without explicit synchronization
4446
private final Map<UUID, Long> playerCooldowns = new ConcurrentHashMap<>();
@@ -50,6 +52,7 @@ public SpawnerClickManager(SmartSpawner plugin) {
5052
this.spawnEggHandler = plugin.getSpawnEggHandler();
5153
this.spawnerStackHandler = plugin.getSpawnerStackHandler();
5254
this.spawnerMenuUI = plugin.getSpawnerMenuUI();
55+
this.spawnerMenuFormUI = plugin.getSpawnerMenuFormUI();
5356
initCleanupTask();
5457
}
5558

@@ -213,8 +216,13 @@ private void handleInactiveSpawnerInteraction(Player player, Block block, Spawne
213216
}
214217

215218
private void openSpawnerMenu(Player player, SpawnerData spawner) {
216-
// Open the menu as normal
217-
spawnerMenuUI.openSpawnerMenu(player, spawner, false);
219+
// Check if the player is a Bedrock player and use FormUI
220+
if (isBedrockPlayer(player)) {
221+
spawnerMenuFormUI.openSpawnerForm(player, spawner);
222+
} else {
223+
// Open the regular GUI menu for Java players
224+
spawnerMenuUI.openSpawnerMenu(player, spawner, false);
225+
}
218226
}
219227

220228
private boolean isSpawnEgg(Material material) {

core/src/main/resources/language/DonutSMP/gui.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,42 @@ gui_title_main:
2121
single_spawner: '&#545454%ᴇɴᴛɪᴛʏ% ꜱᴘᴀᴡɴᴇʀ'
2222
stacked_spawner: '&#545454%amount% %ᴇɴᴛɪᴛʏ% ꜱᴘᴀᴡɴᴇʀ'
2323

24+
# ═══════════════════════════════════════════════════════════════════════════════════════════════════════════
25+
# BEDROCK/GEYSER GUI CONFIGURATION
26+
# ═══════════════════════════════════════════════════════════════════════════════════════════════════════════
27+
#
28+
# This section contains configuration for Bedrock Edition players using Geyser/Floodgate.
29+
# Form-based UI elements for cross-platform compatibility with consistent styling.
30+
# Note: Bedrock forms support limited formatting compared to Java Edition GUIs.
31+
#
32+
bedrock_gui:
33+
# Button text configuration for Bedrock forms
34+
buttons:
35+
# Storage button - opens spawner loot storage
36+
storage: '&#F97603Open Storage'
37+
38+
# Info/Stack button - opens spawner stacking menu
39+
stack_info: '&#FCE300Open Stack Menu'
40+
41+
# Experience button - collects stored experience
42+
experience: '&#FCE300Collect Experience'
43+
44+
# Status text for storage and experience displays
45+
status:
46+
storage:
47+
empty: '&#aEmpty'
48+
plenty_space: '&#aPlenty of Space'
49+
half_full: '&#eHalf Full'
50+
filling_up: '&#F97603Filling Up'
51+
nearly_full: '&#cNearly Full'
52+
53+
experience:
54+
empty: '&#aEmpty'
55+
small_amount: '&#aSmall Amount'
56+
medium_amount: '&#FCE300Medium Amount'
57+
large_amount: '&#F97603Large Amount'
58+
almost_full: '&#cAlmost Full'
59+
2460
spawner_storage_item:
2561
name: '&#F97603sᴘᴀᴡɴᴇʀ sᴛᴏʀᴀɢᴇ'
2662
lore:

core/src/main/resources/language/en_US/gui.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,42 @@ gui_title_main:
2121
single_spawner: '%ᴇɴᴛɪᴛʏ% ꜱᴘᴀᴡɴᴇʀ'
2222
stacked_spawner: '%amount% %ᴇɴᴛɪᴛʏ% ꜱᴘᴀᴡɴᴇʀ'
2323

24+
# ═══════════════════════════════════════════════════════════════════════════════════════════════════════════
25+
# BEDROCK/GEYSER GUI CONFIGURATION
26+
# ═══════════════════════════════════════════════════════════════════════════════════════════════════════════
27+
#
28+
# This section contains configuration for Bedrock Edition players using Geyser/Floodgate.
29+
# Form-based UI elements for cross-platform compatibility with consistent styling.
30+
# Note: Bedrock forms support limited formatting compared to Java Edition GUIs.
31+
#
32+
bedrock_gui:
33+
# Button text configuration for Bedrock forms
34+
buttons:
35+
# Storage button - opens spawner loot storage
36+
storage: '&#fce96aOpen Storage'
37+
38+
# Info/Stack button - opens spawner stacking menu
39+
stack_info: '&#ab7afdOpen Stack Menu'
40+
41+
# Experience button - collects stored experience
42+
experience: '&#37eb9aCollect Experience'
43+
44+
# Status text for storage and experience displays
45+
status:
46+
storage:
47+
empty: '&#aEmpty'
48+
plenty_space: '&#aPlenty of Space'
49+
half_full: '&#eHalf Full'
50+
filling_up: '&#6Filling Up'
51+
nearly_full: '&#cNearly Full'
52+
53+
experience:
54+
empty: '&#aEmpty'
55+
small_amount: '&#aSmall Amount'
56+
medium_amount: '&#eMedium Amount'
57+
large_amount: '&#6Large Amount'
58+
almost_full: '&#cAlmost Full'
59+
2460
# Spawner Storage Item Configuration
2561

2662
spawner_storage_item:

core/src/main/resources/language/vi_VN/gui.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,42 @@ gui_title_main:
2121
single_spawner: "ʟồɴɢ sᴘᴀᴡɴ %ᴇɴᴛɪᴛʏ%"
2222
stacked_spawner: '%amount% ʟồɴɢ sᴘᴀᴡɴ %ᴇɴᴛɪᴛʏ%'
2323

24+
# ═══════════════════════════════════════════════════════════════════════════════════════════════════════════
25+
# BEDROCK/GEYSER GUI CONFIGURATION
26+
# ═══════════════════════════════════════════════════════════════════════════════════════════════════════════
27+
#
28+
# This section contains configuration for Bedrock Edition players using Geyser/Floodgate.
29+
# Form-based UI elements for cross-platform compatibility with consistent styling.
30+
# Note: Bedrock forms support limited formatting compared to Java Edition GUIs.
31+
#
32+
bedrock_gui:
33+
# Button text configuration for Bedrock forms
34+
buttons:
35+
# Storage button - opens spawner loot storage
36+
storage: '&#fce96aᴍở ᴋʜᴏ ᴄʜứᴀ'
37+
38+
# Info/Stack button - opens spawner stacking menu
39+
stack_info: '&#ab7afdᴍở ᴍᴇɴᴜ xếᴘ ᴄʜồɴɢ'
40+
41+
# Experience button - collects stored experience
42+
experience: '&#37eb9aThu thập ᴋɪɴʜ ɴɢʜɪệᴍ'
43+
44+
# Status text for storage and experience displays
45+
status:
46+
storage:
47+
empty: '&#aTrống'
48+
plenty_space: '&#aCòn ɴʜɪềᴜ ᴄʜỗ'
49+
half_full: '&#eNửᴀ đầʏ'
50+
filling_up: '&#6Đang đầʏ dần'
51+
nearly_full: '&#cGầɴ đầʏ'
52+
53+
experience:
54+
empty: '&#aTrống'
55+
small_amount: '&#aSố ʟượɴɢ ɪ́ᴛ'
56+
medium_amount: '&#eSố ʟượɴɢ ᴛrung bình'
57+
large_amount: '&#6Số ʟượɴɢ ʟớɴ'
58+
almost_full: '&#cGầɴ đầʏ'
59+
2460
spawner_storage_item:
2561
name: '&#fce96aᴋʜᴏ ᴄʜứᴀ'
2662
lore:

0 commit comments

Comments
 (0)