99import org .bukkit .event .Listener ;
1010import org .bukkit .event .inventory .ClickType ;
1111import org .bukkit .event .inventory .InventoryClickEvent ;
12+ import org .bukkit .event .inventory .InventoryCloseEvent ;
1213import org .bukkit .inventory .Inventory ;
1314import org .bukkit .inventory .ItemStack ;
1415import org .bukkit .inventory .meta .ItemMeta ;
1819public class GUIManager implements Listener {
1920 private final SimplePointPlugin plugin ;
2021 private final Map <UUID , SettingSession > sessions = new HashMap <>();
22+ // ✨ 現在どのプレイヤーがどのポイントIDのGUIを開いているかを追跡
23+ private final Map <UUID , String > activeGuiId = new HashMap <>();
2124
2225 public GUIManager (SimplePointPlugin plugin ) {
2326 this .plugin = plugin ;
2427 }
2528
2629 private static class SettingSession {
2730 String pointName ; int slot ; ItemStack item ; int price = 100 ; int stock = -1 ;
28- boolean isPersonal = false ; // ✨追加
31+ boolean isPersonal = false ;
2932 }
3033
3134 public void openRewardGUI (Player player , String pointName , boolean isAdmin ) {
32- String title = pointName + (isAdmin ? ":編集" : ":受け取り" );
35+ String displayName = plugin .getPointManager ().getDisplayName (pointName );
36+ String title = displayName + (isAdmin ? "§r:編集" : "§r:受け取り" );
3337 Inventory gui = Bukkit .createInventory (null , 54 , title );
38+
39+ // ✨ 追跡用マップに保存(タイトル文字列に頼らずにIDを特定するため)
40+ activeGuiId .put (player .getUniqueId (), pointName );
41+
3442 FileConfiguration config = plugin .getRewardManager ().getRewardConfig (pointName );
3543
3644 if (config != null ) {
@@ -43,7 +51,6 @@ public void openRewardGUI(Player player, String pointName, boolean isAdmin) {
4351 boolean isPersonal = config .getBoolean (slot + ".is_personal" , false );
4452 int req = config .getInt (slot + ".requirement" , 0 );
4553
46- // 在庫切れ判定
4754 boolean isSoldOut = false ;
4855 if (price != -1 ) {
4956 if (isPersonal ) {
@@ -54,25 +61,20 @@ public void openRewardGUI(Player player, String pointName, boolean isAdmin) {
5461 }
5562 }
5663
57- // --- 編集モード時のみの特別処理 ---
58- // 編集モードならバリアに変えず、かつ在庫情報をそのまま出す
5964 if (isAdmin ) isSoldOut = false ;
6065
61- ItemMeta meta = item .getItemMeta (); // 元の名前・説明文を保持したメタを取得
62-
63- if (price != -1 ) {
66+ ItemMeta meta = item .getItemMeta ();
67+ if (price != -1 && meta != null ) {
6468 List <String > lore = meta .hasLore () ? meta .getLore () : new ArrayList <>();
6569 lore .add ("§8----------" );
6670
6771 if (isSoldOut ) {
68- // 在庫切れ時の演出
69- item .setType (Material .BARRIER ); // ✨ 見た目だけをバリアに変更
72+ item .setType (Material .BARRIER );
7073 lore .add ("§c§l在庫切れ / 購入不可" );
7174 } else {
7275 lore .add ("§e価格: §f" + price + " pt" );
7376 }
7477
75- // 在庫状況の表示
7678 if (isPersonal ) {
7779 int bought = getPersonalBoughtCount (player , pointName , slot );
7880 lore .add ("§b個人在庫: §f" + (stock == -1 ? "なし" : bought + " / " + stock ));
@@ -81,10 +83,10 @@ public void openRewardGUI(Player player, String pointName, boolean isAdmin) {
8183 }
8284
8385 if (req > 0 ) lore .add ("§6必要解放pt: §f" + req );
84- meta .setLore (lore ); // SPPの情報を追加したLoreをセット
86+ meta .setLore (lore );
8587 }
8688
87- item .setItemMeta (meta ); // バリアになったアイテムに元のメタを上書き
89+ item .setItemMeta (meta );
8890 gui .setItem (slot , item );
8991 } catch (Exception ignored ) {}
9092 }
@@ -98,23 +100,28 @@ public void onInventoryClick(InventoryClickEvent event) {
98100 Player player = (Player ) event .getWhoClicked ();
99101 String title = event .getView ().getTitle ();
100102
103+ // ✨ メモリから開いているポイントIDを取得
104+ String pId = activeGuiId .get (player .getUniqueId ());
105+
101106 if (title .contains (":受け取り" )) {
102107 event .setCancelled (true );
103- handlePurchase (player , title . split ( ":" )[ 0 ] , event .getRawSlot ());
108+ if ( pId != null ) handlePurchase (player , pId , event .getRawSlot ());
104109 }
105110 else if (title .contains (":編集" )) {
106111 if (event .getRawSlot () < 0 || event .getRawSlot () >= 54 ) return ;
107112 event .setCancelled (true );
108- String pName = title .split (":" )[0 ];
113+
114+ if (pId == null ) return ;
115+
109116 ItemStack cursor = event .getCursor ();
110117 ItemStack clicked = event .getCurrentItem ();
111118
112119 if (cursor != null && cursor .getType () != Material .AIR ) {
113- startSetting (player , pName , event .getRawSlot (), cursor .clone ());
120+ startSetting (player , pId , event .getRawSlot (), cursor .clone ());
114121 player .setItemOnCursor (null );
115122 }
116123 else if (clicked != null && clicked .getType () != Material .AIR ) {
117- startSetting (player , pName , event .getRawSlot (), clicked .clone ());
124+ startSetting (player , pId , event .getRawSlot (), clicked .clone ());
118125 }
119126 }
120127 else if (title .startsWith ("報酬設定:" )) {
@@ -123,22 +130,29 @@ else if (title.startsWith("報酬設定:")) {
123130 }
124131 }
125132
126- private void startSetting (Player player , String pName , int slot , ItemStack item ) {
133+ // ✨ インベントリを閉じたら追跡を解除
134+ @ EventHandler
135+ public void onInventoryClose (InventoryCloseEvent event ) {
136+ activeGuiId .remove (event .getPlayer ().getUniqueId ());
137+ }
138+
139+ private void startSetting (Player player , String pId , int slot , ItemStack item ) {
127140 SettingSession s = new SettingSession ();
128- s .pointName = pName ; s .slot = slot ; s .item = item ;
129- FileConfiguration config = plugin .getRewardManager ().getRewardConfig (pName );
141+ s .pointName = pId ; s .slot = slot ; s .item = item ;
142+ FileConfiguration config = plugin .getRewardManager ().getRewardConfig (pId );
130143 if (config .contains (String .valueOf (slot ))) {
131144 s .price = config .getInt (slot + ".price" );
132145 s .stock = config .getInt (slot + ".stock" , -1 );
133- s .isPersonal = config .getBoolean (slot + ".is_personal" , false ); // ✨追加
146+ s .isPersonal = config .getBoolean (slot + ".is_personal" , false );
134147 }
135148 sessions .put (player .getUniqueId (), s );
136149 openSettingGUI (player );
137150 }
138151
139152 public void openSettingGUI (Player player ) {
140153 SettingSession s = sessions .get (player .getUniqueId ());
141- Inventory inv = Bukkit .createInventory (null , 27 , "報酬設定: " + s .pointName );
154+ String displayName = plugin .getPointManager ().getDisplayName (s .pointName );
155+ Inventory inv = Bukkit .createInventory (null , 27 , "報酬設定: " + displayName );
142156 inv .setItem (4 , s .item );
143157
144158 inv .setItem (10 , createGuiItem (Material .RED_STAINED_GLASS_PANE , "§c価格 -100" , "§7現在: " + (s .price == -1 ? "装飾中" : s .price )));
@@ -151,7 +165,6 @@ public void openSettingGUI(Player player) {
151165 inv .setItem (12 , createGuiItem (Material .COMPARATOR , "§f在庫設定切替" , "§7クリックで §b無限 §7と §e数値 §7を切り替え" ));
152166 inv .setItem (18 , createGuiItem (Material .PAINTING , "§d§l装飾モード切替" , "§7現在: " + (s .price == -1 ? "§aON" : "§cOFF" )));
153167
154- // ✨在庫モード切替ボタン
155168 inv .setItem (19 , createGuiItem (Material .PLAYER_HEAD , "§6§l在庫モード切替" ,
156169 "§7現在: " + (s .isPersonal ? "§a個人制限" : "§e共有在庫" ) + "\n §8クリックで切り替え" ));
157170
@@ -181,17 +194,17 @@ else if (slot == 15) {
181194 }
182195 else if (slot == 12 ) s .stock = (s .stock == -1 ) ? 1 : -1 ;
183196 else if (slot == 18 ) s .price = (s .price == -1 ) ? 100 : -1 ;
184- else if (slot == 19 ) s .isPersonal = !s .isPersonal ; // ✨追加
197+ else if (slot == 19 ) s .isPersonal = !s .isPersonal ;
185198 else if (slot == 22 ) {
186199 plugin .getRewardManager ().deleteReward (s .pointName , s .slot );
187200 player .closeInventory ();
188201 return ;
189202 }
190203 else if (slot == 13 ) {
191- // ✨引数に s.isPersonal を追加
192204 plugin .getRewardManager ().saveReward (s .pointName , s .slot , s .item , s .price , s .stock , s .isPersonal );
193205 player .playSound (player .getLocation (), Sound .ENTITY_EXPERIENCE_ORB_PICKUP , 1.0f , 1.0f );
194206 player .closeInventory ();
207+ // activeGuiId は InventoryCloseEvent で自動削除される
195208 return ;
196209 }
197210 openSettingGUI (player );
@@ -205,16 +218,12 @@ private void handlePurchase(Player player, String pointName, int slot) {
205218 if (price == -1 ) return ;
206219
207220 int stock = config .getInt (slot + ".stock" , -1 );
208- boolean isPersonal = config .getBoolean (slot + ".is_personal" , false ); // ✨追加
221+ boolean isPersonal = config .getBoolean (slot + ".is_personal" , false );
209222 int req = config .getInt (slot + ".requirement" , 0 );
210223
211- // ✨解放条件チェック
212- int total = pointName .startsWith ("TEAMREWARD_" ) ?
213- plugin .getTeamManager ().getTeamPoints (pointName .replace ("TEAMREWARD_" , "" )) :
214- plugin .getPointManager ().getTotalPoint (pointName , player .getUniqueId ());
224+ int total = plugin .getPointManager ().getTotalPoint (pointName , player .getUniqueId ());
215225 if (total < req ) { player .sendMessage ("§c解放条件未達成 (" + total + "/" + req + ")" ); return ; }
216226
217- // ✨在庫チェックの分岐
218227 if (isPersonal ) {
219228 if (stock != -1 && getPersonalBoughtCount (player , pointName , slot ) >= stock ) {
220229 player .sendMessage ("§cこれ以上購入できません" );
@@ -229,27 +238,18 @@ private void handlePurchase(Player player, String pointName, int slot) {
229238 }
230239 }
231240
232- String pKey = pointName .startsWith ("TEAMREWARD_" ) ? pointName .replace ("TEAMREWARD_" , "" ) : pointName ;
233- int balance = plugin .getPointManager ().getPoint (pKey , player .getUniqueId ());
241+ int balance = plugin .getPointManager ().getPoint (pointName , player .getUniqueId ());
234242
235243 if (balance >= price ) {
236- // ✨減算処理の分岐
237244 if (isPersonal ) {
238245 addPersonalBoughtCount (player , pointName , slot );
239246 } else if (stock > 0 ) {
240247 plugin .getRewardManager ().updateStock (pointName , slot , stock - 1 );
241248 }
242249
243- plugin .getPointManager ().addPoint (pKey , player .getUniqueId (), -price );
250+ plugin .getPointManager ().addPoint (pointName , player .getUniqueId (), -price );
244251 player .getInventory ().addItem (config .getItemStack (slot + ".item" ).clone ());
245252
246- List <String > commands = config .getStringList (slot + ".commands" );
247- for (String cmd : commands ) {
248- String processedCmd = cmd .replace ("%player%" , player .getName ()).replace ("%point%" , pointName );
249- Bukkit .dispatchCommand (Bukkit .getConsoleSender (), processedCmd );
250- }
251-
252- plugin .getLogManager ().logPurchase (player .getName (), pointName , price , slot );
253253 player .sendMessage ("§a購入完了!" );
254254 player .playSound (player .getLocation (), Sound .ENTITY_PLAYER_LEVELUP , 1.0f , 1.2f );
255255 openRewardGUI (player , pointName , false );
@@ -259,22 +259,26 @@ private void handlePurchase(Player player, String pointName, int slot) {
259259 }
260260 }
261261
262- // ✨個人データの管理用ヘルパー
263262 private int getPersonalBoughtCount (Player p , String pointName , int slot ) {
264263 FileConfiguration cfg = plugin .getPointManager ().getPointConfig (pointName );
265- return cfg .getInt (p .getUniqueId () + ".purchased." + slot , 0 );
264+ return cfg != null ? cfg .getInt (p .getUniqueId () + ".purchased." + slot , 0 ) : 0 ;
266265 }
267266
268267 private void addPersonalBoughtCount (Player p , String pointName , int slot ) {
269268 FileConfiguration cfg = plugin .getPointManager ().getPointConfig (pointName );
269+ if (cfg == null ) return ;
270270 int current = cfg .getInt (p .getUniqueId () + ".purchased." + slot , 0 );
271271 cfg .set (p .getUniqueId () + ".purchased." + slot , current + 1 );
272272 plugin .getPointManager ().savePointConfig (pointName );
273273 }
274274
275275 private ItemStack createGuiItem (Material m , String name , String lore ) {
276276 ItemStack item = new ItemStack (m ); ItemMeta meta = item .getItemMeta ();
277- meta .setDisplayName (name ); meta .setLore (Collections .singletonList (lore ));
278- item .setItemMeta (meta ); return item ;
277+ if (meta != null ) {
278+ meta .setDisplayName (name );
279+ meta .setLore (Collections .singletonList (lore ));
280+ item .setItemMeta (meta );
281+ }
282+ return item ;
279283 }
280284}
0 commit comments