Skip to content

Commit 1a246e4

Browse files
committed
feat: 個人在庫
1 parent a594ca8 commit 1a246e4

File tree

5 files changed

+124
-55
lines changed

5 files changed

+124
-55
lines changed

Readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
### 報酬設定GUI
5353
`/spp rewardgui` で開いた画面にアイテムを置くだけで設定開始!
54-
* **在庫設定**: 有限在庫だけでなく、コンパレーターのボタンで「無限在庫」に切り替え可能。
54+
* **在庫設定**: 有限在庫だけでなく、コンパレーターのボタンで「無限在庫」に切り替え可能。サーバー全体・個人のみの在庫の切り替えも可能です。
5555
* **装飾モード**: 絵画のボタンで「装飾モード」に切り替えると、アイテム名と説明文だけが表示され、価格や在庫などの要素が表示されなくなります(購入も不可)。
5656
* **コマンド実行**: `rewards/ポイント名.yml` を直接編集することで、購入時にコンソールからコマンド(`%player%` `%point%`)を実行できます。
5757
```

src/main/java/net/azisaba/simplepoint/GUIManager.java

Lines changed: 91 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.bukkit.Bukkit;
44
import org.bukkit.Material;
5+
import org.bukkit.Sound;
56
import org.bukkit.configuration.file.FileConfiguration;
67
import org.bukkit.entity.Player;
78
import org.bukkit.event.EventHandler;
@@ -24,32 +25,66 @@ public GUIManager(SimplePointPlugin plugin) {
2425

2526
private static class SettingSession {
2627
String pointName; int slot; ItemStack item; int price = 100; int stock = -1;
28+
boolean isPersonal = false; // ✨追加
2729
}
2830

2931
public void openRewardGUI(Player player, String pointName, boolean isAdmin) {
3032
String title = pointName + (isAdmin ? ":編集" : ":受け取り");
3133
Inventory gui = Bukkit.createInventory(null, 54, title);
3234
FileConfiguration config = plugin.getRewardManager().getRewardConfig(pointName);
35+
3336
if (config != null) {
3437
for (String key : config.getKeys(false)) {
3538
try {
3639
int slot = Integer.parseInt(key);
3740
ItemStack item = config.getItemStack(slot + ".item").clone();
3841
int price = config.getInt(slot + ".price");
3942
int stock = config.getInt(slot + ".stock", -1);
43+
boolean isPersonal = config.getBoolean(slot + ".is_personal", false);
4044
int req = config.getInt(slot + ".requirement", 0);
4145

42-
ItemMeta meta = item.getItemMeta();
43-
// ✨ 装飾モード(price: -1)でない場合のみ、SPPの要素を追加表示
46+
// 在庫切れ判定
47+
boolean isSoldOut = false;
48+
if (price != -1) {
49+
if (isPersonal) {
50+
int bought = getPersonalBoughtCount(player, pointName, slot);
51+
if (stock != -1 && bought >= stock) isSoldOut = true;
52+
} else {
53+
if (stock == 0) isSoldOut = true;
54+
}
55+
}
56+
57+
// --- 編集モード時のみの特別処理 ---
58+
// 編集モードならバリアに変えず、かつ在庫情報をそのまま出す
59+
if (isAdmin) isSoldOut = false;
60+
61+
ItemMeta meta = item.getItemMeta(); // 元の名前・説明文を保持したメタを取得
62+
4463
if (price != -1) {
4564
List<String> lore = meta.hasLore() ? meta.getLore() : new ArrayList<>();
4665
lore.add("§8----------");
47-
lore.add("§e価格: §f" + price + " pt");
48-
lore.add("§b在庫: §f" + (stock == -1 ? "無限" : stock));
66+
67+
if (isSoldOut) {
68+
// 在庫切れ時の演出
69+
item.setType(Material.BARRIER); // ✨ 見た目だけをバリアに変更
70+
lore.add("§c§l在庫切れ / 購入不可");
71+
} else {
72+
lore.add("§e価格: §f" + price + " pt");
73+
}
74+
75+
// 在庫状況の表示
76+
if (isPersonal) {
77+
int bought = getPersonalBoughtCount(player, pointName, slot);
78+
lore.add("§b個人在庫: §f" + (stock == -1 ? "なし" : bought + " / " + stock));
79+
} else {
80+
lore.add("§b共有在庫: §f" + (stock == -1 ? "無限" : stock));
81+
}
82+
4983
if (req > 0) lore.add("§6必要解放pt: §f" + req);
50-
meta.setLore(lore);
84+
meta.setLore(lore); // SPPの情報を追加したLoreをセット
5185
}
52-
item.setItemMeta(meta);
86+
87+
item.setItemMeta(meta); // バリアになったアイテムに元のメタを上書き
5388
gui.setItem(slot, item);
5489
} catch (Exception ignored) {}
5590
}
@@ -70,7 +105,6 @@ public void onInventoryClick(InventoryClickEvent event) {
70105
else if (title.contains(":編集")) {
71106
if (event.getRawSlot() < 0 || event.getRawSlot() >= 54) return;
72107
event.setCancelled(true);
73-
74108
String pName = title.split(":")[0];
75109
ItemStack cursor = event.getCursor();
76110
ItemStack clicked = event.getCurrentItem();
@@ -96,6 +130,7 @@ private void startSetting(Player player, String pName, int slot, ItemStack item)
96130
if (config.contains(String.valueOf(slot))) {
97131
s.price = config.getInt(slot + ".price");
98132
s.stock = config.getInt(slot + ".stock", -1);
133+
s.isPersonal = config.getBoolean(slot + ".is_personal", false); // ✨追加
99134
}
100135
sessions.put(player.getUniqueId(), s);
101136
openSettingGUI(player);
@@ -106,20 +141,19 @@ public void openSettingGUI(Player player) {
106141
Inventory inv = Bukkit.createInventory(null, 27, "報酬設定: " + s.pointName);
107142
inv.setItem(4, s.item);
108143

109-
// ボタン配置
110144
inv.setItem(10, createGuiItem(Material.RED_STAINED_GLASS_PANE, "§c価格 -100", "§7現在: " + (s.price == -1 ? "装飾中" : s.price)));
111145
inv.setItem(16, createGuiItem(Material.LIME_STAINED_GLASS_PANE, "§a価格 +100", "§7現在: " + (s.price == -1 ? "装飾中" : s.price)));
112146

113147
String stockDisplay = (s.stock == -1) ? "§b無限" : "§f" + s.stock;
114148
inv.setItem(11, createGuiItem(Material.PINK_STAINED_GLASS_PANE, "§c在庫 -1", "§7現在: " + stockDisplay));
115149
inv.setItem(15, createGuiItem(Material.LIGHT_BLUE_STAINED_GLASS_PANE, "§b在庫 +1", "§7現在: " + stockDisplay));
116150

117-
// 在庫トグルボタン (無限/有限切り替え)
118151
inv.setItem(12, createGuiItem(Material.COMPARATOR, "§f在庫設定切替", "§7クリックで §b無限 §7と §e数値 §7を切り替え"));
152+
inv.setItem(18, createGuiItem(Material.PAINTING, "§d§l装飾モード切替", "§7現在: " + (s.price == -1 ? "§aON" : "§cOFF")));
119153

120-
// ✨ 装飾モードトグルボタン
121-
inv.setItem(18, createGuiItem(Material.PAINTING, d§l装飾モード切替",
122-
"§7現在: " + (s.price == -1 ? aON (表示のみ)" : cOFF (販売用)") + "\n§8ONにすると価格・在庫が表示されません"));
154+
// ✨在庫モード切替ボタン
155+
inv.setItem(19, createGuiItem(Material.PLAYER_HEAD, 6§l在庫モード切替",
156+
"§7現在: " + (s.isPersonal ? a個人制限" : e共有在庫") + "\n§8クリックで切り替え"));
123157

124158
inv.setItem(13, createGuiItem(Material.GOLD_BLOCK, "§e§l保存", "§7スロット: " + s.slot));
125159
inv.setItem(22, createGuiItem(Material.BARRIER, "§4§l削除", ""));
@@ -145,20 +179,18 @@ else if (slot == 15) {
145179
if (s.stock == -1) s.stock = 1;
146180
else s.stock += (click.isRightClick() ? 10 : 1);
147181
}
148-
else if (slot == 12) { // 在庫トグル
149-
s.stock = (s.stock == -1) ? 1 : -1;
150-
}
151-
else if (slot == 18) { // ✨ 装飾モードトグル
152-
s.price = (s.price == -1) ? 100 : -1;
153-
}
182+
else if (slot == 12) s.stock = (s.stock == -1) ? 1 : -1;
183+
else if (slot == 18) s.price = (s.price == -1) ? 100 : -1;
184+
else if (slot == 19) s.isPersonal = !s.isPersonal; // ✨追加
154185
else if (slot == 22) {
155186
plugin.getRewardManager().deleteReward(s.pointName, s.slot);
156187
player.closeInventory();
157188
return;
158189
}
159190
else if (slot == 13) {
160-
plugin.getRewardManager().saveReward(s.pointName, s.slot, s.item, s.price, s.stock);
161-
player.playSound(player.getLocation(), org.bukkit.Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f, 1.0f);
191+
// ✨引数に s.isPersonal を追加
192+
plugin.getRewardManager().saveReward(s.pointName, s.slot, s.item, s.price, s.stock, s.isPersonal);
193+
player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1.0f, 1.0f);
162194
player.closeInventory();
163195
return;
164196
}
@@ -170,25 +202,44 @@ private void handlePurchase(Player player, String pointName, int slot) {
170202
if (config == null || !config.contains(String.valueOf(slot))) return;
171203

172204
int price = config.getInt(slot + ".price");
173-
174-
// ✨ 装飾用アイテムなら購入処理を中断
175205
if (price == -1) return;
176206

177207
int stock = config.getInt(slot + ".stock", -1);
208+
boolean isPersonal = config.getBoolean(slot + ".is_personal", false); // ✨追加
178209
int req = config.getInt(slot + ".requirement", 0);
179210

211+
// ✨解放条件チェック
180212
int total = pointName.startsWith("TEAMREWARD_") ?
181213
plugin.getTeamManager().getTeamPoints(pointName.replace("TEAMREWARD_", "")) :
182214
plugin.getPointManager().getTotalPoint(pointName, player.getUniqueId());
183-
184215
if (total < req) { player.sendMessage("§c解放条件未達成 (" + total + "/" + req + ")"); return; }
185-
if (stock == 0) { player.sendMessage("§c在庫切れ"); return; }
216+
217+
// ✨在庫チェックの分岐
218+
if (isPersonal) {
219+
if (stock != -1 && getPersonalBoughtCount(player, pointName, slot) >= stock) {
220+
player.sendMessage("§cこれ以上購入できません");
221+
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1.0f, 1.0f);
222+
return;
223+
}
224+
} else {
225+
if (stock == 0) {
226+
player.sendMessage("§c在庫切れ");
227+
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1.0f, 1.0f);
228+
return;
229+
}
230+
}
186231

187232
String pKey = pointName.startsWith("TEAMREWARD_") ? pointName.replace("TEAMREWARD_", "") : pointName;
188233
int balance = plugin.getPointManager().getPoint(pKey, player.getUniqueId());
189234

190235
if (balance >= price) {
191-
if (stock > 0) plugin.getRewardManager().updateStock(pointName, slot, stock - 1);
236+
// ✨減算処理の分岐
237+
if (isPersonal) {
238+
addPersonalBoughtCount(player, pointName, slot);
239+
} else if (stock > 0) {
240+
plugin.getRewardManager().updateStock(pointName, slot, stock - 1);
241+
}
242+
192243
plugin.getPointManager().addPoint(pKey, player.getUniqueId(), -price);
193244
player.getInventory().addItem(config.getItemStack(slot + ".item").clone());
194245

@@ -200,15 +251,27 @@ private void handlePurchase(Player player, String pointName, int slot) {
200251

201252
plugin.getLogManager().logPurchase(player.getName(), pointName, price, slot);
202253
player.sendMessage("§a購入完了!");
203-
player.playSound(player.getLocation(), org.bukkit.Sound.ENTITY_PLAYER_LEVELUP, 1.0f, 1.2f);
254+
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1.0f, 1.2f);
204255
openRewardGUI(player, pointName, false);
205256
} else {
206257
player.sendMessage("§cポイント不足");
207-
208-
player.playSound(player.getLocation(), org.bukkit.Sound.ENTITY_VILLAGER_NO, 1.0f, 1.0f);
258+
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1.0f, 1.0f);
209259
}
210260
}
211261

262+
// ✨個人データの管理用ヘルパー
263+
private int getPersonalBoughtCount(Player p, String pointName, int slot) {
264+
FileConfiguration cfg = plugin.getPointManager().getPointConfig(pointName);
265+
return cfg.getInt(p.getUniqueId() + ".purchased." + slot, 0);
266+
}
267+
268+
private void addPersonalBoughtCount(Player p, String pointName, int slot) {
269+
FileConfiguration cfg = plugin.getPointManager().getPointConfig(pointName);
270+
int current = cfg.getInt(p.getUniqueId() + ".purchased." + slot, 0);
271+
cfg.set(p.getUniqueId() + ".purchased." + slot, current + 1);
272+
plugin.getPointManager().savePointConfig(pointName);
273+
}
274+
212275
private ItemStack createGuiItem(Material m, String name, String lore) {
213276
ItemStack item = new ItemStack(m); ItemMeta meta = item.getItemMeta();
214277
meta.setDisplayName(name); meta.setLore(Collections.singletonList(lore));

src/main/java/net/azisaba/simplepoint/PointManager.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,13 @@ public List<String> getPointNames() {
8888
}
8989
return names;
9090
}
91+
92+
public void savePointConfig(String pointName) {
93+
FileConfiguration config = getPointConfig(pointName);
94+
try {
95+
config.save(new File(pointFolder, pointName + ".yml"));
96+
} catch (IOException e) {
97+
e.printStackTrace();
98+
}
99+
}
91100
}

src/main/java/net/azisaba/simplepoint/RewardManager.java

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,12 @@ public class RewardManager {
1616

1717
public RewardManager(SimplePointPlugin plugin) {
1818
this.plugin = plugin;
19-
// rewards フォルダを作成
2019
this.rewardFolder = new File(plugin.getDataFolder(), "rewards");
2120
if (!rewardFolder.exists()) {
2221
rewardFolder.mkdirs();
2322
}
2423
}
2524

26-
/**
27-
* ポイント名に対応する報酬設定ファイルを取得またはロードします
28-
*/
2925
public FileConfiguration getRewardConfig(String pointName) {
3026
if (configs.containsKey(pointName)) {
3127
return configs.get(pointName);
@@ -46,40 +42,32 @@ public FileConfiguration getRewardConfig(String pointName) {
4642
}
4743

4844
/**
49-
* 報酬アイテムを保存します
45+
* 報酬アイテムを保存します (isPersonal 引数を追加)
5046
*/
51-
public void saveReward(String pointName, int slot, ItemStack item, int price, int stock) {
47+
public void saveReward(String pointName, int slot, ItemStack item, int price, int stock, boolean isPersonal) {
5248
FileConfiguration config = getRewardConfig(pointName);
5349
String path = String.valueOf(slot);
5450

5551
config.set(path + ".item", item);
5652
config.set(path + ".price", price);
5753
config.set(path + ".stock", stock);
54+
config.set(path + ".is_personal", isPersonal); // ✨ ここで保存
5855

5956
saveFile(pointName, config);
6057
}
6158

62-
/**
63-
* 在庫数のみを更新します
64-
*/
6559
public void updateStock(String pointName, int slot, int newStock) {
6660
FileConfiguration config = getRewardConfig(pointName);
6761
config.set(slot + ".stock", newStock);
6862
saveFile(pointName, config);
6963
}
7064

71-
/**
72-
* 指定スロットの報酬を削除します
73-
*/
7465
public void deleteReward(String pointName, int slot) {
7566
FileConfiguration config = getRewardConfig(pointName);
7667
config.set(String.valueOf(slot), null);
7768
saveFile(pointName, config);
7869
}
7970

80-
/**
81-
* ファイルに物理保存します
82-
*/
8371
private void saveFile(String pointName, FileConfiguration config) {
8472
try {
8573
config.save(new File(rewardFolder, pointName + ".yml"));
@@ -89,9 +77,6 @@ private void saveFile(String pointName, FileConfiguration config) {
8977
}
9078
}
9179

92-
/**
93-
* メモリ上のキャッシュをクリア(リロード用)
94-
*/
9580
public void reload() {
9681
configs.clear();
9782
}

src/main/java/net/azisaba/simplepoint/SPPCommand.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,30 @@ else if (sub.equals("set")) {
9292
break;
9393

9494
case "setreq":
95-
if (args.length < 4) return false;
95+
// ... 前後の引数チェックなどは既存通り ...
9696
String pName = args[1];
9797
int slot = Integer.parseInt(args[2]);
9898
int req = Integer.parseInt(args[3]);
99+
99100
FileConfiguration config = plugin.getRewardManager().getRewardConfig(pName);
100-
config.set(slot + ".requirement", req);
101-
// 既存のデータを維持して保存
102-
plugin.getRewardManager().saveReward(pName, slot,
103-
config.getItemStack(slot + ".item"),
104-
config.getInt(slot + ".price", 100),
105-
config.getInt(slot + ".stock", -1));
106-
sender.sendMessage("§a" + pName + " " + slot + "番に解放条件 " + req + " pt を設定しました。");
101+
if (config.contains(String.valueOf(slot))) {
102+
// 解放条件(requirement)だけをセット
103+
config.set(slot + ".requirement", req);
104+
105+
// ✨ saveReward の引数に config から読み取った is_personal を追加して呼び出す
106+
plugin.getRewardManager().saveReward(
107+
pName,
108+
slot,
109+
config.getItemStack(slot + ".item"),
110+
config.getInt(slot + ".price", 100),
111+
config.getInt(slot + ".stock", -1),
112+
config.getBoolean(slot + ".is_personal", false) // ← ここを追加!
113+
);
114+
115+
sender.sendMessage("§a" + pName + " " + slot + "番に解放条件 " + req + " pt を設定しました。");
116+
} else {
117+
sender.sendMessage("§c指定されたスロットに報酬が存在しません。");
118+
}
107119
break;
108120

109121
case "ranking":

0 commit comments

Comments
 (0)