Skip to content

Commit aade61e

Browse files
fix: update build issues
1 parent c63b3dd commit aade61e

10 files changed

Lines changed: 110 additions & 64 deletions

File tree

PistonChat/src/main/java/net/pistonmaster/pistonchat/PistonChat.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.bukkit.plugin.java.JavaPlugin;
3030

3131
import java.io.IOException;
32+
import java.util.logging.Level;
3233
import java.util.logging.Logger;
3334

3435
@Getter
@@ -73,7 +74,7 @@ public void onEnable() {
7374
log.info(ChatColor.DARK_GREEN + "Loading storage");
7475
var storageType = configManager.get().getString("storage");
7576
if (storageType.equalsIgnoreCase("mysql")) {
76-
storage = new MySQLStorage(log, configManager);
77+
storage = MySQLStorage.create(log, configManager);
7778
} else if (storageType.equalsIgnoreCase("file")) {
7879
storage = new FileStorage(log, getDataFolder().toPath());
7980
}
@@ -172,6 +173,11 @@ public FileConfiguration getLanguage() {
172173
}
173174

174175
public void runAsync(Runnable runnable) {
175-
var unused = foliaLib.getScheduler().runAsync(task -> runnable.run());
176+
foliaLib.getScheduler()
177+
.runAsync(task -> runnable.run())
178+
.exceptionally(throwable -> {
179+
getLogger().log(Level.SEVERE, "Async task failed", throwable);
180+
return null;
181+
});
176182
}
177183
}

PistonChat/src/main/java/net/pistonmaster/pistonchat/api/PistonChatAPI.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,27 @@
33
import net.pistonmaster.pistonchat.PistonChat;
44

55
import java.util.Objects;
6+
import java.util.concurrent.atomic.AtomicReference;
67

78
/**
89
* API for interacting with PistonChat!
910
*/
1011
@SuppressWarnings({"unused"})
1112
public final class PistonChatAPI {
12-
private static PistonChat plugin = null;
13+
private static final AtomicReference<PistonChat> INSTANCE = new AtomicReference<>();
1314

1415
private PistonChatAPI() {
1516
}
1617

1718
public static PistonChat getInstance() {
18-
return Objects.requireNonNull(plugin, "plugin is null");
19+
return Objects.requireNonNull(INSTANCE.get(), "plugin is null");
1920
}
2021

21-
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "MS_EXPOSE_REP", justification = "Plugin singleton pattern - intentional API design")
2222
public static void setInstance(PistonChat plugin) {
23-
if (plugin != null && PistonChatAPI.plugin == null)
24-
PistonChatAPI.plugin = plugin;
23+
if (plugin == null) {
24+
return;
25+
}
26+
27+
INSTANCE.compareAndSet(null, plugin);
2528
}
2629
}

PistonChat/src/main/java/net/pistonmaster/pistonchat/commands/MainCommand.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import java.util.ArrayList;
1818
import java.util.Collections;
1919
import java.util.List;
20+
import java.util.Locale;
2021
import java.util.Map;
2122

2223
@RequiredArgsConstructor

PistonChat/src/main/java/net/pistonmaster/pistonchat/storage/mysql/MySQLStorage.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,29 @@
1313
import java.util.ArrayList;
1414
import java.util.List;
1515
import java.util.UUID;
16+
import java.util.logging.Level;
1617
import java.util.logging.Logger;
1718

