Skip to content
This repository was archived by the owner on Mar 9, 2026. It is now read-only.

Commit c96c640

Browse files
committed
[PP-2]: Improve detection of failed/loaded plugins
1 parent 597ba56 commit c96c640

1 file changed

Lines changed: 168 additions & 20 deletions

File tree

src/main/java/com/plexprison/serverpersistence/ServerPersistence.java

Lines changed: 168 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,185 @@
88
import org.bukkit.plugin.java.JavaPlugin;
99
import org.bukkit.scheduler.BukkitRunnable;
1010

11+
import java.util.ArrayList;
12+
import java.util.HashMap;
13+
import java.util.List;
14+
import java.util.Map;
15+
16+
/**
17+
* Main plugin class for ServerPersistence.
18+
* Handles plugin loading coordination and game state initialization.
19+
*/
1120
@Getter
1221
public class ServerPersistence extends JavaPlugin implements Listener {
1322

23+
private static final int REQUIRED_STABLE_TICKS = 20; // 1 second of stable state
24+
1425
@Override
1526
public void onEnable() {
16-
// Wait for all other plugins to be enabled
17-
new BukkitRunnable() {
18-
@Override
19-
public void run() {
20-
final PluginManager pluginManager = ServerPersistence.this.getServer().getPluginManager();
21-
boolean allPluginsEnabled = true;
22-
23-
// Check if all plugins except this one are enabled
24-
for (final Plugin plugin : pluginManager.getPlugins()) {
25-
if (!plugin.equals(ServerPersistence.this) && !plugin.isEnabled()) {
26-
allPluginsEnabled = false;
27-
break;
27+
// Wait for all other plugins to be enabled or failed
28+
new PluginLoadingCoordinator().runTaskTimer(this, 1L, 1L);
29+
}
30+
31+
/**
32+
* Sets up the game state by initializing the EmptyGame.
33+
*/
34+
private static void setState() {
35+
new EmptyGame().setup();
36+
}
37+
38+
/**
39+
* Coordinates the loading of all plugins and manages the transition to game state.
40+
* Monitors plugin states and ensures all plugins have finished loading before proceeding.
41+
*/
42+
private class PluginLoadingCoordinator extends BukkitRunnable {
43+
private final Map<String, Boolean> pluginStates = new HashMap<>();
44+
private final List<String> warnedPlugins = new ArrayList<>();
45+
private int stableTicks = 0;
46+
47+
@Override
48+
public void run() {
49+
final PluginStateSnapshot snapshot = this.createPluginStateSnapshot();
50+
51+
if (this.hasPluginStatesChanged(snapshot.getCurrentStates())) {
52+
this.updatePluginStates(snapshot.getCurrentStates());
53+
} else {
54+
this.stableTicks++;
55+
}
56+
57+
this.warnAboutFailedPlugins(snapshot.getFailedPlugins());
58+
59+
if (this.shouldProceedToGameState(snapshot.isAllPluginsFinished())) {
60+
this.proceedToGameState();
61+
}
62+
}
63+
64+
/**
65+
* Creates a snapshot of the current plugin states.
66+
*
67+
* @return PluginStateSnapshot containing current plugin information
68+
*/
69+
private PluginStateSnapshot createPluginStateSnapshot() {
70+
final PluginManager pluginManager = ServerPersistence.this.getServer().getPluginManager();
71+
final Map<String, Boolean> currentStates = new HashMap<>();
72+
final List<String> failedPlugins = new ArrayList<>();
73+
boolean allPluginsFinished = true;
74+
75+
for (final Plugin plugin : pluginManager.getPlugins()) {
76+
if (!plugin.equals(ServerPersistence.this)) {
77+
final boolean isEnabled = plugin.isEnabled();
78+
currentStates.put(plugin.getName(), isEnabled);
79+
80+
if (!isEnabled) {
81+
allPluginsFinished = false;
82+
failedPlugins.add(plugin.getName());
2883
}
2984
}
85+
}
86+
87+
return new PluginStateSnapshot(currentStates, failedPlugins, allPluginsFinished);
88+
}
89+
90+
/**
91+
* Checks if plugin states have changed since the last check.
92+
*
93+
* @param currentStates Current plugin states
94+
* @return true if states have changed, false otherwise
95+
*/
96+
private boolean hasPluginStatesChanged(final Map<String, Boolean> currentStates) {
97+
return !currentStates.equals(this.pluginStates);
98+
}
3099

31-
if (allPluginsEnabled) {
32-
// All plugins are enabled, call setState
33-
ServerPersistence.setState();
34-
this.cancel();
100+
/**
101+
* Updates the stored plugin states and resets the stability counter.
102+
*
103+
* @param currentStates New plugin states to store
104+
*/
105+
private void updatePluginStates(final Map<String, Boolean> currentStates) {
106+
this.pluginStates.clear();
107+
this.pluginStates.putAll(currentStates);
108+
this.stableTicks = 0;
109+
}
110+
111+
/**
112+
* Warns about failed plugins (only once per plugin).
113+
*
114+
* @param failedPlugins List of failed plugin names
115+
*/
116+
private void warnAboutFailedPlugins(final List<String> failedPlugins) {
117+
for (final String failedPlugin : failedPlugins) {
118+
if (!this.warnedPlugins.contains(failedPlugin)) {
119+
ServerPersistence.this.getLogger().warning(
120+
"Plugin '" + failedPlugin + "' failed to load but continuing with game state setup."
121+
);
122+
this.warnedPlugins.add(failedPlugin);
35123
}
36124
}
37-
}.runTaskTimer(this, 1L, 1L); // Check every tick until all plugins are enabled
38-
}
125+
}
39126

40-
private static void setState() {
41-
new EmptyGame().setup();
127+
/**
128+
* Determines if the system should proceed to game state initialization.
129+
*
130+
* @param allPluginsFinished Whether all plugins have finished loading
131+
* @return true if you should proceed, false otherwise
132+
*/
133+
private boolean shouldProceedToGameState(final boolean allPluginsFinished) {
134+
return this.stableTicks >= ServerPersistence.REQUIRED_STABLE_TICKS && allPluginsFinished;
135+
}
136+
137+
/**
138+
* Proceeds to game state initialization and logs the status.
139+
*/
140+
private void proceedToGameState() {
141+
if (!this.warnedPlugins.isEmpty()) {
142+
ServerPersistence.this.getLogger().info(
143+
"All plugins have finished loading. Setting up game state with " +
144+
this.warnedPlugins.size() + " failed plugin(s)."
145+
);
146+
} else {
147+
ServerPersistence.this.getLogger().info(
148+
"All plugins have finished loading successfully. Setting up game state."
149+
);
150+
}
151+
ServerPersistence.setState();
152+
this.cancel();
153+
}
42154
}
43155

156+
/**
157+
* Snapshot of plugin states at a given moment.
158+
* Contains information about current plugin states, failed plugins, and overall completion status.
159+
*/
160+
private static class PluginStateSnapshot {
161+
private final Map<String, Boolean> currentStates;
162+
private final List<String> failedPlugins;
163+
private final boolean allPluginsFinished;
164+
165+
/**
166+
* Creates a new plugin state snapshot.
167+
*
168+
* @param currentStates Current plugin states
169+
* @param failedPlugins List of failed plugin names
170+
* @param allPluginsFinished Whether all plugins have finished loading
171+
*/
172+
public PluginStateSnapshot(final Map<String, Boolean> currentStates,
173+
final List<String> failedPlugins,
174+
final boolean allPluginsFinished) {
175+
this.currentStates = currentStates;
176+
this.failedPlugins = failedPlugins;
177+
this.allPluginsFinished = allPluginsFinished;
178+
}
179+
180+
public Map<String, Boolean> getCurrentStates() {
181+
return this.currentStates;
182+
}
183+
184+
public List<String> getFailedPlugins() {
185+
return this.failedPlugins;
186+
}
187+
188+
public boolean isAllPluginsFinished() {
189+
return this.allPluginsFinished;
190+
}
191+
}
44192
}

0 commit comments

Comments
 (0)