improved initializer resolver

master
Ondřej Hruška 10 years ago
parent 2398a4ee6a
commit 8e9a658098
  1. 92
      src/mightypork/gamecore/core/App.java
  2. 18
      src/mightypork/gamecore/core/AppBackend.java
  3. 5
      src/mightypork/gamecore/core/BasicMainLoop.java
  4. 8
      src/mightypork/gamecore/core/config/Config.java
  5. 21
      src/mightypork/gamecore/core/events/ShutdownRequest.java
  6. 8
      src/mightypork/gamecore/core/events/ShutdownRequestListener.java
  7. 168
      src/mightypork/gamecore/core/init/InitSequence.java
  8. 87
      src/mightypork/gamecore/core/init/InitTask.java
  9. 41
      src/mightypork/gamecore/core/init/InitTaskBackend.java
  10. 11
      src/mightypork/gamecore/core/init/InitTaskConfig.java
  11. 7
      src/mightypork/gamecore/core/init/InitTaskCrashHandler.java
  12. 2
      src/mightypork/gamecore/core/init/InitTaskDisplay.java
  13. 13
      src/mightypork/gamecore/core/init/InitTaskIonizables.java
  14. 16
      src/mightypork/gamecore/core/init/InitTaskLog.java
  15. 7
      src/mightypork/gamecore/core/init/InitTaskLogHeader.java
  16. 24
      src/mightypork/gamecore/core/init/InitTaskMainLoop.java
  17. 1
      src/mightypork/gamecore/core/init/InitTaskResourceLoader.java
  18. 9
      src/mightypork/gamecore/core/init/InitTaskResourceLoaderAsync.java
  19. 4
      src/mightypork/gamecore/core/init/InitTaskResourceLoaderNone.java
  20. 4
      src/mightypork/gamecore/core/init/InitTaskResources.java
  21. 42
      src/mightypork/gamecore/core/init/InitTaskScreens.java
  22. 51
      src/mightypork/gamecore/core/init/InitTaskUI.java
  23. 7
      src/mightypork/gamecore/core/init/InitTaskWorkdir.java
  24. 4
      src/mightypork/gamecore/gui/components/BaseComponent.java
  25. 6
      src/mightypork/gamecore/input/KeyStroke.java
  26. 4
      src/mightypork/gamecore/resources/BaseDeferredResource.java
  27. 7
      src/mightypork/gamecore/resources/loading/AsyncResourceLoader.java

