88import org .bukkit .plugin .java .JavaPlugin ;
99import 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
1221public 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