Skip to content

Commit d628762

Browse files
committed
チーム機能を部分実装
1 parent 7e5fc21 commit d628762

File tree

22 files changed

+907
-63
lines changed

22 files changed

+907
-63
lines changed

pom.xml

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>dev.felnull</groupId>
88
<artifactId>Pointed</artifactId>
9-
<version>2.0.0</version>
9+
<version>2.1.1</version>
1010
<packaging>jar</packaging>
1111

1212
<name>Pointed</name>
@@ -44,7 +44,7 @@
4444
</transformers>
4545

4646
<relocations>
47-
<!-- HikariCP はパッケージをピンポイントで -->
47+
<!-- HikariCP -->
4848
<relocation>
4949
<pattern>com.zaxxer.hikari</pattern>
5050
<shadedPattern>dev.felnull.pointed.shaded.hikari</shadedPattern>
@@ -55,6 +55,12 @@
5555
<pattern>org.mariadb.jdbc</pattern>
5656
<shadedPattern>dev.felnull.pointed.shaded.mariadb.jdbc</shadedPattern>
5757
</relocation>
58+
59+
<relocation>
60+
<pattern>net.wesjd.anvilgui</pattern>
61+
<shadedPattern>dev.felnull.pointed.anvilgui</shadedPattern> <!-- Replace [YOUR_PLUGIN_PACKAGE] with your namespace -->
62+
</relocation>
63+
5864
</relocations>
5965

6066
<!-- 署名ファイル等は除外(警告回避) -->
@@ -95,6 +101,10 @@
95101
<id>net.azisaba</id>
96102
<url>https://repo.azisaba.net/repository/maven-public/</url>
97103
</repository>
104+
<repository>
105+
<id>codemc-snapshots</id>
106+
<url>https://repo.codemc.io/repository/maven-snapshots/</url>
107+
</repository>
98108
</repositories>
99109

100110
<dependencies>
@@ -108,6 +118,7 @@
108118
<groupId>dev.felnull</groupId>
109119
<artifactId>BetterGUI</artifactId>
110120
<version>1.0.7</version>
121+
<scope>provided</scope>
111122
</dependency>
112123
<dependency>
113124
<groupId>org.projectlombok</groupId>
@@ -125,6 +136,11 @@
125136
<artifactId>mariadb-java-client</artifactId>
126137
<version>3.5.6</version>
127138
</dependency>
139+
<dependency>
140+
<groupId>net.wesjd</groupId>
141+
<artifactId>anvilgui</artifactId>
142+
<version>1.10.8-SNAPSHOT</version>
143+
</dependency>
128144
</dependencies>
129145

130146
<distributionManagement>