@ -1,17 +1,29 @@
package mightypork.gamecore.core; package mightypork.gamecore.core;
import java.util.ArrayList; import java.io.File;
import java.util.Arrays;
import java.util.List; import java.util.List;
import mightypork.gamecore.audio.AudioModule; import mightypork.gamecore.audio.AudioModule;
import mightypork.gamecore.core.config.Config; import mightypork.gamecore.core.config.Config;
import mightypork.gamecore.core.events.ShutdownEvent; import mightypork.gamecore.core.events.MainLoopRequest;
import mightypork.gamecore.core.events.ShutdownRequest;
import mightypork.gamecore.core.init.InitSequence;
import mightypork.gamecore.core.init.InitTask; import mightypork.gamecore.core.init.InitTask;
import mightypork.gamecore.core.init.InitTaskBackend;
import mightypork.gamecore.core.init.InitTaskCrashHandler;
import mightypork.gamecore.core.init.InitTaskIonizables;
import mightypork.gamecore.core.init.InitTaskLog;
import mightypork.gamecore.core.init.InitTaskLogHeader;
import mightypork.gamecore.core.init.InitTaskMainLoop;
import mightypork.gamecore.core.init.InitTaskResourceLoaderAsync;
import mightypork.gamecore.core.init.InitTaskWorkdir;
import mightypork.gamecore.core.plugins.AppPlugin; import mightypork.gamecore.core.plugins.AppPlugin;
import mightypork.gamecore.graphics.GraphicsModule; import mightypork.gamecore.graphics.GraphicsModule;
import mightypork.gamecore.graphics.Renderable; import mightypork.gamecore.graphics.Renderable;
import mightypork.gamecore.input.InputModule; import mightypork.gamecore.input.InputModule;
import mightypork.utils.Str;
import mightypork.utils.annotations.Stub; import mightypork.utils.annotations.Stub;
import mightypork.utils.eventbus.EventBus; import mightypork.utils.eventbus.EventBus;
import mightypork.utils.eventbus.clients.BusNode; import mightypork.utils.eventbus.clients.BusNode;
@ -37,7 +49,7 @@ public class App extends BusNode {
/** List of installed App plugins */ /** List of installed App plugins */
protected final DelegatingList plugins = new DelegatingList(); protected final DelegatingList plugins = new DelegatingList();
/** List of initializers */ /** List of initializers */
protected final List<InitTask> initializers = new ArrayList<>(); protected final InitSequence initTasks = new InitSequence();
/** The used main loop instance */ /** The used main loop instance */
protected MainLoop mainLoop; protected MainLoop mainLoop;
@ -63,13 +75,28 @@ public class App extends BusNode {
this.eventBus.subscribe(this); this.eventBus.subscribe(this);
// create plugin registry attached to bus // create plugin registry attached to bus
this.eventBus.subscribe(this.plugins); addChildClient(this.plugins);
// initialize and use backend // initialize and use backend
this.backend = backend; this.backend = backend;
this.backend.bind(this); this.backend.bind(this);
this.eventBus.subscribe(backend); addChildClient(backend);
this.backend.initialize();
addDefaultInitTasks();
this.backend.addInitTasks();
}
private void addDefaultInitTasks()
{
addInitTask(new InitTaskCrashHandler());
addInitTask(new InitTaskWorkdir(new File("."), true));
addInitTask(new InitTaskLog());
addInitTask(new InitTaskBackend());
addInitTask(new InitTaskIonizables());
addInitTask(new InitTaskMainLoop());
addInitTask(new InitTaskResourceLoaderAsync());
addInitTask(new InitTaskLogHeader());
} }
@ -99,7 +126,7 @@ public class App extends BusNode {
throw new IllegalStateException("App already started, cannot add initializers."); throw new IllegalStateException("App already started, cannot add initializers.");
} }
initializers.add(initializer); initTasks.addTask(initializer);
} }
@ -111,7 +138,7 @@ public class App extends BusNode {
public void setMainLoop(MainLoop loop) public void setMainLoop(MainLoop loop)
{ {
this.mainLoop = loop; this.mainLoop = loop;
bus().subscribe(loop); // ? addChildClient(loop); // ?
} }
@ -176,8 +203,15 @@ public class App extends BusNode {
Log.f2("Running init tasks..."); Log.f2("Running init tasks...");
// sort initializers by order. // sort initializers based on dependencies
final List<InitTask> orderedInitializers = InitTask.inOrder(initializers); final List<InitTask> orderedInitializers = initTasks.getSequence();
// detailed logging
Log.f3("=== Task overview ===");
for (final InitTask t : orderedInitializers) {
Log.f3("Task " + Str.pad(t.getName(), 20) + " class = " + Str.pad(Str.val(t), 30) + " prio = " + Str.pad("" + t.getPriority(), 12) + " deps = "
+ Arrays.toString(t.getDependencies()));
}
for (final InitTask initTask : orderedInitializers) { for (final InitTask initTask : orderedInitializers) {
Log.f1("Running init task \"" + initTask.getName() + "\"..."); Log.f1("Running init task \"" + initTask.getName() + "\"...");
@ -220,16 +254,37 @@ public class App extends BusNode {
} }
/**
* Shut down the running instance.<br>
* Deinitialize backend modules and terminate the JVM.
*/
public static void requestShutdown()
{
if (instance == null) {
Log.w("App is not running.");
System.exit(0);
}
Log.i("Sending a shutdown request...");
bus().send(new ShutdownRequest());
}
/** /**
* Shut down the running instance.<br> * Shut down the running instance.<br>
* Deinitialize backend modules and terminate the JVM. * Deinitialize backend modules and terminate the JVM.
*/ */
public static void shutdown() public static void shutdown()
{ {
if (instance != null) { if (instance == null) {
Log.i("Dispatching Shutdown event..."); Log.w("App is not running.");
System.exit(0);
}
// It's safer to shutdown in rendering context
// (LWJGL backend has problems otherwise)
bus().send(new ShutdownEvent(new Runnable() { App.bus().send(new MainLoopRequest(new Runnable() {
@Override @Override
public void run() public void run()
@ -238,22 +293,17 @@ public class App extends BusNode {
final EventBus bus = bus(); final EventBus bus = bus();
if (bus != null) { if (bus != null) {
bus.send(new DestroyEvent()); bus.send(new DestroyEvent());
bus.destroy();
} }
} catch (final Throwable e) { } catch (final Throwable e) {
Log.e(e); Log.e(e);
} }
Log.i("Shutdown completed.");
System.exit(0);
} }
})); }, true));
} else {
Log.w("App is not running."); Log.i("Shutdown completed.");
System.exit(0); System.exit(0);
} }
}
/** /**

@ -2,8 +2,10 @@ package mightypork.gamecore.core;
import mightypork.gamecore.audio.AudioModule; import mightypork.gamecore.audio.AudioModule;
import mightypork.gamecore.core.init.InitTaskBackend;
import mightypork.gamecore.graphics.GraphicsModule; import mightypork.gamecore.graphics.GraphicsModule;
import mightypork.gamecore.input.InputModule; import mightypork.gamecore.input.InputModule;
import mightypork.utils.annotations.Stub;
import mightypork.utils.eventbus.clients.BusNode; import mightypork.utils.eventbus.clients.BusNode;
@ -11,7 +13,8 @@ import mightypork.utils.eventbus.clients.BusNode;
* Application backend interface (set of core modules).<br> * Application backend interface (set of core modules).<br>
* The goal of this abstraction is to allow easy migration to different * The goal of this abstraction is to allow easy migration to different
* environment with different libraries etc. It should be as simple as using * environment with different libraries etc. It should be as simple as using
* different backend. * different backend.<br>
* The backend is initialized using {@link InitTaskBackend}.
* *
* @author MightyPork * @author MightyPork
*/ */
@ -35,6 +38,19 @@ public abstract class AppBackend extends BusNode {
} }
/**
* Add backend-specific init tasks or init task configurations.<br>
* This is run after default init tasks have been added, and before the init
* sequence is started.<br>
* The backend is already binded to the app.
*/
@Stub
public void addInitTasks()
{
//
}
/** /**
* Initialize backend modules, add them to event bus. * Initialize backend modules, add them to event bus.
*/ */

