Browse Source

improved initializer resolver

Ondřej Hruška 7 years ago
parent
commit
8e9a658098
100 changed files with 1783 additions and 1519 deletions
  1. 37 37
      src/mightypork/gamecore/audio/AudioModule.java
  2. 7 7
      src/mightypork/gamecore/audio/DeferredAudio.java
  3. 22 22
      src/mightypork/gamecore/audio/IAudio.java
  4. 8 8
      src/mightypork/gamecore/audio/JointVolume.java
  5. 21 21
      src/mightypork/gamecore/audio/SoundRegistry.java
  6. 4 4
      src/mightypork/gamecore/audio/Volume.java
  7. 23 23
      src/mightypork/gamecore/audio/players/AudioPlayer.java
  8. 12 12
      src/mightypork/gamecore/audio/players/EffectPlayer.java
  9. 41 41
      src/mightypork/gamecore/audio/players/LoopPlayer.java
  10. 143 93
      src/mightypork/gamecore/core/App.java
  11. 26 10
      src/mightypork/gamecore/core/AppBackend.java
  12. 3 3
      src/mightypork/gamecore/core/BackendModule.java
  13. 30 27
      src/mightypork/gamecore/core/BasicMainLoop.java
  14. 8 8
      src/mightypork/gamecore/core/MainLoop.java
  15. 50 50
      src/mightypork/gamecore/core/config/Config.java
  16. 9 9
      src/mightypork/gamecore/core/config/KeyStrokeProperty.java
  17. 7 7
      src/mightypork/gamecore/core/events/MainLoopRequest.java
  18. 4 17
      src/mightypork/gamecore/core/events/ShutdownRequest.java
  19. 4 4
      src/mightypork/gamecore/core/events/ShutdownRequestListener.java
  20. 168 0
      src/mightypork/gamecore/core/init/InitSequence.java
  21. 29 92
      src/mightypork/gamecore/core/init/InitTask.java
  22. 41 0
      src/mightypork/gamecore/core/init/InitTaskBackend.java
  23. 9 2
      src/mightypork/gamecore/core/init/InitTaskConfig.java
  24. 12 5
      src/mightypork/gamecore/core/init/InitTaskCrashHandler.java
  25. 12 12
      src/mightypork/gamecore/core/init/InitTaskCustom.java
  26. 1 1
      src/mightypork/gamecore/core/init/InitTaskDisplay.java
  27. 22 15
      src/mightypork/gamecore/core/init/InitTaskIonizables.java
  28. 28 22
      src/mightypork/gamecore/core/init/InitTaskLog.java
  29. 7 0
      src/mightypork/gamecore/core/init/InitTaskLogHeader.java
  30. 25 13
      src/mightypork/gamecore/core/init/InitTaskMainLoop.java
  31. 1 0
      src/mightypork/gamecore/core/init/InitTaskResourceLoader.java
  32. 3 8
      src/mightypork/gamecore/core/init/InitTaskResourceLoaderAsync.java
  33. 4 4
      src/mightypork/gamecore/core/init/InitTaskResourceLoaderNone.java
  34. 9 5
      src/mightypork/gamecore/core/init/InitTaskResources.java
  35. 0 42
      src/mightypork/gamecore/core/init/InitTaskScreens.java
  36. 51 0
      src/mightypork/gamecore/core/init/InitTaskUI.java
  37. 7 0
      src/mightypork/gamecore/core/init/InitTaskWorkdir.java
  38. 5 5
      src/mightypork/gamecore/core/plugins/AppPlugin.java
  39. 16 16
      src/mightypork/gamecore/core/plugins/screenshot/InitTaskPluginScreenshot.java
  40. 2 2
      src/mightypork/gamecore/core/plugins/screenshot/ScreenshotPlugin.java
  41. 2 2
      src/mightypork/gamecore/core/plugins/screenshot/ScreenshotRequest.java
  42. 1 1
      src/mightypork/gamecore/core/plugins/screenshot/ScreenshotRequestListener.java
  43. 16 16
      src/mightypork/gamecore/core/plugins/screenshot/TaskTakeScreenshot.java
  44. 1 1
      src/mightypork/gamecore/graphics/FullscreenToggleRequest.java
  45. 102 102
      src/mightypork/gamecore/graphics/GraphicsModule.java
  46. 2 2
      src/mightypork/gamecore/graphics/Renderable.java
  47. 1 1
      src/mightypork/gamecore/graphics/Screenshot.java
  48. 26 26
      src/mightypork/gamecore/graphics/fonts/DeferredFont.java
  49. 14 14
      src/mightypork/gamecore/graphics/fonts/FontRegistry.java
  50. 41 41
      src/mightypork/gamecore/graphics/fonts/FontRenderer.java
  51. 3 3
      src/mightypork/gamecore/graphics/fonts/FontStyle.java
  52. 11 11
      src/mightypork/gamecore/graphics/fonts/Glyphs.java
  53. 15 15
      src/mightypork/gamecore/graphics/fonts/IFont.java
  54. 11 11
      src/mightypork/gamecore/graphics/textures/DeferredTexture.java
  55. 13 13
      src/mightypork/gamecore/graphics/textures/ITexture.java
  56. 14 14
      src/mightypork/gamecore/graphics/textures/QuadGrid.java
  57. 27 27
      src/mightypork/gamecore/graphics/textures/TextureRegistry.java
  58. 27 27
      src/mightypork/gamecore/graphics/textures/TxQuad.java
  59. 22 22
      src/mightypork/gamecore/graphics/textures/TxSheet.java
  60. 10 10
      src/mightypork/gamecore/gui/Action.java
  61. 11 11
      src/mightypork/gamecore/gui/ActionGroup.java
  62. 1 1
      src/mightypork/gamecore/gui/HasAction.java
  63. 41 41
      src/mightypork/gamecore/gui/components/BaseComponent.java
  64. 19 19
      src/mightypork/gamecore/gui/components/Component.java
  65. 1 1
      src/mightypork/gamecore/gui/components/DynamicWidthComponent.java
  66. 1 1
      src/mightypork/gamecore/gui/components/InputComponent.java
  67. 28 28
      src/mightypork/gamecore/gui/components/LayoutComponent.java
  68. 18 18
      src/mightypork/gamecore/gui/components/LinearComponent.java
  69. 6 6
      src/mightypork/gamecore/gui/components/PluggableRenderable.java
  70. 11 11
      src/mightypork/gamecore/gui/components/input/ClickableComponent.java
  71. 15 15
      src/mightypork/gamecore/gui/components/input/ClickableWrapper.java
  72. 16 16
      src/mightypork/gamecore/gui/components/input/TextButton.java
  73. 12 12
      src/mightypork/gamecore/gui/components/layout/ColumnLayout.java
  74. 6 6
      src/mightypork/gamecore/gui/components/layout/ConstraintLayout.java
  75. 15 15
      src/mightypork/gamecore/gui/components/layout/FlowColumnLayout.java
  76. 14 14
      src/mightypork/gamecore/gui/components/layout/FlowRowLayout.java
  77. 14 14
      src/mightypork/gamecore/gui/components/layout/GridLayout.java
  78. 1 1
      src/mightypork/gamecore/gui/components/layout/NullComponent.java
  79. 12 12
      src/mightypork/gamecore/gui/components/layout/RowLayout.java
  80. 14 14
      src/mightypork/gamecore/gui/components/layout/linear/AbstractLinearWrapper.java
  81. 3 3
      src/mightypork/gamecore/gui/components/layout/linear/LinearGap.java
  82. 17 17
      src/mightypork/gamecore/gui/components/layout/linear/LinearLayout.java
  83. 8 8
      src/mightypork/gamecore/gui/components/layout/linear/LinearRectangle.java
  84. 4 4
      src/mightypork/gamecore/gui/components/layout/linear/LinearSquare.java
  85. 4 4
      src/mightypork/gamecore/gui/components/layout/linear/LinearWrapper.java
  86. 9 9
      src/mightypork/gamecore/gui/components/painters/ImagePainter.java
  87. 10 10
      src/mightypork/gamecore/gui/components/painters/QuadPainter.java
  88. 45 45
      src/mightypork/gamecore/gui/components/painters/TextPainter.java
  89. 1 1
      src/mightypork/gamecore/gui/events/LayoutChangeEvent.java
  90. 1 1
      src/mightypork/gamecore/gui/events/LayoutChangeListener.java
  91. 6 6
      src/mightypork/gamecore/gui/events/ScreenRequest.java
  92. 1 1
      src/mightypork/gamecore/gui/events/ScreenRequestListener.java
  93. 7 7
      src/mightypork/gamecore/gui/events/ViewportChangeEvent.java
  94. 1 1
      src/mightypork/gamecore/gui/events/ViewportChangeListener.java
  95. 24 24
      src/mightypork/gamecore/gui/screens/LayeredScreen.java
  96. 49 49
      src/mightypork/gamecore/gui/screens/Overlay.java
  97. 38 38
      src/mightypork/gamecore/gui/screens/Screen.java
  98. 9 9
      src/mightypork/gamecore/gui/screens/ScreenLayer.java
  99. 20 20
      src/mightypork/gamecore/gui/screens/ScreenRegistry.java
  100. 0 0
      src/mightypork/gamecore/gui/screens/impl/CrossfadeOverlay.java

+ 37 - 37
src/mightypork/gamecore/audio/AudioModule.java View File

@@ -19,50 +19,50 @@ import mightypork.utils.math.constraints.vect.Vect;
19 19
  * @author Ondřej Hruška (MightyPork)
20 20
  */
21 21
 public abstract class AudioModule extends BackendModule implements Updateable {
22
-
22
+	
23 23
 	/**
24 24
 	 * Set listener position
25 25
 	 *
26 26
 	 * @param pos listener position
27 27
 	 */
28 28
 	public abstract void setListenerPos(Vect pos);
29
-
30
-
29
+	
30
+	
31 31
 	/**
32 32
 	 * Get current listener position
33 33
 	 *
34 34
 	 * @return listener position
35 35
 	 */
36 36
 	public abstract Vect getListenerPos();
37
-
37
+	
38 38
 	// -- instance --
39
-
39
+	
40 40
 	private final Volume masterVolume = new Volume(1D);
41 41
 	private final Volume effectsVolume = new JointVolume(masterVolume);
42 42
 	private final Volume loopsVolume = new JointVolume(masterVolume);
43
-
43
+	
44 44
 	private final List<LoopPlayer> loopPlayers = new ArrayList<>();
45 45
 	private final List<DeferredAudio> resources = new ArrayList<>();
46
-
47
-
46
+	
47
+	
48 48
 	@Override
49 49
 	public void destroy()
50 50
 	{
51 51
 		for (final DeferredAudio r : resources) {
52 52
 			r.destroy();
53 53
 		}
54
-
54
+		
55 55
 		deinitSoundSystem();
56 56
 	}
57
-
58
-
57
+	
58
+	
59 59
 	/**
60 60
 	 * Deinitialize the soud system, release resources etc.<br>
61 61
 	 * Audio resources are already destroyed.
62 62
 	 */
63 63
 	protected abstract void deinitSoundSystem();
64
-
65
-
64
+	
65
+	
66 66
 	@Override
67 67
 	public void update(double delta)
68 68
 	{
@@ -70,8 +70,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
70 70
 			lp.update(delta);
71 71
 		}
72 72
 	}