src/main/java/dev/felnull/pointed/Pointed.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import dev.felnull.pointed.core.listener.ChatListener;
99
import dev.felnull.pointed.core.util.ChatReader;
1010
import dev.felnull.pointed.teams.database.TeamTableInitializer;
11+
import dev.felnull.pointed.teams.manager.TeamManager;
12+
import dev.felnull.pointed.teams.manager.TeamManagerImpl;
1113
import lombok.Getter;
1214
import org.bukkit.Bukkit;
1315
import org.bukkit.configuration.file.FileConfiguration;
@@ -27,6 +29,8 @@ public final class Pointed extends JavaPlugin {
2729
public static List<BukkitTask> taskList = new ArrayList<>();
2830
ZoneId zoneId = ZoneId.of(getConfig().getString("timezone", "Asia/Tokyo"));
2931
public static PointServiceImpl pointService;
32+
@Getter
33+
public TeamManager teamManager;
3034

3135
@Override
3236
public void onEnable() {
@@ -37,6 +41,7 @@ public void onEnable() {
3741
Db.init(conf.getString("database.host"), conf.getInt("database.port"), conf.getString("database.database"), conf.getString("database.user"), conf.getString("database.pass"));
3842
this.chatReader = new ChatReader();
3943
pointService = new PointServiceImpl(Db.get(), zoneId);
44+
teamManager = new TeamManagerImpl();
4045
Bukkit.getLogger().info("Pointedが動作を開始しました");
4146
setupCommand();
4247
setupListener();
@@ -55,8 +60,8 @@ public void onDisable() {
5560
}
5661

5762
public void setupCommand(){
58-
getCommand("pt").setExecutor(new PtCommand(pointService, this, zoneId) {
59-
});
63+
getCommand("pt").setExecutor(new PtCommand(pointService, this, zoneId));
64+
getCommand("ptteam").setExecutor(new PtTeam(this));
6065
}
6166
public void setupListener(){
6267
Bukkit.getPluginManager().registerEvents(new ChatListener(this), this);
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package dev.felnull.pointed.core.commands;
2+
3+
import dev.felnull.bettergui.core.InventoryGUI;
4+
import dev.felnull.pointed.core.database.api.PointService;
5+
import dev.felnull.pointed.core.database.data.RankRow;
6+
import dev.felnull.pointed.core.util.Util;
7+
import dev.felnull.pointed.teams.gui.page.TeamConfigGUI;
8+
import org.bukkit.Bukkit;
9+
import org.bukkit.OfflinePlayer;
10+
import org.bukkit.command.Command;
11+
import org.bukkit.command.CommandExecutor;
12+
import org.bukkit.command.CommandSender;
13+
import org.bukkit.command.TabCompleter;
14+
import org.bukkit.entity.Player;
15+
import org.bukkit.plugin.Plugin;
16+
17+
import java.time.LocalDate;
18+
import java.time.ZoneId;
19+
import java.util.List;
20+
import java.util.UUID;
21+
22+
public class PtTeam implements CommandExecutor, TabCompleter {
23+
private final Plugin plugin;
24+
25+
public PtTeam(Plugin plugin) {
26+
this.plugin = plugin;
27+
}
28+
29+
// type=PLAYER のときだけ <名前 or UUID> を UUID文字列に正規化して返す
30+
// それ以外の type は key をそのまま返す
31+
private static String resolveSubjectKey(String type, String keyOrName) {
32+
if (!"PLAYER".equalsIgnoreCase(type)) {
33+
return keyOrName; // 任意文字列キーをそのまま使用
34+
}
35+
// PLAYER の場合: UUIDっぽければそのまま、そうでなければ名前→UUID
36+
try {
37+
UUID uuid = UUID.fromString(keyOrName);
38+
return uuid.toString();
39+
} catch (IllegalArgumentException ignore) {
40+
OfflinePlayer op = Bukkit.getOfflinePlayer(keyOrName);
41+
UUID uuid = op.getUniqueId();
42+
return uuid.toString();
43+
}
44+
}
45+
46+
@Override
47+
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
48+
if (args.length == 0) {
49+
sender.sendMessage(Util.f("&e/ptteam <set> <scope> <teamID>"));
50+
return true;
51+
}
52+
53+
if (!sender.hasPermission("pointed.admin")) {
54+
sender.sendMessage(Util.f("&c権限がありません。"));
55+
return true;
56+
}
57+
58+
String sub = args[0].toLowerCase();
59+
switch (sub) {
60+
case "set" -> {
61+
if(args.length < 2){
62+
sender.sendMessage(Util.f("&e/ptteam <set> <teamID>"));
63+
return true;
64+
}
65+
if(!(sender instanceof Player)){
66+
sender.sendMessage(Util.f("Playerのみが使用可能なコマンドです"));
67+
return true;
68+
}
69+
InventoryGUI gui = new InventoryGUI((Player) sender);
70+
gui.openPage(new TeamConfigGUI(gui, args[1]));
71+
}
72+
default -> sender.sendMessage(Util.f("/ptteam <set> <teamID>"));
73+
}
74+
75+
return true;
76+
}
77+
78+
@Override
79+
public List<String> onTabComplete(CommandSender sender, Command cmd, String label, String[] args) {
80+
if (args.length == 1) {
81+
return List.of("set");
82+
}
83+
// サブコマンド毎の type 補完
84+
if (args.length == 2 && List.of("getnow","gettotal","get","add","sub","set").contains(args[0].toLowerCase())) {
85+
return List.of("PLAYER","TEAM","SYSTEM");
86+
}
87+
if (args.length == 2 && args[0].equalsIgnoreCase("rank")) {
88+
return List.of("daily", "weekly", "global");
89+
}
90+
return List.of();
91+
}
92+
93+
// 共通メソッド
94+
private String formatRankLine(int rankNum, RankRow r) {
95+
String color = switch (rankNum) {
96+
case 1 -> "&6"; // 金
97+
case 2 -> "&7"; // 銀
98+
case 3 -> "&c"; // 赤
99+
default -> "&e"; // 黄
100+
};
101+
return Util.f(color + "#{0} &b{1} &f+{2}", rankNum, r.name, r.gained);
102+
}
103+
}

src/main/java/dev/felnull/pointed/core/database/TableInitializer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ public static void addColumnIfNotExists(Connection conn, String baseTable, Strin
195195
}
196196
}
197197

198-
private static void ensurePrimaryKey(Connection conn, String baseTable, String[] columns) {
198+
public static void ensurePrimaryKey(Connection conn, String baseTable, String[] columns) {
199199
String phys = Names.phys(baseTable);
200200
try {
201201
Set<String> existing = new LinkedHashSet<String>();

src/main/java/dev/felnull/pointed/core/database/api/PointServiceImpl.java

Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -41,44 +41,66 @@ private long getAccountId(Connection con, String subjectType, String subjectKey,
4141
private static Date toSqlDate(LocalDate d) { return Date.valueOf(d); }
4242
private Date todayLocal() { return toSqlDate(LocalDate.now(zoneId)); }
4343

44+
// 1) subjects を upsert して subjectId を返す(nameは上書き)
45+
public long ensureSubject(Connection con, String subjectType, String subjectKey, String name) throws SQLException {
46+
try (PreparedStatement ps = con.prepareStatement(
47+
"INSERT INTO " + Names.t("subjects") + " (type, subject_key, name) VALUES (?, ?, ?) " +
48+
"ON DUPLICATE KEY UPDATE name=VALUES(name)")) {
49+
ps.setString(1, subjectType);
50+
ps.setString(2, subjectKey);
51+
ps.setString(3, name);
52+
ps.executeUpdate();
53+
}
54+
try (PreparedStatement ps = con.prepareStatement(
55+
"SELECT id FROM " + Names.t("subjects") + " WHERE type=? AND subject_key=?")) {
56+
ps.setString(1, subjectType);
57+
ps.setString(2, subjectKey);
58+
try (ResultSet rs = ps.executeQuery()) {
59+
if (!rs.next()) throw new IllegalStateException("Subject not found after upsert");
60+
return rs.getLong(1);
61+
}
62+
}
63+
}
64+
65+
// 2) accounts を upsert して accountId を返す(scopeユニーク)
66+
public long ensureAccountForScope(Connection con, long subjectId, String scope) throws SQLException {
67+
try (PreparedStatement ps = con.prepareStatement(
68+
"INSERT INTO " + Names.t("accounts") + " (subject_id, scope) VALUES (?, ?) " +
69+
"ON DUPLICATE KEY UPDATE scope=scope")) {
70+
ps.setLong(1, subjectId);
71+
ps.setString(2, scope);
72+
ps.executeUpdate();
73+
}
74+
try (PreparedStatement ps = con.prepareStatement(
75+
"SELECT id FROM " + Names.t("accounts") + " WHERE subject_id=? AND scope=?")) {
76+
ps.setLong(1, subjectId);
77+
ps.setString(2, scope);
78+
try (ResultSet rs = ps.executeQuery()) {
79+
if (!rs.next()) throw new IllegalStateException("Account not found after upsert");
80+
return rs.getLong(1);
81+
}
82+
}
83+
}
84+
85+
// 3) account_balances を確保(INSERT IGNORE)
86+
public void ensureBalances(Connection con, long accountId) throws SQLException {
87+
try (PreparedStatement ps = con.prepareStatement(
88+
"INSERT IGNORE INTO " + Names.t("account_balances") + " (account_id, now_point, total_point) " +
89+
"VALUES (?, 0, 0)")) {
90+
ps.setLong(1, accountId);
91+
ps.executeUpdate();
92+
}
93+
}
94+
95+
// 4) 互換レイヤ(既存の ensureAccount を “まとめ役” に)
4496
@Override
4597
public void ensureAccount(String subjectType, String subjectKey, String scope, String name) {
4698
try (Connection con = ds.getConnection()) {
4799
con.setAutoCommit(false);
48100
try {
49-
// subjects
50-
PreparedStatement ps1 = con.prepareStatement(
51-
"INSERT INTO " + Names.t("subjects") + " (type, subject_key, name) VALUES(?, ?, ?) " +
52-
"ON DUPLICATE KEY UPDATE name=VALUES(name)");
53-
ps1.setString(1, subjectType);
54-
ps1.setString(2, subjectKey);
55-
ps1.setString(3, name);
56-
ps1.executeUpdate();
57-
ps1.close();
58-
59-
// accounts
60-
PreparedStatement ps2 = con.prepareStatement(
61-
"INSERT INTO " + Names.t("accounts") + " (subject_id, scope) " +
62-
"SELECT id, ? FROM " + Names.t("subjects") + " WHERE type=? AND subject_key=? " +
63-
"ON DUPLICATE KEY UPDATE scope=scope");
64-
ps2.setString(1, scope);
65-
ps2.setString(2, subjectType);
66-
ps2.setString(3, subjectKey);
67-
ps2.executeUpdate();
68-
ps2.close();
69-
70-
// account_balances
71-
PreparedStatement ps3 = con.prepareStatement(
72-
"INSERT IGNORE INTO " + Names.t("account_balances") + " (account_id, now_point, total_point) " +
73-
"SELECT a.id, 0, 0 FROM " + Names.t("accounts") + " a " +
74-
"JOIN " + Names.t("subjects") + " s ON s.id=a.subject_id " +
75-
"WHERE s.type=? AND s.subject_key=? AND a.scope=?");
76-
ps3.setString(1, subjectType);
77-
ps3.setString(2, subjectKey);
78-
ps3.setString(3, scope);
79-
ps3.executeUpdate();
80-
ps3.close();
81-
101+
long subjectId = ensureSubject(con, subjectType, subjectKey, name);
102+
long accountId = ensureAccountForScope(con, subjectId, scope);
103+
ensureBalances(con, accountId);
82104
con.commit();
83105
} catch (SQLException e) {
84106
con.rollback();
@@ -90,7 +112,6 @@ public void ensureAccount(String subjectType, String subjectKey, String scope, S
90112
throw new RuntimeException(e);
91113
}
92114
}
93-
94115
@Override
95116
public long getNowPoint(String subjectType, String subjectKey, String scope) {
96117
try (Connection con = ds.getConnection();

src/main/java/dev/felnull/pointed/core/util/ChatReader.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,13 @@ public void onChat(Player p, Component msg) {
3333

3434
switch (type) {
3535
//ChatContentTypeがDisplay_Nameの場合の処理
36-
36+
/**
37+
* ========================================================
38+
*
39+
* Conversationを使うように変更するべし
40+
*
41+
* ========================================================
42+
*/
3743
}
3844

3945
unregisterNextChat(p);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package dev.felnull.pointed.core.util;
2+
3+
import net.kyori.adventure.text.format.NamedTextColor;
4+
5+
import java.util.HashMap;
6+
import java.util.Map;
7+
8+
public class ColorUtil {
9+
private static final Map<Character, NamedTextColor> LEGACY_TO_NAMED = new HashMap<>();
10+
private static final Map<NamedTextColor, String> NAMED_TO_LEGACY = new HashMap<>();
11+
static {
12+
LEGACY_TO_NAMED.put('0', NamedTextColor.BLACK);
13+
LEGACY_TO_NAMED.put('1', NamedTextColor.DARK_BLUE);
14+
LEGACY_TO_NAMED.put('2', NamedTextColor.DARK_GREEN);
15+
LEGACY_TO_NAMED.put('3', NamedTextColor.DARK_AQUA);
16+
LEGACY_TO_NAMED.put('4', NamedTextColor.DARK_RED);
17+
LEGACY_TO_NAMED.put('5', NamedTextColor.DARK_PURPLE);
18+
LEGACY_TO_NAMED.put('6', NamedTextColor.GOLD);
19+
LEGACY_TO_NAMED.put('7', NamedTextColor.GRAY);
20+
LEGACY_TO_NAMED.put('8', NamedTextColor.DARK_GRAY);
21+
LEGACY_TO_NAMED.put('9', NamedTextColor.BLUE);
22+
LEGACY_TO_NAMED.put('a', NamedTextColor.GREEN);
23+
LEGACY_TO_NAMED.put('b', NamedTextColor.AQUA);
24+
LEGACY_TO_NAMED.put('c', NamedTextColor.RED);
25+
LEGACY_TO_NAMED.put('d', NamedTextColor.LIGHT_PURPLE);
26+
LEGACY_TO_NAMED.put('e', NamedTextColor.YELLOW);
27+
LEGACY_TO_NAMED.put('f', NamedTextColor.WHITE);
28+
29+
// 逆引きマップを自動で生成
30+
for (var entry : LEGACY_TO_NAMED.entrySet()) {
31+
NAMED_TO_LEGACY.put(entry.getValue(), "&" + entry.getKey());
32+
}
33+
}
34+
35+
public static NamedTextColor fromLegacyCode(String legacy) {
36+
if (legacy == null || legacy.length() < 2 || legacy.charAt(0) != '&') return null;
37+
char code = Character.toLowerCase(legacy.charAt(1));
38+
return LEGACY_TO_NAMED.get(code);
39+
}
40+
41+
public static String toLegacyCode(NamedTextColor color) {
42+
return NAMED_TO_LEGACY.getOrDefault(color, "&f");
43+
}
44+
}

0 commit comments

Comments
 (0)