@ -18,7 +18,7 @@ import mightypork.utils.math.timing.TimerDelta;
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class DeltaMainLoop extends BusNode implements MainLoop { public class BasicMainLoop extends BusNode implements MainLoop {
/** /**
* Max time spent on main loop tasks per cycle (s) * Max time spent on main loop tasks per cycle (s)
@ -75,6 +75,9 @@ public class DeltaMainLoop extends BusNode implements MainLoop {
} }
} }
// halt if tasks terminated the app.
if (!running) break;
beforeRender(); beforeRender();
if (rootRenderable != null) { if (rootRenderable != null) {

@ -4,8 +4,8 @@ package mightypork.gamecore.core.config;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import mightypork.gamecore.core.events.ShutdownEvent; import mightypork.gamecore.core.events.ShutdownRequest;
import mightypork.gamecore.core.events.ShutdownListener; import mightypork.gamecore.core.events.ShutdownRequestListener;
import mightypork.gamecore.input.Key; import mightypork.gamecore.input.Key;
import mightypork.gamecore.input.KeyStroke; import mightypork.gamecore.input.KeyStroke;
import mightypork.utils.config.propmgr.Property; import mightypork.utils.config.propmgr.Property;
@ -21,7 +21,7 @@ import mightypork.utils.logging.Log;
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class Config implements ShutdownListener { public class Config implements ShutdownRequestListener {
/** Array of configs registered for the app */ /** Array of configs registered for the app */
protected static Map<String, Config> configs = new HashMap<>(); protected static Map<String, Config> configs = new HashMap<>();
@ -270,7 +270,7 @@ public class Config implements ShutdownListener {
@Override @Override
public void onShutdown(ShutdownEvent event) public void onShutdownRequested(ShutdownRequest event)
{ {
save(); // save changes done to the config save(); // save changes done to the config
} }

@ -15,26 +15,13 @@ import mightypork.utils.logging.Log;
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class ShutdownEvent extends BusEvent<ShutdownListener> { public class ShutdownRequest extends BusEvent<ShutdownRequestListener> {
private final Runnable shutdownTask;
/**
* Make a shutdown event
*
* @param doShutdown Task that does the actual shutdown
*/
public ShutdownEvent(Runnable doShutdown)
{
this.shutdownTask = doShutdown;
}
@Override @Override
protected void handleBy(ShutdownListener handler) protected void handleBy(ShutdownRequestListener handler)
{ {
handler.onShutdown(this); handler.onShutdownRequested(this);
} }
@ -44,7 +31,7 @@ public class ShutdownEvent extends BusEvent<ShutdownListener> {
if (!isConsumed()) { if (!isConsumed()) {
Log.i("Shutting down..."); Log.i("Shutting down...");
App.bus().send(new MainLoopRequest(shutdownTask, true)); App.shutdown();
} else { } else {
Log.i("Shutdown aborted."); Log.i("Shutdown aborted.");

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

@ -0,0 +1,168 @@
package mightypork.gamecore.core.init;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import mightypork.utils.Reflect;
import mightypork.utils.logging.Log;
/**
* initialization sequence that takes care of task dependencies and ordering.
*
* @author Ondřej Hruška (MightyPork)
*/
public class InitSequence {
private final Map<String, InitTask> taskMap = new HashMap<>();
/**
* Add a task. If a task with the name already exists, replace it.
*
* @param task task to add
*/
public void addTask(InitTask task)
{
final String name = task.getName();
// detailed logging
// if (taskMap.containsKey(name)) {
// Log.f3("REPL init " + Str.pad("\"" + name + "\"", 20) + " <" + Str.val(task) + ">");
// } else {
// Log.f3("ADD init " + Str.pad("\"" + name + "\"", 20) + " <" + Str.val(task) + ">");
// }
taskMap.put(name, task);
}
/**
* Get task sequence in proper order.
*
* @return initialization sequence
*/
public List<InitTask> getSequence()
{
final List<InitTask> remainingTasks = new ArrayList<>(taskMap.values());
final List<InitTask> orderedTasks = new ArrayList<>();
final Set<String> loadedTaskNames = new HashSet<>();
// resolve task order
InitTask taskToAdd = null;
do {
taskToAdd = null;
for (final InitTask task : remainingTasks) {
String[] deps = task.getDependencies();
if (deps == null) deps = new String[] {};
int missingDeps = deps.length;
for (final String d : deps) {
if (loadedTaskNames.contains(d)) missingDeps--;
}
if (missingDeps == 0) {
if (taskToAdd == null || taskToAdd.getPriority() < task.getPriority()) {
taskToAdd = task;
}
}
}
if (taskToAdd != null) {
orderedTasks.add(taskToAdd);
loadedTaskNames.add(taskToAdd.getName());
remainingTasks.remove(taskToAdd);
}
} while (taskToAdd != null);
checkLeftovers(loadedTaskNames, remainingTasks);
return orderedTasks;
}
public List<InitTask> getSequenceOldImpl()
{
final List<InitTask> remainingTasks = new ArrayList<>(taskMap.values());
final List<InitTask> orderedTasks = new ArrayList<>();
final Set<String> loadedTaskNames = new HashSet<>();
// resolve task order
int addedThisIteration = 0;
do {
addedThisIteration = 0;
for (final Iterator<InitTask> i = remainingTasks.iterator(); i.hasNext();) {
final InitTask task = i.next();
String[] deps = task.getDependencies();
if (deps == null) deps = new String[] {};
int missingDeps = deps.length;
for (final String d : deps) {
if (loadedTaskNames.contains(d)) missingDeps--;
}
if (missingDeps == 0) {
orderedTasks.add(task);
loadedTaskNames.add(task.getName());
i.remove();
addedThisIteration++;
}
}
} while (addedThisIteration > 0);
checkLeftovers(loadedTaskNames, remainingTasks);
return orderedTasks;
}
private void checkLeftovers(Collection<String> loadedTaskNames, Collection<InitTask> remainingTasks)
{
// check if any tasks are left out
if (remainingTasks.size() > 0) {
// build error message for each bad task
int badInitializers = 0;
for (final InitTask task : remainingTasks) {
if (Reflect.hasAnnotation(task.getClass(), OptionalInitTask.class)) {
continue;
}
badInitializers++;
String notSatisfied = "";
for (final String d : task.getDependencies()) {
if (!loadedTaskNames.contains(d)) {
if (!notSatisfied.isEmpty()) {
notSatisfied += ", ";
}
notSatisfied += d;
}
}
Log.w("InitTask \"" + task.getName() + "\" - missing dependencies: " + notSatisfied);
}
if (badInitializers > 0) throw new RuntimeException("Some InitTask dependencies could not be satisfied.");
}
}
}

@ -1,16 +1,8 @@
package mightypork.gamecore.core.init; package mightypork.gamecore.core.init;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import mightypork.gamecore.core.App; import mightypork.gamecore.core.App;
import mightypork.utils.Reflect;
import mightypork.utils.annotations.Stub; import mightypork.utils.annotations.Stub;
import mightypork.utils.logging.Log;
/** /**
@ -22,6 +14,12 @@ import mightypork.utils.logging.Log;
*/ */
public abstract class InitTask { public abstract class InitTask {
protected static final int PRIO_FIRST = Integer.MAX_VALUE;
protected static final int PRIO_EARLY = 9000;
protected static final int PRIO_DEFAULT = 0;
protected static final int PRIO_LATE = -9000;
protected static final int PRIO_LAST = Integer.MIN_VALUE;
/** App instance assigned using <code>bind()</code> */ /** App instance assigned using <code>bind()</code> */
protected App app; protected App app;
@ -102,75 +100,14 @@ public abstract class InitTask {
/** /**
* Order init tasks so that all dependencies are loaded before thye are * Get priority in the init sequence. Tasks with higher priority are loaded
* needed by the tasks. * earlier (but only after their dependencies are loaded).
* *
* @param tasks task list * @return priority, higher = runs earlier
* @return task list ordered
*/ */
public static List<InitTask> inOrder(List<InitTask> tasks) @Stub
public int getPriority()
{ {
final List<InitTask> remaining = new ArrayList<>(tasks); return PRIO_DEFAULT;
final List<InitTask> ordered = new ArrayList<>();
final Set<String> loaded = new HashSet<>();
// resolve task order
int addedThisIteration = 0;
do {
addedThisIteration = 0;
for (final Iterator<InitTask> i = remaining.iterator(); i.hasNext();) {
final InitTask task = i.next();
String[] deps = task.getDependencies();
if (deps == null) deps = new String[] {};
int unmetDepsCount = deps.length;
for (final String d : deps) {
if (loaded.contains(d)) unmetDepsCount--;
}
if (unmetDepsCount == 0) {
ordered.add(task);
loaded.add(task.getName());
i.remove();
addedThisIteration++;
}
}
} while (addedThisIteration > 0);
// check if any tasks are left out
if (remaining.size() > 0) {
// build error message for each bad task
int badInitializers = 0;
for (final InitTask task : remaining) {
if (Reflect.hasAnnotation(task.getClass(), OptionalInitTask.class)) {
continue;
}
badInitializers++;
String notSatisfied = "";
for (final String d : task.getDependencies()) {
if (!loaded.contains(d)) {
if (!notSatisfied.isEmpty()) {
notSatisfied += ", ";
}
notSatisfied += d;
}
}
Log.w("InitTask \"" + task.getName() + "\" - missing dependencies: " + notSatisfied);
}
if (badInitializers > 0) throw new RuntimeException("Some InitTask dependencies could not be satisfied.");
}
return ordered;
} }
} }

@ -0,0 +1,41 @@
package mightypork.gamecore.core.init;
import mightypork.gamecore.core.App;
/**
* Initialize backend. The main point of postponing this is to make sure the
* init is logged properly.
*
* @author Ondřej Hruška (MightyPork)
*/
public class InitTaskBackend extends InitTask {
@Override
public void run()
{
App.instance().getBackend().initialize();
}
@Override
public String getName()
{
return "backend";
}
@Override
public String[] getDependencies()
{
return new String[] { "log" };
}
@Override
public int getPriority()
{
return PRIO_EARLY;
}
}

@ -1,7 +1,7 @@
package mightypork.gamecore.core.config; package mightypork.gamecore.core.init;
import mightypork.gamecore.core.init.InitTask; import mightypork.gamecore.core.config.Config;
import mightypork.utils.annotations.Stub; import mightypork.utils.annotations.Stub;
@ -72,4 +72,11 @@ public abstract class InitTaskConfig extends InitTask {
return new String[] { "workdir" }; return new String[] { "workdir" };
} }
@Override
public int getPriority()
{
return PRIO_FIRST;
}
} }

@ -38,4 +38,11 @@ public class InitTaskCrashHandler extends InitTask implements UncaughtExceptionH
{ {
return "crash_handler"; return "crash_handler";
} }
@Override
public int getPriority()
{
return PRIO_FIRST;
}
} }

@ -5,7 +5,7 @@ import mightypork.gamecore.graphics.GraphicsModule;
/** /**
* Setup main window. * Setup main window / display with rendering context.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */

@ -12,8 +12,8 @@ import mightypork.utils.math.algo.Move;
/** /**
* Register extra ionizables added by the game library (non-native ION types).<br> * Register extra ionizables. More ionizables can be registered ie. in the
* This initializer can be called anywhere in the initialization sequence. * <code>after()</code> hook.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
@ -67,7 +67,14 @@ public class InitTaskIonizables extends InitTask {
@Override @Override
public String getName() public String getName()
{ {
return "ion"; return "ionizables";
}
@Override
public int getPriority()
{
return PRIO_EARLY;
} }
} }

@ -4,21 +4,20 @@ package mightypork.gamecore.core.init;
import java.io.File; import java.io.File;
import java.util.logging.Level; import java.util.logging.Level;
import mightypork.utils.Str;
import mightypork.utils.files.WorkDir; import mightypork.utils.files.WorkDir;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
import mightypork.utils.logging.writers.LogWriter; import mightypork.utils.logging.writers.LogWriter;
import mightypork.utils.string.StringUtil;
/** /**
* Init main logger and console log printing.<br> * Init logging system.
* Must be called after workdir is initialized.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public class InitTaskLog extends InitTask { public class InitTaskLog extends InitTask {
private String logDir = "log"; private String logDir = ".";
private String logName = "runtime"; private String logName = "runtime";
private int archiveCount = 5; private int archiveCount = 5;
@ -47,7 +46,7 @@ public class InitTaskLog extends InitTask {
*/ */
public void setLogName(String logName) public void setLogName(String logName)
{ {
if (!StringUtil.isValidFilenameString(logName)) { if (!Str.isValidFilenameString(logName)) {
throw new IllegalArgumentException("Invalid log name."); throw new IllegalArgumentException("Invalid log name.");
} }
@ -104,4 +103,11 @@ public class InitTaskLog extends InitTask {
{ {
return new String[] { "workdir" }; return new String[] { "workdir" };
} }
@Override
public int getPriority()
{
return PRIO_FIRST;
}
} }

@ -49,4 +49,11 @@ public class InitTaskLogHeader extends InitTask {
{ {
return new String[] { "log", "workdir" }; return new String[] { "log", "workdir" };
} }
@Override
public int getPriority()
{
return PRIO_FIRST;
}
} }

@ -1,18 +1,19 @@
package mightypork.gamecore.core.init; package mightypork.gamecore.core.init;
import mightypork.gamecore.core.BasicMainLoop;
import mightypork.gamecore.core.MainLoop; import mightypork.gamecore.core.MainLoop;
import mightypork.utils.annotations.Stub;
/** /**
* Task to add a resource loader.<br> * Task to add a main loop.
* By default the async resource loader is used
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class InitTaskMainLoop extends InitTask { public class InitTaskMainLoop extends InitTask {
/** The loader. */ /** The loop, can be accessed in the after() method. */
protected MainLoop loop; protected MainLoop loop;
@ -25,11 +26,15 @@ public abstract class InitTaskMainLoop extends InitTask {
/** /**
* Create a loader impl * Create a main loop
* *
* @return loader * @return loader
*/ */
protected abstract MainLoop getLoopImpl(); @Stub
protected MainLoop getLoopImpl()
{
return new BasicMainLoop();
}
@Override @Override
@ -37,4 +42,11 @@ public abstract class InitTaskMainLoop extends InitTask {
{ {
return "main_loop"; return "main_loop";
} }
@Override
public int getPriority()
{
return PRIO_EARLY;
}
} }

@ -21,6 +21,7 @@ public abstract class InitTaskResourceLoader extends InitTask {
{ {
loader = getLoaderImpl(); loader = getLoaderImpl();
if (loader != null) loader.init(); if (loader != null) loader.init();
app.addChildClient(loader);
} }

@ -6,8 +6,7 @@ import mightypork.gamecore.resources.loading.ResourceLoader;
/** /**
* Task to add a resource loader.<br> * Add Async resource loader.
* By default the async resource loader is used
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
@ -21,10 +20,6 @@ public class InitTaskResourceLoaderAsync extends InitTaskResourceLoader {
@Override @Override
protected ResourceLoader getLoaderImpl() protected ResourceLoader getLoaderImpl()
{ {
final AsyncResourceLoader loader = new AsyncResourceLoader(); return new AsyncResourceLoader();
// could now configure the loader
return loader;
} }
} }

@ -5,8 +5,8 @@ import mightypork.gamecore.resources.loading.ResourceLoader;
/** /**
* Task to add a resource loader.<br> * Add no resource loader. That will cause resources to be loaded on-demand. May
* By default the async resource loader is used * cause lag if the resources are too large.
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */

@ -29,6 +29,10 @@ public abstract class InitTaskResources extends InitTask implements ResourceInit
@Override @Override
public String[] getDependencies() public String[] getDependencies()
{ {
// main loop handles resource load rewuests that run in rendering context
// must be before, otherwise the requests would get lost.
return new String[] { "resource_loader", "main_loop" }; return new String[] { "resource_loader", "main_loop" };
} }
} }

@ -1,42 +0,0 @@
package mightypork.gamecore.core.init;
import mightypork.gamecore.graphics.Renderable;
/**
* Task to init renderable screens (part of the main loop).<br>
* Resources must already be ready.
*
* @author Ondřej Hruška (MightyPork)
*/
public abstract class InitTaskScreens extends InitTask {
@Override
public void run()
{
app.setMainRenderable(getMainRenderableImpl());
}
/**
* Create a loader impl
*
* @return loader
*/
protected abstract Renderable getMainRenderableImpl();
@Override
public String getName()
{
return "renderables";
}
@Override
public String[] getDependencies()
{
return new String[] { "resources", "main_loop" };
}
}

@ -0,0 +1,51 @@
package mightypork.gamecore.core.init;
import mightypork.gamecore.graphics.Renderable;
import mightypork.gamecore.resources.Res;
/**
* Task to init main renderable (UI).<br>
* Resources are already registered in {@link Res}.
*
* @author Ondřej Hruška (MightyPork)
*/
public abstract class InitTaskUI extends InitTask {
@Override
public void run()
{
app.setMainRenderable(createMainRenderable());
}
/**
* Create a loader impl
*
* @return loader
*/
protected abstract Renderable createMainRenderable();
@Override
public String getName()
{
return "ui";
}
@Override
public String[] getDependencies()
{
// main loop queues layout change events, would lose them otherwise
return new String[] { "resources", "main_loop" };
}
@Override
public int getPriority()
{
return PRIO_LAST;
}
}

@ -133,4 +133,11 @@ public class InitTaskWorkdir extends InitTask {
{ {
return "workdir"; return "workdir";
} }
@Override
public int getPriority()
{
return PRIO_EARLY;
}
} }

@ -5,7 +5,7 @@ import mightypork.gamecore.core.App;
import mightypork.gamecore.graphics.Renderable; import mightypork.gamecore.graphics.Renderable;
import mightypork.gamecore.gui.events.LayoutChangeEvent; import mightypork.gamecore.gui.events.LayoutChangeEvent;
import mightypork.gamecore.gui.events.LayoutChangeListener; import mightypork.gamecore.gui.events.LayoutChangeListener;
import mightypork.utils.Support; import mightypork.utils.Str;
import mightypork.utils.annotations.Stub; import mightypork.utils.annotations.Stub;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
import mightypork.utils.math.color.Color; import mightypork.utils.math.color.Color;
@ -88,7 +88,7 @@ public abstract class BaseComponent extends AbstractRectCache implements Compone
try { try {
poll(); poll();
} catch (final NullPointerException e) { } catch (final NullPointerException e) {
Log.e("Component is missing a bounding rect, at: " + Support.str(getClass())); Log.e("Component is missing a bounding rect, at: " + Str.val(getClass()));
} }
} }