73
-
74
-
73
+	
74
+	
75 75
 	/**
76 76
 	 * Create effect resource
77 77
 	 *
@@ -82,8 +82,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
82 82
 	{
83 83
 		return new EffectPlayer(createAudioResource(resource), effectsVolume);
84 84
 	}
85
-
86
-
85
+	
86
+	
87 87
 	/**
88 88
 	 * Register loop resource (music / effect loop)
89 89
 	 *
@@ -96,8 +96,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
96 96
 		loopPlayers.add(p);
97 97
 		return p;
98 98
 	}
99
-
100
-
99
+	
100
+	
101 101
 	/**
102 102
 	 * Create {@link DeferredAudio} for a resource, request deferred load and
103 103
 	 * add to the resources list.<br>
@@ -115,8 +115,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
115 115
 		resources.add(a);
116 116
 		return a;
117 117
 	}
118
-
119
-
118
+	
119
+	
120 120
 	/**
121 121
 	 * Create a backend-specific deferred audio resource.<br>
122 122
 	 * The actual resource instance should be created here. Registering, loading
@@ -126,8 +126,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
126 126
 	 * @return Deferred Audio
127 127
 	 */
128 128
 	protected abstract DeferredAudio doCreateResource(String res);
129
-
130
-
129
+	
130
+	
131 131
 	/**
132 132
 	 * Fade out all loops (= fade out the currently playing loops)
133 133
 	 */
@@ -137,8 +137,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
137 137
 			p.fadeOut();
138 138
 		}
139 139
 	}
140
-
141
-
140
+	
141
+	
142 142
 	/**
143 143
 	 * Pause all loops (leave volume unchanged)
144 144
 	 */
@@ -148,8 +148,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
148 148
 			p.pause();
149 149
 		}
150 150
 	}
151
-
152
-
151
+	
152
+	
153 153
 	/**
154 154
 	 * Set level of master volume (volume multiplier)
155 155
 	 *
@@ -159,8 +159,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
159 159
 	{
160 160
 		masterVolume.set(volume);
161 161
 	}
162
-
163
-
162
+	
163
+	
164 164
 	/**
165 165
 	 * Set level of effects volume (volume multiplier)
166 166
 	 *
@@ -170,8 +170,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
170 170
 	{
171 171
 		effectsVolume.set(volume);
172 172
 	}
173
-
174
-
173
+	
174
+	
175 175
 	/**
176 176
 	 * Set level of loops volume (volume multiplier)
177 177
 	 *
@@ -181,8 +181,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
181 181
 	{
182 182
 		loopsVolume.set(volume);
183 183
 	}
184
-
185
-
184
+	
185
+	
186 186
 	/**
187 187
 	 * Get level of master volume (volume multiplier)
188 188
 	 *
@@ -192,8 +192,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
192 192
 	{
193 193
 		return masterVolume.get();
194 194
 	}
195
-
196
-
195
+	
196
+	
197 197
 	/**
198 198
 	 * Get level of effects volume (volume multiplier)
199 199
 	 *
@@ -203,8 +203,8 @@ public abstract class AudioModule extends BackendModule implements Updateable {
203 203
 	{
204 204
 		return effectsVolume.get();
205 205
 	}
206
-
207
-
206
+	
207
+	
208 208
 	/**
209 209
 	 * Get level of loops volume (volume multiplier)
210 210
 	 *

+ 7 - 7
src/mightypork/gamecore/audio/DeferredAudio.java View File

@@ -14,7 +14,7 @@ import mightypork.utils.math.constraints.vect.Vect;
14 14
  */
15 15
 @Alias(name = "Audio")