1819
public class MySQLStorage implements PCStorage {
1920
private final MariaDbPoolDataSource ds;
2021

21-
public MySQLStorage(Logger log, ConfigManager configManager) {
22+
private MySQLStorage(MariaDbPoolDataSource dataSource) {
23+
this.ds = dataSource;
24+
}
25+
26+
public static MySQLStorage create(Logger log, ConfigManager configManager) {
2227
log.info(ChatColor.DARK_GREEN + "Connecting to database");
23-
ds = new MariaDbPoolDataSource();
28+
MariaDbPoolDataSource dataSource = new MariaDbPoolDataSource();
2429
FileConfiguration config = configManager.get();
2530
try {
26-
ds.setUser(config.getString("mysql.username"));
27-
ds.setPassword(config.getString("mysql.password"));
28-
ds.setUrl("jdbc:mariadb://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") +
31+
dataSource.setUser(config.getString("mysql.username"));
32+
dataSource.setPassword(config.getString("mysql.password"));
33+
dataSource.setUrl("jdbc:mariadb://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") +
2934
"/" + config.getString("mysql.database")
3035
+ "?sslMode=disable&serverTimezone=UTC&maxPoolSize=10"
3136
);
3237

33-
try (Connection connection = ds.getConnection();
38+
try (Connection connection = dataSource.getConnection();
3439
var stmt1 = connection.createStatement();
3540
var stmt2 = connection.createStatement();
3641
var stmt3 = connection.createStatement()) {
@@ -45,10 +50,13 @@ public MySQLStorage(Logger log, ConfigManager configManager) {
4550
"PRIMARY KEY (`uuid`, `ignored_uuid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;");
4651
}
4752
} catch (SQLException e) {
48-
e.printStackTrace();
53+
log.log(Level.SEVERE, "Failed to initialize database connection", e);
54+
throw new IllegalStateException("Unable to initialize PistonChat database", e);
4955
}
5056

5157
log.info(ChatColor.DARK_GREEN + "Connected to database");
58+
59+
return new MySQLStorage(dataSource);
5260
}
5361

5462
@Override

PistonFilter/src/main/java/net/pistonmaster/pistonfilter/hooks/PistonMuteHook.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import net.pistonmaster.pistonmute.utils.StorageTool;
44
import org.bukkit.entity.Player;
55

6-
import java.util.Date;
6+
import java.time.Instant;
77

88
public class PistonMuteHook {
9-
public static void mute(Player player, Date date) {
10-
StorageTool.tempMutePlayer(player, date);
9+
public static void mute(Player player, Instant unmuteAt) {
10+
StorageTool.tempMutePlayer(player, unmuteAt);
1111
}
1212
}

PistonFilter/src/main/java/net/pistonmaster/pistonfilter/listeners/ChatListener.java

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import net.pistonmaster.pistonchat.utils.UniqueSender;
1111
import net.pistonmaster.pistonfilter.PistonFilter;
1212
import net.pistonmaster.pistonfilter.hooks.PistonMuteHook;
13-
import net.pistonmaster.pistonfilter.utils.FilteredPlayer;
1413
import net.pistonmaster.pistonfilter.utils.MaxSizeDeque;
1514
import net.pistonmaster.pistonfilter.utils.MessageInfo;
1615
import net.pistonmaster.pistonfilter.utils.StringHelper;
@@ -32,7 +31,7 @@
3231
public class ChatListener implements Listener {
3332
private final PistonFilter plugin;
3433
private final Deque<MessageInfo> globalMessages;
35-
private final Map<UUID, FilteredPlayer> players = new ConcurrentHashMap<>();
34+
private final Map<UUID, Deque<MessageInfo>> players = new ConcurrentHashMap<>();
3635
private final Cache<UUID, AtomicInteger> violationsCache;
3736

3837
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "Plugin instance is intentionally shared")
@@ -97,13 +96,10 @@ public void handleMessage(CommandSender sender, MessageInfo message, Runnable ca
9796

9897
if (plugin.getConfig().getBoolean("no-repeat")) {
9998
UUID uuid = new UniqueSender(sender).getUniqueId();
100-
FilteredPlayer filteredPlayerCached = players.compute(uuid, (k, v) ->
101-
Objects.requireNonNullElseGet(v, () -> new FilteredPlayer(new UniqueSender(sender).getUniqueId(),
102-
new MaxSizeDeque<>(plugin.getConfig().getInt("no-repeat-stack-size")))));
103-
10499
int noRepeatTime = plugin.getConfig().getInt("no-repeat-time");
105100
int similarRatio = plugin.getConfig().getInt("no-repeat-similar-ratio");
106-
Deque<MessageInfo> lastMessages = filteredPlayerCached.lastMessages();
101+
Deque<MessageInfo> lastMessages = players.compute(uuid, (k, v) ->
102+
Objects.requireNonNullElseGet(v, () -> new MaxSizeDeque<>(plugin.getConfig().getInt("no-repeat-stack-size"))));
107103

108104
boolean blocked = isBlocked(sender, message, cancelEvent, sendEmpty, noRepeatTime, similarRatio, lastMessages, false);
109105

@@ -112,7 +108,7 @@ public void handleMessage(CommandSender sender, MessageInfo message, Runnable ca
112108
}
113109

114110
if (!blocked) {
115-
filteredPlayerCached.lastMessages().add(message);
111+
lastMessages.add(message);
116112
globalMessages.add(message);
117113
}
118114
}
@@ -194,7 +190,7 @@ private void cancelMessage(CommandSender sender, MessageInfo message, Runnable c
194190
if (violations > plugin.getConfig().getInt("mute-violations")) {
195191
violationsCache.invalidate(uniqueSender.getUniqueId());
196192
int muteTime = plugin.getConfig().getInt("mute-time");
197-
PistonMuteHook.mute(player, Date.from(Instant.now().plus(muteTime, ChronoUnit.SECONDS)));
193+
PistonMuteHook.mute(player, Instant.now().plus(muteTime, ChronoUnit.SECONDS));
198194
if (plugin.getConfig().getBoolean("verbose")) {
199195
plugin.getLogger().info(ChatColor.RED + "[AntiSpam] Muted " + uniqueSender.sender().getName() + " for " + muteTime + " seconds.");
200196
}

PistonFilter/src/main/java/net/pistonmaster/pistonfilter/utils/FilteredPlayer.java

Lines changed: 0 additions & 8 deletions
This file was deleted.

PistonMute/src/main/java/net/pistonmaster/pistonmute/commands/MuteCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
5151
return false;
5252
}
5353

54-
if (StorageTool.tempMutePlayer(player, Date.from(muteUntil))) {
54+
if (StorageTool.tempMutePlayer(player, muteUntil)) {
5555
successMessage(sender, player);
5656
} else {
5757
alreadyMutedMessage(sender, player);

PistonMute/src/main/java/net/pistonmaster/pistonmute/utils/StorageTool.java

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,18 @@
88

99
import java.io.File;
1010
import java.io.IOException;
11-
import java.text.ParseException;
12-
import java.text.SimpleDateFormat;
1311
import java.time.Instant;
14-
import java.util.Date;
12+
import java.time.format.DateTimeFormatter;
13+
import java.time.format.DateTimeParseException;
1514
import java.util.Locale;
15+
import java.util.Objects;
16+
import java.util.concurrent.atomic.AtomicReference;
1617
import java.util.stream.Collectors;
1718
import java.util.stream.Stream;
1819

1920
public final class StorageTool {
20-
private static PistonMute plugin;
21+
private static final AtomicReference<PistonMute> PLUGIN = new AtomicReference<>();
22+
private static final DateTimeFormatter LEGACY_FORMATTER = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
2123
private static FileConfiguration dataConfig;
2224
private static File dataFile;
2325

@@ -28,14 +30,16 @@ private StorageTool() {
2830
* Mute a player temporarily!
2931
*
3032
* @param player The player to mute.
31-
* @param date The date when the player will be unmuted.
33+
* @param muteUntil The instant when the player will be unmuted.
3234
* @return true if player got muted and if already muted false.
3335
*/
34-
public static boolean tempMutePlayer(Player player, Date date) {
36+
public static boolean tempMutePlayer(Player player, Instant muteUntil) {
3537
manageMute(player);
3638

37-
if (!dataConfig.contains(player.getUniqueId().toString())) {
38-
dataConfig.set(player.getUniqueId().toString(), date.toString());
39+
String key = player.getUniqueId().toString();
40+
41+
if (!dataConfig.contains(key)) {
42+
dataConfig.set(key, Objects.requireNonNull(muteUntil, "muteUntil").toString());
3943

4044
saveData();
4145

@@ -97,21 +101,18 @@ public static boolean isMuted(OfflinePlayer player) {
97101
}
98102

99103
private static void manageMute(OfflinePlayer player) {
100-
Instant now = Instant.now();
101-
102-
if (dataConfig.contains(player.getUniqueId().toString())) {
103-
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.US);
104+
String key = player.getUniqueId().toString();
105+
if (!dataConfig.contains(key)) {
106+
return;
107+
}
104108

105-
try {
106-
Date date = sdf.parse(dataConfig.getString(player.getUniqueId().toString()));
107-
Instant muteUntil = date.toInstant();
109+
Instant muteUntil = parseMuteUntil(dataConfig.getString(key), key);
110+
if (muteUntil == null) {
111+
return;
112+
}
108113

109-
if (now.isAfter(muteUntil) || now.equals(muteUntil)) {
110-
unMutePlayer(player);
111-
}
112-
} catch (ParseException e) {
113-
plugin.getLogger().warning("Failed to parse mute date for player " + player.getUniqueId() + ": " + e.getMessage());
114-
}
114+
if (!Instant.now().isBefore(muteUntil)) {
115+
unMutePlayer(player);
115116
}
116117
}
117118

@@ -127,34 +128,63 @@ private static void saveData() {
127128
try {
128129
dataConfig.save(dataFile);
129130
} catch (IOException e) {
130-
plugin.getLogger().warning("Failed to save mute data: " + e.getMessage());
131+
logWarning("Failed to save mute data: " + e.getMessage());
131132
}
132133
}
133134

134135
private static void generateFile() {
135-
if (!plugin.getDataFolder().exists() && !plugin.getDataFolder().mkdir()) {
136-
plugin.getLogger().warning("Failed to create plugin data folder.");
136+
File dataFolder = plugin().getDataFolder();
137+
if (!dataFolder.exists() && !dataFolder.mkdir()) {
138+
logWarning("Failed to create plugin data folder.");
137139
}
138140

139141
if (!dataFile.exists()) {
140142
try {
141143
if (!dataFile.createNewFile()) {
142-
plugin.getLogger().warning("Mute data file already exists.");
144+
logWarning("Mute data file already exists.");
143145
}
144146
} catch (IOException e) {
145-
plugin.getLogger().warning("Failed to create mute data file: " + e.getMessage());
147+
logWarning("Failed to create mute data file: " + e.getMessage());
146148
}
147149
}
148150
}
149151

150-
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "MS_EXPOSE_REP", justification = "Plugin singleton pattern - intentional API design")
151152
public static void setupTool(PistonMute plugin) {
152-
if (plugin == null || StorageTool.plugin != null)
153+
if (plugin == null) {
154+
return;
155+
}
156+
157+
if (!PLUGIN.compareAndSet(null, plugin)) {
153158
return;
159+
}
154160

155-
StorageTool.plugin = plugin;
156161
StorageTool.dataFile = new File(plugin.getDataFolder(), "data.yml");
157162

158163
loadData();
159164
}
165+
166+
private static PistonMute plugin() {
167+
return Objects.requireNonNull(PLUGIN.get(), "StorageTool has not been initialized");
168+
}
169+
170+
private static void logWarning(String message) {
171+
plugin().getLogger().warning(message);
172+
}
173+
174+
private static Instant parseMuteUntil(String raw, String playerId) {
175+
if (raw == null) {
176+
return null;
177+
}
178+
179+
try {
180+
return Instant.parse(raw);
181+
} catch (DateTimeParseException ignored) {
182+
try {
183+
return Instant.from(LEGACY_FORMATTER.parse(raw));
184+
} catch (DateTimeParseException e) {
185+
logWarning("Failed to parse mute date for player " + playerId + ": " + e.getMessage());
186+
return null;
187+
}
188+
}
189+
}
160190
}

buildSrc/src/main/kotlin/pc.java-conventions.gradle.kts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import com.github.spotbugs.snom.SpotBugsTask
2+
import org.gradle.api.tasks.SourceSetContainer
3+
14
plugins {
25
`java-library`
36
`maven-publish`
@@ -23,6 +26,7 @@ dependencies {
2326
rewrite("org.openrewrite.recipe:rewrite-rewrite:0.14.1")
2427

2528
compileOnly("net.luckperms:api:5.5")
29+
compileOnly("com.github.spotbugs:spotbugs-annotations:4.8.6")
2630

2731
compileOnly("org.projectlombok:lombok:1.18.42")
2832
annotationProcessor("org.projectlombok:lombok:1.18.42")
@@ -69,6 +73,12 @@ tasks.withType<Javadoc> {
6973
enabled = false
7074
}
7175

76+
val sourceSets = extensions.getByType<SourceSetContainer>()
77+
78+
tasks.withType<SpotBugsTask>().configureEach {
79+
auxClassPaths.from(sourceSets.map { it.compileClasspath })
80+
}
81+
7282
val repoName = if (version.toString().endsWith("SNAPSHOT")) "maven-snapshots" else "maven-releases"
7383
publishing {
7484
repositories {

0 commit comments

Comments
 (0)