@ -1,7 +1,7 @@
package mightypork.gamecore.input; package mightypork.gamecore.input;
import mightypork.utils.string.StringUtil; import mightypork.utils.Str;
/** /**
@ -84,8 +84,8 @@ public class KeyStroke {
if (dataString1.contains("+")) { if (dataString1.contains("+")) {
final String keyStr = StringUtil.fromLastChar(dataString1, '+'); final String keyStr = Str.fromLast(dataString1, '+');
final String modStr = StringUtil.toLastChar(dataString1, '+'); final String modStr = Str.toLast(dataString1, '+');
setTo(Keys.stringToKey(keyStr), Keys.stringToMod(modStr)); setTo(Keys.stringToKey(keyStr), Keys.stringToMod(modStr));

@ -3,11 +3,11 @@ package mightypork.gamecore.resources;
import java.io.IOException; import java.io.IOException;
import mightypork.utils.Str;
import mightypork.utils.annotations.Alias; import mightypork.utils.annotations.Alias;
import mightypork.utils.interfaces.Destroyable; import mightypork.utils.interfaces.Destroyable;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
import mightypork.utils.math.timing.Profiler; import mightypork.utils.math.timing.Profiler;
import mightypork.utils.string.StringUtil;
/** /**
@ -107,7 +107,7 @@ public abstract class BaseDeferredResource implements DeferredResource, Destroya
@Override @Override
public String toString() public String toString()
{ {
return StringUtil.fromLastChar(resource, '/'); return Str.fromLast(resource, '/');
} }

@ -9,7 +9,7 @@ import mightypork.gamecore.core.App;
import mightypork.gamecore.core.events.MainLoopRequest; import mightypork.gamecore.core.events.MainLoopRequest;
import mightypork.gamecore.resources.DeferredResource; import mightypork.gamecore.resources.DeferredResource;
import mightypork.utils.Reflect; import mightypork.utils.Reflect;
import mightypork.utils.Support; import mightypork.utils.Str;
import mightypork.utils.interfaces.Destroyable; import mightypork.utils.interfaces.Destroyable;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
@ -40,7 +40,6 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr
@Override @Override
public synchronized void init() public synchronized void init()
{ {
App.bus().subscribe(this);
setDaemon(true); setDaemon(true);
super.start(); super.start();
} }
@ -70,7 +69,7 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr
if (!mainLoopQueuing) { if (!mainLoopQueuing) {
// just let it be // just let it be
} else { } else {
Log.f3("(loader) Delegating to main thread: " + Support.str(resource)); Log.f3("(loader) Delegating to main thread: " + Str.val(resource));
App.bus().send(new MainLoopRequest(new Runnable() { App.bus().send(new MainLoopRequest(new Runnable() {
@ -102,7 +101,7 @@ public class AsyncResourceLoader extends Thread implements ResourceLoader, Destr
if (!def.isLoaded()) { if (!def.isLoaded()) {
Log.f3("(loader) Scheduling... " + Support.str(def)); Log.f3("(loader) Scheduling... " + Str.val(def));
exs.submit(new Runnable() { exs.submit(new Runnable() {

Loading…
Cancel
Save