16 16
 public abstract class DeferredAudio extends BaseDeferredResource implements IAudio {
17
-	
17
+
18 18
 	/**
19 19
 	 * Create audio
20 20
 	 *
@@ -24,22 +24,22 @@ public abstract class DeferredAudio extends BaseDeferredResource implements IAud
24 24
 	{
25 25
 		super(resourceName);
26 26
 	}
27
-
28
-
27
+	
28
+	
29 29
 	@Override
30 30
 	public void play(double gain, double pitch, boolean loop)
31 31
 	{
32 32
 		play(gain, pitch, loop, App.sound().getListenerPos());
33 33
 	}
34
-
35
-
34
+	
35
+	
36 36
 	@Override
37 37
 	public void play(double gain, double pitch, boolean loop, double x, double y)
38 38
 	{
39 39
 		play(gain, pitch, loop, x, y, App.sound().getListenerPos().z());
40 40
 	}
41
-
42
-
41
+	
42
+	
43 43
 	@Override
44 44
 	public void play(double gain, double pitch, boolean loop, Vect pos)
45 45
 	{

+ 22 - 22
src/mightypork/gamecore/audio/IAudio.java View File

@@ -11,19 +11,19 @@ import mightypork.utils.math.constraints.vect.Vect;
11 11
  * @author Ondřej Hruška (MightyPork)
12 12
  */
13 13
 public interface IAudio extends Destroyable {
14
-
14
+	
15 15
 	/**
16 16
 	 * Pause loop (remember position and stop playing) - if was looping
17 17
 	 */
18 18
 	void pauseLoop();
19
-
20
-
19
+	
20
+	
21 21
 	/**
22 22
 	 * Resume loop (if was looping and paused)
23 23
 	 */
24 24
 	void resumeLoop();
25
-
26
-
25
+	
26
+	
27 27
 	/**
28 28
 	 * Adjust gain for the currently playing effect (can be used for fading
29 29
 	 * music)
@@ -31,27 +31,27 @@ public interface IAudio extends Destroyable {
31 31
 	 * @param gain gain to set 0..1
32 32
 	 */
33 33
 	void adjustGain(double gain);
34
-
35
-
34
+	
35
+	
36 36
 	/**
37 37
 	 * Stop audio playback, free source. Meaningful for loops, may not work
38 38
 	 * properly for effects.
39 39
 	 */
40 40
 	void stop();
41
-
42
-
41
+	
42
+	
43 43
 	/**
44 44
 	 * @return true if the audio is playing
45 45
 	 */
46 46
 	boolean isPlaying();
47
-
48
-
47
+	
48
+	
49 49
 	/**
50 50
 	 * @return trie if the audio is paused
51 51
 	 */
52 52
 	boolean isPaused();
53
-	
54
-	
53
+
54
+
55 55
 	/**
56 56
 	 * Play as sound effect at listener position
57 57
 	 *
@@ -60,8 +60,8 @@ public interface IAudio extends Destroyable {
60 60
 	 * @param loop looping
61 61
 	 */
62 62
 	void play(double gain, double pitch, boolean loop);
63
-
64
-
63
+	
64
+	
65 65
 	/**
66 66
 	 * Play as sound effect at given position
67 67
 	 *
@@ -73,8 +73,8 @@ public interface IAudio extends Destroyable {
73 73
 	 * @param z
74 74
 	 */
75 75
 	void play(double gain, double pitch, boolean loop, double x, double y, double z);
76
-
77
-
76
+	
77
+	
78 78
 	/**
79 79
 	 * Play as sound effect at given X-Y position
80 80
 	 *
@@ -85,8 +85,8 @@ public interface IAudio extends Destroyable {
85 85
 	 * @param y
86 86
 	 */
87 87
 	void play(double gain, double pitch, boolean loop, double x, double y);
88
-
89
-
88
+	
89
+	
90 90
 	/**
91 91
 	 * Play as sound effect at given position
92 92
 	 *
@@ -96,8 +96,8 @@ public interface IAudio extends Destroyable {
96 96
 	 * @param pos coord
97 97
 	 */
98 98
 	void play(double gain, double pitch, boolean loop, Vect pos);
99
-
100
-
99
+	
100
+	
101 101
 	/**
102 102
 	 * Check if this audio is currently active (ie. playing or paused, not
103 103
 	 * stopped)
@@ -105,5 +105,5 @@ public interface IAudio extends Destroyable {
105 105
 	 * @return is active
106 106
 	 */
107 107
 	boolean isActive();
108
-
108
+	
109 109
 }

+ 8 - 8
src/mightypork/gamecore/audio/JointVolume.java View File

@@ -10,10 +10,10 @@ import mightypork.utils.math.Calc;
10 10
  * @author Ondřej Hruška (MightyPork)
11 11
  */
12 12
 public class JointVolume extends Volume {
13
-	
13
+
14 14
 	private final Volume[] volumes;
15
-	
16
-	
15
+
16
+
17 17
 	/**
18 18
 	 * Create joint volume with master gain of 1
19 19
 	 *
@@ -25,8 +25,8 @@ public class JointVolume extends Volume {
25 25
 		super(1D);
26 26
 		this.volumes = volumes;
27 27
 	}
28
-	
29
-	
28
+
29
+
30 30
 	/**
31 31
 	 * Get combined gain (multiplied)
32 32
 	 */
@@ -36,11 +36,11 @@ public class JointVolume extends Volume {
36 36
 		double d = super.get();
37 37
 		for (final Volume v : volumes)
38 38
 			d *= v.get();
39
-		
39
+
40 40
 		return Calc.clamp(d, 0, 1);
41 41
 	}
42
-	
43
-	
42
+
43
+
44 44
 	/**
45 45
 	 * Set master gain
46 46
 	 */

+ 21 - 21
src/mightypork/gamecore/audio/SoundRegistry.java View File

@@ -16,11 +16,11 @@ import mightypork.utils.exceptions.KeyAlreadyExistsException;
16 16
  * @author Ondřej Hruška (MightyPork)
17 17
  */
18 18
 public class SoundRegistry {
19
-
19
+	
20 20
 	private final Map<String, EffectPlayer> effects = new HashMap<>();
21 21
 	private final Map<String, LoopPlayer> loops = new HashMap<>();
22
-
23
-
22
+	
23
+	
24 24
 	/**
25 25
 	 * Register effect resource
26 26
 	 *
@@ -33,16 +33,16 @@ public class SoundRegistry {
33 33
 	public EffectPlayer addEffect(String key, String resourcePath, double gain, double pitch)
34 34
 	{
35 35
 		final EffectPlayer effect = App.sound().createEffect(resourcePath);
36
-
36
+		
37 37
 		effect.setPitch(pitch);
38 38
 		effect.setGain(gain);
39
-
39
+		
40 40
 		addEffect(key, effect);
41
-
41
+		
42 42
 		return effect;
43 43
 	}
44
-
45
-
44
+	
45
+	
46 46
 	/**
47 47
 	 * Register effect resource
48 48
 	 *
@@ -52,11 +52,11 @@ public class SoundRegistry {
52 52
 	public void addEffect(String key, EffectPlayer effect)
53 53
 	{
54 54
 		if (effects.containsKey(key)) throw new KeyAlreadyExistsException();
55
-
55
+		
56 56
 		effects.put(key, effect);
57 57
 	}
58
-
59
-
58
+	
59
+	
60 60
 	/**
61 61
 	 * Register loop resource (music / effect loop)
62 62
 	 *
@@ -71,17 +71,17 @@ public class SoundRegistry {
71 71
 	public LoopPlayer addLoop(String key, String resourcePath, double gain, double pitch, double fadeIn, double fadeOut)
72 72
 	{
73 73
 		final LoopPlayer loop = App.sound().createLoop(resourcePath);
74
-		
74
+
75 75
 		loop.setPitch(pitch);
76 76
 		loop.setGain(gain);
77 77
 		loop.setFadeTimes(fadeIn, fadeOut);
78
-		
78
+
79 79
 		addLoop(key, loop);
80
-		
80
+
81 81
 		return loop;
82 82
 	}
83
-
84
-
83
+	
84
+	
85 85
 	/**
86 86
 	 * Register loop resource (music / effect loop)
87 87
 	 *
@@ -91,11 +91,11 @@ public class SoundRegistry {
91 91
 	public void addLoop(String key, LoopPlayer loop)
92 92
 	{
93 93
 		if (loops.containsKey(key)) throw new KeyAlreadyExistsException();
94
-
94
+		
95 95
 		loops.put(key, loop);
96 96
 	}
97
-
98
-
97
+	
98
+	
99 99
 	/**
100 100
 	 * Get a loop player for key
101 101
 	 *
@@ -110,8 +110,8 @@ public class SoundRegistry {
110 110
 		}
111 111
 		return p;
112 112
 	}
113
-
114
-
113
+	
114
+	
115 115
 	/**
116 116
 	 * Get a effect player for key
117 117
 	 *

+ 4 - 4
src/mightypork/gamecore/audio/Volume.java View File

@@ -11,7 +11,7 @@ import mightypork.utils.struct.Mutable;
11 11
  * @author Ondřej Hruška (MightyPork)
12 12
  */
13 13
 public class Volume extends Mutable<Double> {
14
-	
14
+
15 15
 	/**
16 16
 	 * @param d initial value
17 17
 	 */
@@ -19,12 +19,12 @@ public class Volume extends Mutable<Double> {
19 19
 	{
20 20
 		super(d);
21 21
 	}
22
-	
23
-	
22
+
23
+
24 24
 	@Override
25 25
 	public void set(Double d)
26 26
 	{
27 27
 		super.set(Calc.clamp(d, 0, 1));
28 28
 	}
29
-	
29
+
30 30
 }

+ 23 - 23
src/mightypork/gamecore/audio/players/AudioPlayer.java View File

@@ -12,20 +12,20 @@ import mightypork.utils.interfaces.Destroyable;
12 12
  * @author Ondřej Hruška (MightyPork)
13 13
  */
14 14
 public abstract class AudioPlayer implements Destroyable {
15
-	
15
+
16 16
 	/** the track */
17 17
 	private final IAudio audio;
18
-	
18
+
19 19
 	/** base gain for sfx */
20 20
 	private double baseGain;
21
-	
21
+
22 22
 	/** base pitch for sfx */
23 23
 	private double basePitch;
24
-	
24
+
25 25
 	/** dedicated volume control */
26 26
 	private final Volume gainMultiplier;
27
-	
28
-	
27
+
28
+
29 29
 	/**
30 30
 	 * @param track audio resource
31 31
 	 * @param volume colume control
@@ -33,20 +33,20 @@ public abstract class AudioPlayer implements Destroyable {
33 33
 	public AudioPlayer(IAudio track, Volume volume)
34 34
 	{
35 35
 		this.audio = track;
36
-		
36
+
37 37
 		if (volume == null) volume = new Volume(1D);
38
-		
38
+
39 39
 		this.gainMultiplier = volume;
40 40
 	}
41
-	
42
-	
41
+
42
+
43 43
 	@Override
44 44
 	public void destroy()
45 45
 	{
46 46
 		audio.destroy();
47 47
 	}
48
-	
49
-	
48
+
49
+
50 50
 	/**
51 51
 	 * @return audio resource
52 52
 	 */
@@ -54,8 +54,8 @@ public abstract class AudioPlayer implements Destroyable {
54 54
 	{
55 55
 		return audio;
56 56
 	}
57
-	
58
-	
57
+
58
+
59 59
 	/**
60 60
 	 * Get play gain, computed based on volume and given multiplier
61 61
 	 *
@@ -66,8 +66,8 @@ public abstract class AudioPlayer implements Destroyable {
66 66
 	{
67 67
 		return baseGain * gainMultiplier.get() * multiplier;
68 68
 	}
69
-	
70
-	
69
+
70
+
71 71
 	/**
72 72
 	 * Get pitch
73 73
 	 *
@@ -78,8 +78,8 @@ public abstract class AudioPlayer implements Destroyable {
78 78
 	{
79 79
 		return basePitch * multiplier;
80 80
 	}
81
-	
82
-	
81
+
82
+
83 83
 	/**
84 84
 	 * Get if audio is valid
85 85
 	 *
@@ -89,8 +89,8 @@ public abstract class AudioPlayer implements Destroyable {
89 89
 	{
90 90
 		return (audio != null);
91 91
 	}
92
-	
93
-	
92
+
93
+
94 94
 	/**
95 95
 	 * Set base gain. 1 is original volume, 0 is silence.
96 96
 	 *
@@ -100,8 +100,8 @@ public abstract class AudioPlayer implements Destroyable {
100 100
 	{
101 101
 		this.baseGain = gain;
102 102
 	}
103
-	
104
-	
103
+
104
+
105 105
 	/**
106 106
 	 * Set base pitch. 1 is original pitch, less is deeper, more is higher.
107 107
 	 *
@@ -111,5 +111,5 @@ public abstract class AudioPlayer implements Destroyable {
111 111
 	{
112 112
 		this.basePitch = pitch;
113 113
 	}
114
-
114
+	
115 115
 }

+ 12 - 12
src/mightypork/gamecore/audio/players/EffectPlayer.java View File

@@ -12,7 +12,7 @@ import mightypork.utils.math.constraints.vect.Vect;
12 12
  * @author Ondřej Hruška (MightyPork)
13 13
  */
14 14
 public class EffectPlayer extends AudioPlayer {
15
-
15
+	
16 16
 	/**
17 17
 	 * @param track audio resource
18 18
 	 * @param volume volume control
@@ -21,8 +21,8 @@ public class EffectPlayer extends AudioPlayer {
21 21
 	{
22 22
 		super(track, volume);
23 23
 	}
24
-
25
-
24
+	
25
+	
26 26
 	/**
27 27
 	 * Play at listener
28 28
 	 *
@@ -32,11 +32,11 @@ public class EffectPlayer extends AudioPlayer {
32 32
 	public void play(double gain, double pitch)
33 33
 	{
34 34
 		if (!hasAudio()) return;
35
-
35
+		
36 36
 		getAudio().play(computeGain(gain), computePitch(pitch), false);
37 37
 	}
38
-
39
-
38
+	
39
+	
40 40
 	/**
41 41
 	 * Play at listener
42 42
 	 *
@@ -46,8 +46,8 @@ public class EffectPlayer extends AudioPlayer {
46 46
 	{
47 47
 		play(gain, 1);
48 48
 	}
49
-
50
-
49
+	
50
+	
51 51
 	/**
52 52
 	 * Play at given position
53 53
 	 *
@@ -58,8 +58,8 @@ public class EffectPlayer extends AudioPlayer {
58 58
 	{
59 59
 		play(gain, 1, pos);
60 60
 	}
61
-
62
-
61
+	
62
+	
63 63
 	/**
64 64
 	 * Play at given position
65 65
 	 *
@@ -70,8 +70,8 @@ public class EffectPlayer extends AudioPlayer {
70 70
 	public void play(double gain, double pitch, Vect pos)
71 71
 	{
72 72
 		if (!hasAudio()) return;
73
-
73
+		
74 74
 		getAudio().play(computeGain(gain), computePitch(pitch), false, pos);
75 75
 	}
76
-
76
+	
77 77
 }

+ 41 - 41
src/mightypork/gamecore/audio/players/LoopPlayer.java View File

@@ -14,22 +14,22 @@ import mightypork.utils.math.animation.NumAnimated;
14 14
  * @author Ondřej Hruška (MightyPork)
15 15
  */
16 16
 public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable {
17
-
17
+	
18 18
 	/** animator for fade in and fade out */
19 19
 	private final NumAnimated fadeAnim = new NumAnimated(0);
20
-	
20
+
21 21
 	private double lastUpdateGain = 0;
22
-	
22
+
23 23
 	/** flag that track is paused */
24 24
 	private boolean paused = true;
25
-	
25
+
26 26
 	/** Default fadeIn time */
27 27
 	private double inTime = 1;
28
-	
28
+
29 29
 	/** Default fadeOut time */
30 30
 	private double outTime = 1;
31
-	
32
-	
31
+
32
+
33 33
 	/**
34 34
 	 * @param track audio resource
35 35
 	 * @param volume volume control
@@ -37,11 +37,11 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable {
37 37
 	public LoopPlayer(DeferredAudio track, Volume volume)
38 38
 	{
39 39
 		super(track, volume);
40
-		
40
+
41 41
 		paused = true;
42 42
 	}
43
-
44
-
43
+	
44
+	
45 45
 	/**
46 46
 	 * Set fading duration (seconds)
47 47
 	 *
@@ -53,8 +53,8 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable {
53 53
 		inTime = in;
54 54
 		outTime = out;
55 55
 	}
56
-	
57
-	
56
+
57
+
58 58
 	private void initLoop()
59 59
 	{
60 60
 		if (hasAudio() && !getAudio().isActive()) {
@@ -62,27 +62,27 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable {
62 62
 			getAudio().pauseLoop();
63 63
 		}
64 64
 	}
65
-	
66
-	
65
+
66
+
67 67
 	@Override
68 68
 	public void pause()
69 69
 	{
70 70
 		if (!hasAudio() || paused) return;
71
-		
71
+
72 72
 		initLoop();
73
-		
73
+
74 74
 		getAudio().pauseLoop();
75 75
 		paused = true;
76 76
 	}
77
-	
78
-	
77
+
78
+
79 79
 	@Override
80 80
 	public boolean isPaused()
81 81
 	{
82 82
 		return paused;
83 83
 	}
84
-	
85
-	
84
+
85
+
86 86
 	/**
87 87
 	 * Alias to resume (more meaningful name)
88 88
 	 */
@@ -90,40 +90,40 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable {
90 90
 	{
91 91
 		resume();
92 92
 	}
93
-	
94
-	
93
+
94
+
95 95
 	@Override
96 96
 	public void resume()
97 97
 	{
98 98
 		if (!hasAudio() || !paused) return;
99
-		
99
+
100 100
 		initLoop();
101
-		
101
+
102 102
 		paused = false;
103
-		
103
+
104 104
 		getAudio().adjustGain(computeGain(fadeAnim.value()));
105 105
 	}
106
-	
107
-	
106
+
107
+
108 108
 	@Override
109 109
 	public void update(double delta)
110 110
 	{
111 111
 		if (!hasAudio() || paused) return;
112
-		
112
+
113 113
 		initLoop();
114
-		
114
+
115 115
 		fadeAnim.update(delta);
116
-		
116
+
117 117
 		final double gain = computeGain(fadeAnim.value());
118 118
 		if (!paused && gain != lastUpdateGain) {
119 119
 			getAudio().adjustGain(gain);
120 120
 			lastUpdateGain = gain;
121 121
 		}
122
-		
122
+
123 123
 		if (gain == 0 && !paused) pause(); // pause on zero volume
124 124
 	}
125
-	
126
-	
125
+
126
+
127 127
 	/**
128 128
 	 * Resume if paused, and fade in (pick up from current volume).
129 129
 	 *
@@ -132,13 +132,13 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable {
132 132
 	public void fadeIn(double fadeTime)
133 133
 	{
134 134
 		if (!hasAudio()) return;
135
-		
135
+
136 136
 		if (isPaused()) fadeAnim.setTo(0);
137 137
 		resume();
138 138
 		fadeAnim.fadeIn(fadeTime);
139 139
 	}
140
-	
141
-	
140
+
141
+
142 142
 	/**
143 143
 	 * Fade out and pause when reached zero volume
144 144
 	 *
@@ -150,8 +150,8 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable {
150 150
 		if (isPaused()) return;
151 151
 		fadeAnim.fadeOut(fadeTime);
152 152
 	}
153
-	
154
-	
153
+
154
+
155 155
 	/**
156 156
 	 * Fade in with default duration
157 157
 	 */
@@ -159,8 +159,8 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable {
159 159
 	{
160 160
 		fadeIn(inTime);
161 161
 	}
162
-	
163
-	
162
+
163
+
164 164
 	/**
165 165
 	 * Fade out with default duration
166 166
 	 */
@@ -168,5 +168,5 @@ public class LoopPlayer extends AudioPlayer implements Updateable, Pauseable {
168 168
 	{
169 169
 		fadeOut(outTime);
170 170
 	}
171
-	
171
+
172 172
 }

+ 143 - 93
src/mightypork/gamecore/core/App.java View File

@@ -1,17 +1,29 @@
1 1
 package mightypork.gamecore.core;
2 2
 
3 3
 
4
-import java.util.ArrayList;
4
+import java.io.File;
5
+import java.util.Arrays;
5 6
 import java.util.List;
6 7
 
7 8
 import mightypork.gamecore.audio.AudioModule;
8 9
 import mightypork.gamecore.core.config.Config;
9
-import mightypork.gamecore.core.events.ShutdownEvent;
10
+import mightypork.gamecore.core.events.MainLoopRequest;
11
+import mightypork.gamecore.core.events.ShutdownRequest;
12
+import mightypork.gamecore.core.init.InitSequence;
10 13
 import mightypork.gamecore.core.init.InitTask;
14
+import mightypork.gamecore.core.init.InitTaskBackend;
15
+import mightypork.gamecore.core.init.InitTaskCrashHandler;
16
+import mightypork.gamecore.core.init.InitTaskIonizables;
17
+import mightypork.gamecore.core.init.InitTaskLog;
18
+import mightypork.gamecore.core.init.InitTaskLogHeader;
19
+import mightypork.gamecore.core.init.InitTaskMainLoop;
20
+import mightypork.gamecore.core.init.InitTaskResourceLoaderAsync;
21
+import mightypork.gamecore.core.init.InitTaskWorkdir;
11 22
 import mightypork.gamecore.core.plugins.AppPlugin;
12 23
 import mightypork.gamecore.graphics.GraphicsModule;
13 24
 import mightypork.gamecore.graphics.Renderable;
14 25
 import mightypork.gamecore.input.InputModule;
26
+import mightypork.utils.Str;
15 27
 import mightypork.utils.annotations.Stub;
16 28
 import mightypork.utils.eventbus.EventBus;
17 29
 import mightypork.utils.eventbus.clients.BusNode;
@@ -26,25 +38,25 @@ import mightypork.utils.logging.Log;
26 38
  * @author MightyPork
27 39
  */
28 40
 public class App extends BusNode {
29
-	
41
+
30 42
 	private static App instance;
31
-	
43
+
32 44
 	private final AppBackend backend;
33 45
 	private final EventBus eventBus = new EventBus();
34 46
 	private boolean started = false;
35 47
 	private boolean inited = false;
36
-	
48
+
37 49
 	/** List of installed App plugins */
38 50
 	protected final DelegatingList plugins = new DelegatingList();
39 51
 	/** List of initializers */
40
-	protected final List<InitTask> initializers = new ArrayList<>();
41
-	
52
+	protected final InitSequence initTasks = new InitSequence();
53
+
42 54
 	/** The used main loop instance */
43 55
 	protected MainLoop mainLoop;
44
-	
56
+
45 57
 	private Renderable mainRenderable;
46
-	
47
-	
58
+
59
+
48 60
 	/**
49 61
 	 * Create an app with given backend.
50 62
 	 *
@@ -55,24 +67,39 @@ public class App extends BusNode {
55 67
 		if (App.instance != null) {
56 68
 			throw new IllegalStateException("App already initialized");
57 69
 		}
58
-		
70
+
59 71
 		// store current instance in static field
60 72
 		App.instance = this;
61
-		
73
+
62 74
 		// join the bus
63 75
 		this.eventBus.subscribe(this);
64
-		
76
+
65 77
 		// create plugin registry attached to bus
66
-		this.eventBus.subscribe(this.plugins);
67
-		
78
+		addChildClient(this.plugins);
79
+
68 80
 		// initialize and use backend
69 81
 		this.backend = backend;
70 82
 		this.backend.bind(this);
71
-		this.eventBus.subscribe(backend);
72
-		this.backend.initialize();
83
+		addChildClient(backend);
84
+		
85
+		addDefaultInitTasks();
86
+		this.backend.addInitTasks();
87
+	}
88
+
89
+
90
+	private void addDefaultInitTasks()
91
+	{
92
+		addInitTask(new InitTaskCrashHandler());
93
+		addInitTask(new InitTaskWorkdir(new File("."), true));
94
+		addInitTask(new InitTaskLog());
95
+		addInitTask(new InitTaskBackend());
96
+		addInitTask(new InitTaskIonizables());
97
+		addInitTask(new InitTaskMainLoop());
98
+		addInitTask(new InitTaskResourceLoaderAsync());
99
+		addInitTask(new InitTaskLogHeader());
73 100
 	}
74
-	
75
-	
101
+
102
+
76 103
 	/**
77 104
 	 * Add a plugin to the app. Plugins can eg. listen to bus events and react
78 105
 	 * to them.
@@ -86,8 +113,8 @@ public class App extends BusNode {
86 113
 		plugin.bind(this);
87 114
 		plugin.initialize();
88 115
 	}
89
-	
90
-	
116
+
117
+
91 118
 	/**
92 119
 	 * Add an initializer to the app.
93 120
 	 *
@@ -98,11 +125,11 @@ public class App extends BusNode {
98 125
 		if (started) {
99 126
 			throw new IllegalStateException("App already started, cannot add initializers.");
100 127
 		}
101
-		
102
-		initializers.add(initializer);
128
+
129
+		initTasks.addTask(initializer);
103 130
 	}
104
-	
105
-	
131
+
132
+
106 133
 	/**
107 134
 	 * Set the main loop implementation
108 135
 	 *
@@ -111,10 +138,10 @@ public class App extends BusNode {
111 138
 	public void setMainLoop(MainLoop loop)
112 139
 	{
113 140
 		this.mainLoop = loop;
114
-		bus().subscribe(loop); // ?
141
+		addChildClient(loop); // ?
115 142
 	}
116
-	
117
-	
143
+
144
+
118 145
 	/**
119 146
 	 * Set the main renderable
120 147
 	 *
@@ -124,8 +151,8 @@ public class App extends BusNode {
124 151
 	{
125 152
 		this.mainRenderable = renderable;
126 153
 	}
127
-	
128
-	
154
+
155
+
129 156
 	/**
130 157
 	 * Get current backend
131 158
 	 *
@@ -135,8 +162,8 @@ public class App extends BusNode {
135 162
 	{
136 163
 		return backend;
137 164
 	}
138
-	
139
-	
165
+
166
+
140 167
 	/**
141 168
 	 * Initialize the App and start operating.<br>
142 169
 	 * This method should be called after adding all required initializers and
@@ -148,60 +175,67 @@ public class App extends BusNode {
148 175
 			throw new IllegalStateException("Already started.");
149 176
 		}
150 177
 		started = true;
151
-
178
+		
152 179
 		Log.i("Starting init...");
153 180
 		init();
154
-		
181
+
155 182
 		if (mainLoop == null) {
156 183
 			throw new IllegalStateException("The app has no main loop assigned.");
157 184
 		}
158
-		
185
+
159 186
 		Log.i("Starting main loop...");
160 187
 		mainLoop.setRootRenderable(mainRenderable);
161 188
 		mainLoop.start();
162 189
 	}
163
-	
164
-	
190
+
191
+
165 192
 	private void init()
166 193
 	{
167
-
194
+		
168 195
 		if (inited) {
169 196
 			throw new IllegalStateException("Already inited.");
170 197
 		}
171 198
 		inited = true;
172
-		
199
+
173 200
 		// pre-init hook, just in case anyone wanted to have one.
174 201
 		Log.f2("Calling pre-init hook...");
175 202
 		preInit();
176
-		
203
+
177 204
 		Log.f2("Running init tasks...");
205
+
206
+		// sort initializers based on dependencies
207
+		final List<InitTask> orderedInitializers = initTasks.getSequence();
178 208
 		
179
-		// sort initializers by order.
180
-		final List<InitTask> orderedInitializers = InitTask.inOrder(initializers);
181
-		
209
+		// detailed logging
210
+		Log.f3("=== Task overview ===");
211
+		for (final InitTask t : orderedInitializers) {
212
+			Log.f3("Task " + Str.pad(t.getName(), 20) + " class = " + Str.pad(Str.val(t), 30) + " prio = " + Str.pad("" + t.getPriority(), 12) + " deps = "
213
+					+ Arrays.toString(t.getDependencies()));
214
+		}
215
+
182 216
 		for (final InitTask initTask : orderedInitializers) {
183 217
 			Log.f1("Running init task \"" + initTask.getName() + "\"...");
184
-			
218
+
185 219
 			initTask.bind(this);
186
-			
220
+
187 221
 			// set the task options
188 222
 			initTask.init();
189
-			
223
+
190 224
 			initTask.before();
191
-			
225
+
192 226
 			// main task action
193 227
 			initTask.run();
194
-			
228
+
195 229
 			// after hook for extra actions immeditaely after the task completes
196 230
 			initTask.after();
197 231
 		}
198
-		
232
+
199 233
 		// user can now start the main loop etc.
200 234
 		Log.f2("Calling post-init hook...");
201 235
 		postInit();
202 236
 	}
203
-	
204
-	
237
+
238
+
205 239
 	/**
206 240
 	 * Hook called before the initialization sequence starts.
207 241
 	 */
@@ -209,8 +243,8 @@ public class App extends BusNode {
209 243
 	protected void preInit()
210 244
 	{
211 245
 	}
212
-	
213
-	
246
+
247
+
214 248
 	/**
215 249
 	 * Hook called after the initialization sequence is finished.
216 250
 	 */
@@ -218,44 +252,60 @@ public class App extends BusNode {
218 252
 	protected void postInit()
219 253
 	{
220 254
 	}
221
-	
222
-	
255
+
256
+
257
+	/**
258
+	 * Shut down the running instance.<br>
259
+	 * Deinitialize backend modules and terminate the JVM.
260
+	 */
261
+	public static void requestShutdown()
262
+	{
263
+		if (instance == null) {
264
+			Log.w("App is not running.");
265
+			System.exit(0);
266
+		}
267
+
268
+		Log.i("Sending a shutdown request...");
269
+		bus().send(new ShutdownRequest());
270
+	}
271
+
272
+
223 273
 	/**
224 274
 	 * Shut down the running instance.<br>
225 275
 	 * Deinitialize backend modules and terminate the JVM.
226 276
 	 */
227 277
 	public static void shutdown()
228 278
 	{
229
-		if (instance != null) {
230
-			Log.i("Dispatching Shutdown event...");
231
-			
232
-			bus().send(new ShutdownEvent(new Runnable() {
233
-				
234
-				@Override
235
-				public void run()
236
-				{
237
-					try {
238
-						final EventBus bus = bus();
239
-						if (bus != null) {
240
-							bus.send(new DestroyEvent());
241
-							bus.destroy();
242
-						}
243
-					} catch (final Throwable e) {
244
-						Log.e(e);
245
-					}
246
-					
247
-					Log.i("Shutdown completed.");
248
-					System.exit(0);
249
-				}
250
-			}));
251
-			
252
-		} else {
279
+		if (instance == null) {
253 280
 			Log.w("App is not running.");
254 281
 			System.exit(0);
255 282
 		}
283
+		
284
+		// It's safer to shutdown in rendering context
285
+		// (LWJGL backend has problems otherwise)
286
+		
287
+		App.bus().send(new MainLoopRequest(new Runnable() {
288
+
289
+			@Override
290
+			public void run()
291
+			{
292
+				try {
293
+					final EventBus bus = bus();
294
+					if (bus != null) {
295
+						bus.send(new DestroyEvent());
296
+					}
297
+				} catch (final Throwable e) {
298
+					Log.e(e);
299
+				}
300
+			}
301
+		}, true));
302
+		
303
+		
304
+		Log.i("Shutdown completed.");
305
+		System.exit(0);
256 306
 	}
257
-	
258
-	
307
+
308
+
259 309
 	/**
260 310
 	 * Get the currently running App instance.
261 311
 	 *
@@ -265,8 +315,8 @@ public class App extends BusNode {
265 315
 	{
266 316
 		return instance;
267 317
 	}
268
-	
269
-	
318
+
319
+
270 320
 	/**
271 321
 	 * Get graphics module from the running app's backend
272 322
 	 *
@@ -276,8 +326,8 @@ public class App extends BusNode {
276 326
 	{
277 327
 		return instance.backend.getGraphics();
278 328
 	}
279
-	
280
-	
329
+
330
+
281 331
 	/**
282 332
 	 * Get audio module from the running app's backend
283 333
 	 *
@@ -287,8 +337,8 @@ public class App extends BusNode {
287 337
 	{
288 338
 		return instance.backend.getAudio();
289 339
 	}
290
-	
291
-	
340
+
341
+
292 342
 	/**
293 343
 	 * Get input module from the running app's backend
294 344
 	 *
@@ -298,8 +348,8 @@ public class App extends BusNode {
298 348
 	{
299 349
 		return instance.backend.getInput();
300 350
 	}
301
-	
302
-	
351
+
352
+
303 353
 	/**
304 354
 	 * Get event bus instance.
305 355
 	 *
@@ -309,8 +359,8 @@ public class App extends BusNode {
309 359
 	{
310 360
 		return instance.eventBus;
311 361
 	}
312
-	
313
-	
362
+
363
+
314 364
 	/**
315 365
 	 * Get the main config, if initialized.
316 366
 	 *
@@ -321,8 +371,8 @@ public class App extends BusNode {
321 371
 	{
322 372
 		return cfg("main");
323 373
 	}
324
-	
325
-	
374
+
375
+
326 376
 	/**
327 377
 	 * Get a config by alias.
328 378
 	 *

+ 26 - 10
src/mightypork/gamecore/core/AppBackend.java View File

@@ -2,8 +2,10 @@ package mightypork.gamecore.core;
2 2
 
3 3
 
4 4
 import mightypork.gamecore.audio.AudioModule;
5
+import mightypork.gamecore.core.init.InitTaskBackend;
5 6
 import mightypork.gamecore.graphics.GraphicsModule;
6 7
 import mightypork.gamecore.input.InputModule;
8
+import mightypork.utils.annotations.Stub;
7 9
 import mightypork.utils.eventbus.clients.BusNode;
8 10
 
9 11
 
@@ -11,16 +13,17 @@ import mightypork.utils.eventbus.clients.BusNode;
11 13
  * Application backend interface (set of core modules).<br>
12 14
  * The goal of this abstraction is to allow easy migration to different
13 15
  * environment with different libraries etc. It should be as simple as using
14
- * different backend.
16
+ * different backend.<br>
17
+ * The backend is initialized using {@link InitTaskBackend}.
15 18
  *
16 19
  * @author MightyPork
17 20
  */
18 21
 public abstract class AppBackend extends BusNode {
19
-
22
+	
20 23
 	/** App instance assigned using <code>bind()</code> */
21 24
 	protected App app;
22
-
23
-
25
+	
26
+	
24 27
 	/**
25 28
 	 * Assign the initialized app instance to an "app" field.
26 29
 	 *
@@ -36,27 +39,40 @@ public abstract class AppBackend extends BusNode {
36 39
 
37 40
 
38 41
 	/**
42
+	 * Add backend-specific init tasks or init task configurations.<br>
43
+	 * This is run after default init tasks have been added, and before the init
44
+	 * sequence is started.<br>
45
+	 * The backend is already binded to the app.
46
+	 */
47
+	@Stub
48
+	public void addInitTasks()
49
+	{
50
+		//
51
+	}
52
+	
53
+	
54
+	/**
39 55
 	 * Initialize backend modules, add them to event bus.
40 56
 	 */
41 57
 	public abstract void initialize();
42
-
43
-
58
+	
59
+	
44 60
 	/**
45 61
 	 * Get graphics module (screen manager, texture and font loader, renderer)
46 62
 	 *
47 63
 	 * @return graphics module
48 64
 	 */
49 65
 	public abstract GraphicsModule getGraphics();
50
-
51
-
66
+	
67
+	
52 68
 	/**
53 69
 	 * Get audio module (
54 70
 	 *
55 71
 	 * @return audio module
56 72
 	 */
57 73
 	public abstract AudioModule getAudio();
58
-
59
-
74
+	
75
+	
60 76
 	/**
61 77
 	 * Get input module
62 78
 	 *

+ 3 - 3
src/mightypork/gamecore/core/BackendModule.java View File

@@ -12,7 +12,7 @@ import mightypork.utils.interfaces.Destroyable;
12 12
  * @author MightyPork
13 13
  */
14 14
 public abstract class BackendModule extends BusNode implements Destroyable {
15
-	
15
+
16 16
 	/**
17 17
 	 * Initialize the backend module.<br>
18 18
 	 * Any initialization that would normally be done in constructor shall be
@@ -20,8 +20,8 @@ public abstract class BackendModule extends BusNode implements Destroyable {
20 20
 	 * "call to overridable method from constructor"
21 21
 	 */
22 22
 	public abstract void init();
23
-	
24
-	
23
+
24
+
25 25
 	@Override
26 26
 	@Stub
27 27
 	public void destroy()

src/mightypork/gamecore/core/DeltaMainLoop.java → src/mightypork/gamecore/core/BasicMainLoop.java View File

@@ -18,76 +18,79 @@ import mightypork.utils.math.timing.TimerDelta;
18 18
  *
19 19
  * @author Ondřej Hruška (MightyPork)
20 20
  */
21
-public class DeltaMainLoop extends BusNode implements MainLoop {
22
-	
21
+public class BasicMainLoop extends BusNode implements MainLoop {
22
+
23 23
 	/**
24 24
 	 * Max time spent on main loop tasks per cycle (s)
25 25
 	 */
26 26
 	protected double MAX_TIME_TASKS = 1 / 30D;
27
-	
27
+
28 28
 	/**
29 29
 	 * Max delta time (s) per frame.<br>
30 30
 	 * If delta is larger than this, it's clamped to it.
31 31
 	 */
32 32
 	protected double MAX_DELTA = 1 / 20D;
33
-	
33
+
34 34
 	private final Deque<Runnable> tasks = new ConcurrentLinkedDeque<>();
35 35
 	private TimerDelta timer;
36 36
 	private Renderable rootRenderable;
37 37
 	private volatile boolean running = true;
38
-	
39
-	
38
+
39
+
40 40
 	@Override
41 41
 	public void setRootRenderable(Renderable rootRenderable)
42 42
 	{
43 43
 		this.rootRenderable = rootRenderable;
44 44
 	}
45
-	
46
-	
45
+
46
+
47 47
 	@Override
48 48
 	public void start()
49 49
 	{
50 50
 		timer = new TimerDelta();
51
-		
51
+
52 52
 		while (running) {
53 53
 			App.gfx().beginFrame();
54
-			
54
+
55 55
 			double delta = timer.getDelta();
56 56
 			if (delta > MAX_DELTA) {
57 57
 				Log.f3("(timing) Clamping delta: was " + delta + " s, MAX_DELTA = " + MAX_DELTA + " s");
58 58
 				delta = MAX_DELTA;
59 59
 			}
60
-			
60
+
61 61
 			// dispatch update event
62 62
 			App.bus().sendDirect(new UpdateEvent(delta));
63
-			
63
+
64 64
 			// run main loop tasks
65 65
 			Runnable r;
66 66
 			final long t = Profiler.begin();
67
-			
67
+
68 68
 			while ((r = tasks.poll()) != null) {
69 69
 				Log.f3(" * Main loop task.");
70 70
 				r.run();
71
-				
71
+
72 72
 				if (Profiler.end(t) > MAX_TIME_TASKS) {
73 73
 					Log.f3("! Time's up, postponing task to next cycle.");
74 74
 					break;
75 75
 				}
76 76
 			}
77
-			
77
+
78
+			// halt if tasks terminated the app.
79
+			if (!running) break;
80
+
78 81
 			beforeRender();
79
-			
82
+
80 83
 			if (rootRenderable != null) {
81 84
 				rootRenderable.render();
82 85
 			}
83
-			
86
+
84 87
 			afterRender();
85
-			
88
+
86 89
 			App.gfx().endFrame();
87 90
 		}
88 91
 	}
89
-	
90
-	
92
+
93
+
91 94
 	/**
92 95
 	 * Called before render
93 96
 	 */
@@ -96,8 +99,8 @@ public class DeltaMainLoop extends BusNode implements MainLoop {
96 99
 	{
97 100
 		//
98 101
 	}
99
-	
100
-	
102
+
103
+
101 104
 	/**
102 105
 	 * Called after render
103 106
 	 */
@@ -106,15 +109,15 @@ public class DeltaMainLoop extends BusNode implements MainLoop {
106 109
 	{
107 110
 		//
108 111
 	}
109
-	
110
-	
112
+
113
+
111 114
 	@Override
112 115
 	public void destroy()
113 116
 	{
114 117
 		running = false;
115 118
 	}
116
-	
117
-	
119
+
120
+
118 121
 	@Override
119 122
 	public synchronized void queueTask(Runnable task, boolean skipQueue)
120 123
 	{
@@ -124,5 +127,5 @@ public class DeltaMainLoop extends BusNode implements MainLoop {
124 127
 			tasks.addLast(task);
125 128
 		}
126 129
 	}
127
-	
130
+
128 131
 }

+ 8 - 8
src/mightypork/gamecore/core/MainLoop.java View File

@@ -12,7 +12,7 @@ import mightypork.utils.interfaces.Destroyable;
12 12
  * @author Ondřej Hruška (MightyPork)
13 13
  */
14 14
 public interface MainLoop extends Destroyable {
15
-	
15
+
16 16
 	/**
17 17
 	 * Set primary renderable
18 18
 	 *
@@ -20,19 +20,19 @@ public interface MainLoop extends Destroyable {
20 20
 	 *            {@link ScreenRegistry}
21 21
 	 */
22 22
 	public abstract void setRootRenderable(Renderable rootRenderable);
23
-	
24
-	
23
+
24
+
25 25
 	/**
26 26
 	 * Start the loop. The loop should be terminated when the destroy() method
27 27
 	 * is called.
28 28
 	 */
29 29
 	public abstract void start();
30
-	
31
-	
30
+
31
+
32 32
 	@Override
33 33
 	public abstract void destroy();
34
-	
35
-	
34
+
35
+
36 36
 	/**
37 37
 	 * Add a task to queue to be executed in the main loop (in rendering
38 38
 	 * context). This may be eg. loading textures.
@@ -41,5 +41,5 @@ public interface MainLoop extends Destroyable {
41 41
 	 * @param skipQueue true to skip the queue
42 42
 	 */
43 43
 	public abstract void queueTask(Runnable task, boolean skipQueue);
44
-	
44
+
45 45
 }

+ 50 - 50
src/mightypork/gamecore/core/config/Config.java View File

@@ -4,8 +4,8 @@ package mightypork.gamecore.core.config;
4 4
 import java.util.HashMap;
5 5
 import java.util.Map;
6 6
 
7
-import mightypork.gamecore.core.events.ShutdownEvent;
8
-import mightypork.gamecore.core.events.ShutdownListener;
7
+import mightypork.gamecore.core.events.ShutdownRequest;
8
+import mightypork.gamecore.core.events.ShutdownRequestListener;
9 9
 import mightypork.gamecore.input.Key;
10 10
 import mightypork.gamecore.input.KeyStroke;
11 11
 import mightypork.utils.config.propmgr.Property;
@@ -21,16 +21,16 @@ import mightypork.utils.logging.Log;
21 21
  *
22 22
  * @author Ondřej Hruška (MightyPork)
23 23
  */
24
-public class Config implements ShutdownListener {
25
-
24
+public class Config implements ShutdownRequestListener {
25
+	
26 26
 	/** Array of configs registered for the app */
27 27
 	protected static Map<String, Config> configs = new HashMap<>();
28
-
28
+	
29 29
 	private final Map<String, KeyStrokeProperty> strokes = new HashMap<>();
30
-
30
+	
31 31
 	private final PropertyManager propertyManager;
32
-
33
-
32
+	
33
+	
34 34
 	/**
35 35
 	 * Get a config from the static map, by given alias
36 36
 	 *
@@ -40,15 +40,15 @@ public class Config implements ShutdownListener {
40 40
 	public static Config forAlias(String alias)
41 41
 	{
42 42
 		final Config c = configs.get(alias);
43
-
43
+		
44 44
 		if (c == null) {
45 45
 			throw new IllegalArgumentException("There is no config with alias \"" + alias + "\"");
46 46
 		}
47
-
47
+		
48 48
 		return c;
49 49
 	}
50
-
51
-
50
+	
51
+	
52 52
 	/**
53 53
 	 * Register a config by alias.
54 54
 	 *
@@ -60,11 +60,11 @@ public class Config implements ShutdownListener {
60 60
 		if (configs.get(alias) != null) {
61 61
 			throw new IllegalArgumentException("The alias \"" + alias + "\" is already used.");
62 62
 		}
63
-
63
+		
64 64
 		configs.put(alias, config);
65 65
 	}
66
-
67
-
66
+	
67
+	
68 68
 	/**
69 69
 	 * Initialize property manager for a file
70 70
 	 *
@@ -75,8 +75,8 @@ public class Config implements ShutdownListener {
75 75
 	{
76 76
 		this(new PropertyFile(WorkDir.getFile(file), headComment));
77 77
 	}
78
-
79
-
78
+	
79
+	
80 80
 	/**
81 81
 	 * Initialize property manager for a given store
82 82
 	 *
@@ -86,8 +86,8 @@ public class Config implements ShutdownListener {
86 86
 	{
87 87
 		propertyManager = new PropertyManager(store);
88 88
 	}
89
-
90
-
89
+	
90
+	
91 91
 	/**
92 92
 	 * Add a keystroke property
93 93
 	 *
@@ -101,8 +101,8 @@ public class Config implements ShutdownListener {
101 101
 		strokes.put(prefixKeyStroke(key), kprop);
102 102
 		propertyManager.addProperty(kprop);
103 103
 	}
104
-
105
-
104
+	
105
+	
106 106
 	/**
107 107
 	 * Add a boolean property (flag)
108 108
 	 *
@@ -114,8 +114,8 @@ public class Config implements ShutdownListener {
114 114
 	{
115 115
 		propertyManager.addBoolean(key, defval, comment);
116 116
 	}
117
-
118
-
117
+	
118
+	
119 119
 	/**
120 120
 	 * Add an integer property
121 121
 	 *
@@ -127,8 +127,8 @@ public class Config implements ShutdownListener {
127 127
 	{
128 128
 		propertyManager.addInteger(key, defval, comment);
129 129
 	}
130
-
131
-
130
+	
131
+	
132 132
 	/**
133 133
 	 * Add a double property
134 134
 	 *
@@ -140,8 +140,8 @@ public class Config implements ShutdownListener {
140 140
 	{
141 141
 		propertyManager.addDouble(key, defval, comment);
142 142
 	}
143
-
144
-
143
+	
144
+	
145 145
 	/**
146 146
 	 * Add a string property
147 147
 	 *
@@ -153,8 +153,8 @@ public class Config implements ShutdownListener {
153 153
 	{
154 154
 		propertyManager.addString(key, defval, comment);
155 155
 	}
156
-
157
-
156
+	
157
+	
158 158
 	/**
159 159
 	 * Add an arbitrary property (can be custom type)
160 160
 	 *
@@ -164,8 +164,8 @@ public class Config implements ShutdownListener {
164 164
 	{
165 165
 		propertyManager.addProperty(prop);
166 166
 	}
167
-
168
-
167
+	
168
+	
169 169
 	/**
170 170
 	 * Load config from file
171 171
 	 */
@@ -173,8 +173,8 @@ public class Config implements ShutdownListener {
173 173
 	{
174 174
 		propertyManager.load();
175 175
 	}
176
-
177
-
176
+	
177
+	
178 178
 	/**
179 179
 	 * Save config to file
180 180
 	 */
@@ -183,8 +183,8 @@ public class Config implements ShutdownListener {
183 183
 		Log.f3("Saving config.");
184 184
 		propertyManager.save();
185 185
 	}
186
-
187
-
186
+	
187
+	
188 188
 	/**
189 189
 	 * Get an option for key
190 190
 	 *
@@ -197,14 +197,14 @@ public class Config implements ShutdownListener {
197 197
 			if (propertyManager.getProperty(key) == null) {
198 198
 				throw new IllegalArgumentException("No such property: " + key);
199 199
 			}
200
-
200
+			
201 201
 			return propertyManager.getValue(key);
202 202
 		} catch (final ClassCastException cce) {
203 203
 			throw new RuntimeException("Property of incompatible type: " + key);
204 204
 		}
205 205
 	}
206
-
207
-
206
+	
207
+	
208 208
 	/**
209 209
 	 * Set option to a value. Call the save() method to make the change
210 210
 	 * permanent.
@@ -217,11 +217,11 @@ public class Config implements ShutdownListener {
217 217
 		if (propertyManager.getProperty(key) == null) {
218 218
 			throw new IllegalArgumentException("No such property: " + key);
219 219
 		}
220
-
220
+		
221 221
 		propertyManager.setValue(key, value);
222 222
 	}
223
-
224
-
223
+	
224
+	
225 225
 	/**
226 226
 	 * Add "key." before the given config file key
227 227
 	 *
@@ -232,8 +232,8 @@ public class Config implements ShutdownListener {
232 232
 	{
233 233
 		return "key." + cfgKey;
234 234
 	}
235
-
236
-
235
+	
236
+	
237 237
 	/**
238 238
 	 * Get keystroke for name
239 239
 	 *
@@ -246,11 +246,11 @@ public class Config implements ShutdownListener {
246 246
 		if (kp == null) {
247 247
 			throw new IllegalArgumentException("No such stroke: " + cfgKey);
248 248
 		}
249
-
249
+		
250 250
 		return kp.getValue();
251 251
 	}
252
-
253
-
252
+	
253
+	
254 254
 	/**
255 255
 	 * Set a keystroke for name
256 256
 	 *
@@ -264,13 +264,13 @@ public class Config implements ShutdownListener {
264 264
 		if (kp == null) {
265 265
 			throw new IllegalArgumentException("No such stroke: " + cfgKey);
266 266
 		}
267
-
267
+		
268 268
 		kp.getValue().setTo(key, mod);
269 269
 	}
270
-
271
-
270
+	
271
+	
272 272
 	@Override
273
-	public void onShutdown(ShutdownEvent event)
273
+	public void onShutdownRequested(ShutdownRequest event)
274 274
 	{
275 275
 		save(); // save changes done to the config
276 276
 	}

+ 9 - 9
src/mightypork/gamecore/core/config/KeyStrokeProperty.java View File

@@ -16,7 +16,7 @@ import mightypork.utils.config.propmgr.Property;
16 16
  * @author Ondřej Hruška (MightyPork)
17 17
  */
18 18
 public class KeyStrokeProperty extends Property<KeyStroke> {
19
-	
19
+
20 20
 	/**
21 21
 	 * Make a keystroke property
22 22
 	 *
@@ -28,32 +28,32 @@ public class KeyStrokeProperty extends Property<KeyStroke> {
28 28
 	{
29 29
 		super(key, defaultValue, comment);
30 30
 	}
31
-	
32
-	
31
+
32
+
33 33
 	@Override
34 34
 	public void fromString(String string)
35 35
 	{
36 36
 		if (string != null) {
37 37
 			// keep the same instance
38
-			
38
+
39 39
 			final Key backup_key = value.getKey();
40 40
 			final int backup_mod = value.getMod();
41
-			
41
+
42 42
 			value.loadFromString(string);
43 43
 			if (value.getKey() == Keys.NONE) {
44 44
 				value.setTo(backup_key, backup_mod);
45 45
 			}
46 46
 		}
47 47
 	}
48
-	
49
-	
48
+
49
+
50 50
 	@Override
51 51
 	public String toString()
52 52
 	{
53 53
 		return value.saveToString();
54 54
 	}
55
-	
56
-	
55
+
56
+
57 57
 	@Override
58 58
 	public void setValue(Object value)
59 59
 	{

+ 7 - 7
src/mightypork/gamecore/core/events/MainLoopRequest.java View File

@@ -13,11 +13,11 @@ import mightypork.utils.eventbus.events.flags.SingleReceiverEvent;
13 13
  */
14 14
 @SingleReceiverEvent
15 15
 public class MainLoopRequest extends BusEvent<MainLoop> {
16
-
16
+	
17 17
 	private final Runnable task;
18 18
 	private final boolean priority;
19
-
20
-
19
+	
20
+	
21 21
 	/**
22 22
 	 * @param task task to run on main thread in rendering context
23 23
 	 */
@@ -25,8 +25,8 @@ public class MainLoopRequest extends BusEvent<MainLoop> {
25 25
 	{
26 26
 		this(task, false);
27 27
 	}
28
-
29
-
28
+	
29
+	
30 30
 	/**
31 31
 	 * @param task task to run on main thread in rendering context
32 32
 	 * @param priority if true, skip other tasks in queue
@@ -36,8 +36,8 @@ public class MainLoopRequest extends BusEvent<MainLoop> {
36 36
 		this.task = task;
37 37
 		this.priority = priority;
38 38
 	}
39
-
40
-
39
+	
40
+	
41 41
 	@Override
42 42
 	public void handleBy(MainLoop handler)
43 43
 	{

src/mightypork/gamecore/core/events/ShutdownEvent.java → src/mightypork/gamecore/core/events/ShutdownRequest.java View File

@@ -15,26 +15,13 @@ import mightypork.utils.logging.Log;
15 15
  *
16 16
  * @author Ondřej Hruška (MightyPork)
17 17
  */
18
-public class ShutdownEvent extends BusEvent<ShutdownListener> {
19
-	
20
-	private final Runnable shutdownTask;
21
-	
22
-	
23
-	/**
24
-	 * Make a shutdown event
25
-	 *
26
-	 * @param doShutdown Task that does the actual shutdown
27
-	 */
28
-	public ShutdownEvent(Runnable doShutdown)
29
-	{
30
-		this.shutdownTask = doShutdown;
31
-	}
18
+public class ShutdownRequest extends BusEvent<ShutdownRequestListener> {
32 19
 	
33 20
 	
34 21
 	@Override
35
-	protected void handleBy(ShutdownListener handler)
22
+	protected void handleBy(ShutdownRequestListener handler)
36 23
 	{
37
-		handler.onShutdown(this);
24
+		handler.onShutdownRequested(this);
38 25
 	}
39 26
 	
40 27
 	
@@ -44,7 +31,7 @@ public class ShutdownEvent extends BusEvent<ShutdownListener> {
44 31
 		if (!isConsumed()) {
45 32
 			Log.i("Shutting down...");
46 33
 
47
-			App.bus().send(new MainLoopRequest(shutdownTask, true));
34
+			App.shutdown();
48 35
 
49 36
 		} else {
50 37
 			Log.i("Shutdown aborted.");

src/mightypork/gamecore/core/events/ShutdownListener.java → src/mightypork/gamecore/core/events/ShutdownRequestListener.java View File

@@ -6,13 +6,13 @@ package mightypork.gamecore.core.events;
6 6
  *
7 7
  * @author Ondřej Hruška (MightyPork)
8 8
  */
9
-public interface ShutdownListener {
9
+public interface ShutdownRequestListener {
10 10
 	
11 11
 	/**
12
-	 * Intercept quit request.<br>
13
-	 * Consume the event to abort shutdown (ie. ask user to save)
12
+	 * Intercept shutdown request.<br>
13
+	 * Consume the event to abort shutdown (ie. ask user to save).
14 14
 	 *
15 15
 	 * @param event quit request event.
16 16
 	 */
17
-	void onShutdown(ShutdownEvent event);
17
+	void onShutdownRequested(ShutdownRequest event);
18 18
 }

+ 168 - 0
src/mightypork/gamecore/core/init/InitSequence.java View File

@@ -0,0 +1,168 @@
1
+package mightypork.gamecore.core.init;
2
+
3
+
4
+import java.util.ArrayList;
5
+import java.util.Collection;
6
+import java.util.HashMap;
7
+import java.util.HashSet;
8
+import java.util.Iterator;
9
+import java.util.List;
10
+import java.util.Map;
11
+import java.util.Set;
12
+
13
+import mightypork.utils.Reflect;
14
+import mightypork.utils.logging.Log;
15
+
16
+
17
+/**
18
+ * initialization sequence that takes care of task dependencies and ordering.
19
+ *
20
+ * @author Ondřej Hruška (MightyPork)
21
+ */
22
+public class InitSequence {
23
+
24
+	private final Map<String, InitTask> taskMap = new HashMap<>();
25
+
26
+
27
+	/**
28
+	 * Add a task. If a task with the name already exists, replace it.
29
+	 *
30
+	 * @param task task to add
31
+	 */
32
+	public void addTask(InitTask task)
33
+	{
34
+		final String name = task.getName();
35
+		
36
+		// detailed logging
37
+//		if (taskMap.containsKey(name)) {
38
+//			Log.f3("REPL init " + Str.pad("\"" + name + "\"", 20) + " <" + Str.val(task) + ">");
39
+//		} else {
40
+//			Log.f3("ADD  init " + Str.pad("\"" + name + "\"", 20) + " <" + Str.val(task) + ">");
41
+//		}
42
+		
43
+		taskMap.put(name, task);
44
+	}
45
+	
46
+	
47
+	/**
48
+	 * Get task sequence in proper order.
49
+	 *
50
+	 * @return initialization sequence
51
+	 */
52
+	public List<InitTask> getSequence()
53
+	{
54
+		final List<InitTask> remainingTasks = new ArrayList<>(taskMap.values());
55
+
56
+		final List<InitTask> orderedTasks = new ArrayList<>();
57
+		final Set<String> loadedTaskNames = new HashSet<>();
58
+		
59
+		// resolve task order
60
+		InitTask taskToAdd = null;
61
+		do {
62
+			taskToAdd = null;
63
+			
64
+			for (final InitTask task : remainingTasks) {
65
+
66
+				String[] deps = task.getDependencies();
67
+				if (deps == null) deps = new String[] {};
68
+				
69
+				int missingDeps = deps.length;
70
+				
71
+				for (final String d : deps) {
72
+					if (loadedTaskNames.contains(d)) missingDeps--;
73
+				}
74
+				
75
+				if (missingDeps == 0) {
76
+					if (taskToAdd == null || taskToAdd.getPriority() < task.getPriority()) {
77
+						taskToAdd = task;
78
+					}
79
+				}
80
+			}
81
+
82
+			if (taskToAdd != null) {
83
+				orderedTasks.add(taskToAdd);
84
+				loadedTaskNames.add(taskToAdd.getName());
85
+				remainingTasks.remove(taskToAdd);
86
+			}
87
+
88
+		} while (taskToAdd != null);
89
+		
90
+		checkLeftovers(loadedTaskNames, remainingTasks);
91
+
92
+		return orderedTasks;
93
+	}
94
+	
95
+	
96
+	public List<InitTask> getSequenceOldImpl()
97
+	{
98
+		final List<InitTask> remainingTasks = new ArrayList<>(taskMap.values());
99
+
100
+		final List<InitTask> orderedTasks = new ArrayList<>();
101
+		final Set<String> loadedTaskNames = new HashSet<>();
102
+		
103
+		// resolve task order
104
+		int addedThisIteration = 0;
105
+		do {
106
+			addedThisIteration = 0;
107
+			for (final Iterator<InitTask> i = remainingTasks.iterator(); i.hasNext();) {
108
+				final InitTask task = i.next();
109
+				
110
+				String[] deps = task.getDependencies();
111
+				if (deps == null) deps = new String[] {};
112
+				
113
+				int missingDeps = deps.length;
114
+				
115
+				for (final String d : deps) {
116
+					if (loadedTaskNames.contains(d)) missingDeps--;
117
+				}
118
+				
119
+				if (missingDeps == 0) {
120
+					orderedTasks.add(task);
121
+					loadedTaskNames.add(task.getName());
122
+					i.remove();
123
+					addedThisIteration++;
124
+				}
125
+			}
126
+		} while (addedThisIteration > 0);
127
+		
128
+		checkLeftovers(loadedTaskNames, remainingTasks);
129
+
130
+		return orderedTasks;
131
+	}
132
+	
133
+	
134
+	private void checkLeftovers(Collection<String> loadedTaskNames, Collection<InitTask> remainingTasks)
135
+	{
136
+		// check if any tasks are left out
137
+		if (remainingTasks.size() > 0) {
138
+			
139
+			// build error message for each bad task
140
+			int badInitializers = 0;
141
+			for (final InitTask task : remainingTasks) {
142
+				
143
+				if (Reflect.hasAnnotation(task.getClass(), OptionalInitTask.class)) {
144
+					continue;
145
+				}
146
+				
147
+				badInitializers++;
148
+				
149
+				String notSatisfied = "";
150
+				
151
+				for (final String d : task.getDependencies()) {
152
+					if (!loadedTaskNames.contains(d)) {
153
+						
154
+						if (!notSatisfied.isEmpty()) {
155
+							notSatisfied += ", ";
156
+						}
157
+						
158
+						notSatisfied += d;
159
+					}
160
+				}
161
+				
162
+				Log.w("InitTask \"" + task.getName() + "\" - missing dependencies: " + notSatisfied);
163
+			}
164
+			
165
+			if (badInitializers > 0) throw new RuntimeException("Some InitTask dependencies could not be satisfied.");
166
+		}
167
+	}
168
+}

+ 29 - 92
src/mightypork/gamecore/core/init/InitTask.java View File

@@ -1,16 +1,8 @@
1 1
 package mightypork.gamecore.core.init;
2 2
 
3 3
 
4
-import java.util.ArrayList;
5
-import java.util.HashSet;
6
-import java.util.Iterator;
7
-import java.util.List;
8
-import java.util.Set;
9
-
10 4
 import mightypork.gamecore.core.App;
11
-import mightypork.utils.Reflect;
12 5
 import mightypork.utils.annotations.Stub;
13
-import mightypork.utils.logging.Log;
14 6
 
15 7
 
16 8
 /**
@@ -21,11 +13,17 @@ import mightypork.utils.logging.Log;
21 13
  * @author Ondřej Hruška (MightyPork)
22 14
  */
23 15
 public abstract class InitTask {
24
-
25
-	/** App instance assigned using <code>bind()</code> */
26
-	protected App app;
27 16
 	
17
+	protected static final int PRIO_FIRST = Integer.MAX_VALUE;
18
+	protected static final int PRIO_EARLY = 9000;
19
+	protected static final int PRIO_DEFAULT = 0;
20
+	protected static final int PRIO_LATE = -9000;
21
+	protected static final int PRIO_LAST = Integer.MIN_VALUE;
28 22
 	
23
+	/** App instance assigned using <code>bind()</code> */
24
+	protected App app;
25
+
26
+
29 27
 	/**
30 28
 	 * Assign the initialized app instance to an "app" field.
31 29
 	 *
@@ -35,8 +33,8 @@ public abstract class InitTask {
35 33
 	{
36 34
 		this.app = app;
37 35
 	}
38
-	
39
-	
36
+
37
+
40 38
 	/**
41 39
 	 * An init method that is called before the <code>run()</code> method.<br>
42 40
 	 * This method should be left unimplemented in the task, and can be used to
@@ -47,8 +45,8 @@ public abstract class InitTask {
47 45
 	{
48 46
 		//
49 47
 	}
50
-	
51
-	
48
+
49
+
52 50
 	/**
53 51
 	 * Hook for extra action before the main task action.<br>
54 52
 	 * Can be overridden during app configuration to "bake-in" extra actions.
@@ -58,14 +56,14 @@ public abstract class InitTask {
58 56
 	{
59 57
 		//
60 58
 	}
61
-	
62
-	
59
+
60
+
63 61
 	/**
64 62
 	 * Run the initializer on app.
65 63
 	 */
66 64
 	public abstract void run();
67
-	
68
-	
65
+
66
+
69 67
 	/**
70 68
 	 * Hook executed after the "run()" method.<br>
71 69
 	 * Can be overridden during app configuration to "bake-in" extra actions.
@@ -75,8 +73,8 @@ public abstract class InitTask {
75 73
 	{
76 74
 		//
77 75
 	}
78
-	
79
-	
76
+
77
+
80 78
 	/**
81 79
 	 * Get name of this initializer (for dependency resolver).<br>
82 80
 	 * The name should be short, snake_case and precise.
@@ -84,8 +82,8 @@ public abstract class InitTask {
84 82
 	 * @return name
85 83
 	 */
86 84
 	public abstract String getName();
87
-	
88
-	
85
+
86
+
89 87
 	/**
90 88
 	 * Get what other initializers must be already loaded before this can load.<br>
91 89
 	 * Depending on itself or creating a circular dependency will cause error.<br>
@@ -99,78 +97,17 @@ public abstract class InitTask {
99 97
 	{
100 98
 		return new String[] {};
101 99
 	}
102
-	
103
-	
100
+
101
+
104 102
 	/**
105
-	 * Order init tasks so that all dependencies are loaded before thye are
106
-	 * needed by the tasks.
103
+	 * Get priority in the init sequence. Tasks with higher priority are loaded
104
+	 * earlier (but only after their dependencies are loaded).
107 105
 	 *
108
-	 * @param tasks task list
109
-	 * @return task list ordered
106
+	 * @return priority, higher = runs earlier
110 107
 	 */
111
-	public static List<InitTask> inOrder(List<InitTask> tasks)
108
+	@Stub
109
+	public int getPriority()
112 110
 	{
113
-		final List<InitTask> remaining = new ArrayList<>(tasks);
114
-		
115
-		final List<InitTask> ordered = new ArrayList<>();
116
-		final Set<String> loaded = new HashSet<>();
117
-		
118
-		// resolve task order
119
-		int addedThisIteration = 0;
120
-		do {
121
-			addedThisIteration = 0;
122
-			for (final Iterator<InitTask> i = remaining.iterator(); i.hasNext();) {
123
-				final InitTask task = i.next();
124
-				
125
-				String[] deps = task.getDependencies();
126
-				if (deps == null) deps = new String[] {};
127
-				
128
-				int unmetDepsCount = deps.length;
129
-				
130
-				for (final String d : deps) {
131
-					if (loaded.contains(d)) unmetDepsCount--;
132
-				}
133
-				
134
-				if (unmetDepsCount == 0) {
135
-					ordered.add(task);
136
-					loaded.add(task.getName());
137
-					i.remove();
138
-					addedThisIteration++;
139
-				}
140
-			}
141
-		} while (addedThisIteration > 0);
142
-		
143
-		// check if any tasks are left out
144
-		if (remaining.size() > 0) {
145
-			
146
-			// build error message for each bad task
147
-			int badInitializers = 0;
148
-			for (final InitTask task : remaining) {
149
-				if (Reflect.hasAnnotation(task.getClass(), OptionalInitTask.class)) {
150
-					continue;
151
-				}
152
-				
153
-				badInitializers++;
154
-				
155
-				String notSatisfied = "";
156
-				
157
-				for (final String d : task.getDependencies()) {
158
-					if (!loaded.contains(d)) {
159
-						
160
-						if (!notSatisfied.isEmpty()) {
161
-							notSatisfied += ", ";
162
-						}
163
-						
164
-						notSatisfied += d;
165
-					}
166
-				}
167
-				
168
-				Log.w("InitTask \"" + task.getName() + "\" - missing dependencies: " + notSatisfied);
169
-			}
170
-			
171
-			if (badInitializers > 0) throw new RuntimeException("Some InitTask dependencies could not be satisfied.");
172
-		}
173
-		
174
-		return ordered;
111
+		return PRIO_DEFAULT;
175 112
 	}
176 113
 }

+ 41 - 0
src/mightypork/gamecore/core/init/InitTaskBackend.java View File

@@ -0,0 +1,41 @@
1
+package mightypork.gamecore.core.init;
2
+
3
+
4
+import mightypork.gamecore.core.App;
5
+
6
+
7
+/**
8
+ * Initialize backend. The main point of postponing this is to make sure the
9
+ * init is logged properly.
10
+ *
11
+ * @author Ondřej Hruška (MightyPork)
12
+ */
13
+public class InitTaskBackend extends InitTask {
14
+	
15
+	@Override
16
+	public void run()
17
+	{
18
+		App.instance().getBackend().initialize();
19
+	}
20
+	
21
+	
22
+	@Override
23
+	public String getName()
24
+	{
25
+		return "backend";
26
+	}
27
+
28
+
29
+	@Override
30
+	public String[] getDependencies()
31
+	{
32
+		return new String[] { "log" };
33
+	}
34
+
35
+
36
+	@Override
37
+	public int getPriority()
38
+	{
39
+		return PRIO_EARLY;
40
+	}
41
+}

src/mightypork/gamecore/core/config/InitTaskConfig.java → src/mightypork/gamecore/core/init/InitTaskConfig.java View File

@@ -1,7 +1,7 @@
1
-package mightypork.gamecore.core.config;
1
+package mightypork.gamecore.core.init;
2 2
 
3 3
 
4
-import mightypork.gamecore.core.init.InitTask;
4
+import mightypork.gamecore.core.config.Config;
5 5
 import mightypork.utils.annotations.Stub;
6 6
 
7 7
 
@@ -72,4 +72,11 @@ public abstract class InitTaskConfig extends InitTask {
72 72
 		return new String[] { "workdir" };
73 73
 	}
74 74
 	
75
+	
76
+	@Override
77
+	public int getPriority()
78
+	{
79
+		return PRIO_FIRST;
80
+	}
81
+	
75 82
 }

+ 12 - 5
src/mightypork/gamecore/core/init/InitTaskCrashHandler.java View File

@@ -16,14 +16,14 @@ import mightypork.utils.logging.Log;
16 16
  * @author Ondřej Hruška (MightyPork)
17 17
  */
18 18
 public class InitTaskCrashHandler extends InitTask implements UncaughtExceptionHandler {
19
-	
19
+
20 20
 	@Override
21 21
 	public void run()
22 22
 	{
23 23
 		Thread.setDefaultUncaughtExceptionHandler(this);
24 24
 	}
25
-	
26
-	
25
+
26
+
27 27
 	@Override
28 28
 	@Stub
29 29
 	public void uncaughtException(Thread thread, Throwable throwable)
@@ -31,11 +31,18 @@ public class InitTaskCrashHandler extends InitTask implements UncaughtExceptionH
31 31
 		Log.e("The game has crashed.", throwable);
32 32
 		App.shutdown();
33 33
 	}
34
-	
35
-	
34
+
35
+
36 36
 	@Override
37 37
 	public String getName()
38 38
 	{
39 39
 		return "crash_handler";
40 40
 	}
41
+	
42
+	
43
+	@Override
44
+	public int getPriority()
45
+	{
46
+		return PRIO_FIRST;
47
+	}
41 48
 }

+ 12 - 12
src/mightypork/gamecore/core/init/InitTaskCustom.java View File

@@ -8,39 +8,39 @@ package mightypork.gamecore.core.init;
8 8
  * @author Ondřej Hruška (MightyPork)
9 9
  */
10 10
 public abstract class InitTaskCustom extends InitTask {
11
-	
11
+
12 12
 	private final String name;
13 13
 	private final String[] deps;
14
-	
15
-	
14
+
15
+
16 16
 	public InitTaskCustom(String name)
17 17
 	{
18 18
 		this(name, null);
19 19
 	}
20
-	
21
-	
20
+
21
+
22 22
 	public InitTaskCustom(String name, String[] dependencies)
23 23
 	{
24 24
 		this.name = name;
25 25
 		this.deps = dependencies;
26 26
 	}
27
-	
28
-	
27
+
28
+
29 29
 	@Override
30 30
 	public abstract void run();